diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
index 621292af809b246636c5832544e47c4257068b49..ce6a668a1d7d4a1758fe6505bcba8cf22fb26b69 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
@@ -658,8 +658,8 @@ final class REngine implements Engine, Engine.Timings {
 
     @TruffleBoundary
     private static boolean checkResult(Object result) {
-        if (FastROptions.CheckResultCompleteness.getBooleanValue() && result instanceof RAbstractVector && ((RAbstractVector) result).isComplete()) {
-            assert ((RAbstractVector) result).checkCompleteness() : "vector: " + result + " is not complete, but isComplete flag is true";
+        if (FastROptions.CheckResultCompleteness.getBooleanValue() && result instanceof RAbstractVector) {
+            assert RAbstractVector.verify((RAbstractVector) result);
         }
         return true;
     }
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 d5efff6efc4373ec4a7162d411aa4f4d9615b327..cab4934525c42ab1be917f7f54f8c255d53f9b3d 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
@@ -90,16 +90,12 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.RUnboundValue;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-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.RAbstractListBaseVector;
 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.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
 import com.oracle.truffle.r.runtime.ffi.DLL;
@@ -860,138 +856,37 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
     @Override
     @TruffleBoundary
     public void Rf_copyMatrix(Object t, Object s, int byRow) {
-        int tRows = RRuntime.nrows(t);
-        int tCols = RRuntime.ncols(t);
-        final Object sav = RRuntime.asAbstractVector(s);
-        ContainerItemCopier c;
-        if (sav instanceof RAbstractContainer) {
-            int sLen = ((RAbstractContainer) sav).getLength();
-            if (sav instanceof RAbstractIntVector) {
-                c = new ContainerItemCopier() {
-                    private final RAbstractIntVector sv = (RAbstractIntVector) sav;
-                    private final RAbstractIntVector tv = (RAbstractIntVector) t;
-                    private final Object tvStore = tv.getInternalStore();
-
-                    @Override
-                    public void copy(int sIdx, int tIdx) {
-                        tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx));
-                    }
-                };
-            } else if (sav instanceof RAbstractDoubleVector) {
-                c = new ContainerItemCopier() {
-
-                    private final RAbstractDoubleVector sv = (RAbstractDoubleVector) sav;
-                    private final RAbstractDoubleVector tv = (RAbstractDoubleVector) t;
-                    private final Object tvStore = tv.getInternalStore();
-
-                    @Override
-                    public void copy(int sIdx, int tIdx) {
-                        tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx));
-                    }
-                };
-            } else if (sav instanceof RAbstractLogicalVector) {
-                c = new ContainerItemCopier() {
-                    private final RAbstractLogicalVector sv = (RAbstractLogicalVector) sav;
-                    private final RAbstractLogicalVector tv = (RAbstractLogicalVector) t;
-                    private final Object tvStore = tv.getInternalStore();
-
-                    @Override
-                    public void copy(int sIdx, int tIdx) {
-                        tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx));
-                    }
-                };
-            } else if (sav instanceof RAbstractComplexVector) {
-                c = new ContainerItemCopier() {
-                    private final RAbstractComplexVector sv = (RAbstractComplexVector) sav;
-                    private final RAbstractComplexVector tv = (RAbstractComplexVector) t;
-                    private final Object tvStore = tv.getInternalStore();
-
-                    @Override
-                    public void copy(int sIdx, int tIdx) {
-                        tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx));
-                    }
-                };
-            } else if (sav instanceof RAbstractStringVector) {
-                c = new ContainerItemCopier() {
-                    private final RAbstractStringVector sv = (RAbstractStringVector) sav;
-                    private final RAbstractStringVector tv = (RAbstractStringVector) t;
-                    private final Object tvStore = tv.getInternalStore();
-
-                    @Override
-                    public void copy(int sIdx, int tIdx) {
-                        tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx));
-                    }
-                };
-            } else if (sav instanceof RAbstractRawVector) {
-                c = new ContainerItemCopier() {
-                    private final RAbstractRawVector sv = (RAbstractRawVector) sav;
-                    private final RAbstractRawVector tv = (RAbstractRawVector) t;
-                    private final Object tvStore = tv.getInternalStore();
-
-                    @Override
-                    public void copy(int sIdx, int tIdx) {
-                        tv.setRawDataAt(tvStore, tIdx, sv.getRawDataAt(sIdx));
-                    }
-                };
-            } else if (sav instanceof RAbstractListBaseVector) {
-                c = new ContainerItemCopier() {
-                    private final RAbstractListBaseVector sv = (RAbstractListBaseVector) sav;
-                    private final RAbstractListBaseVector tv = (RAbstractListBaseVector) t;
-                    private final Object tvStore = tv.getInternalStore();
-
-                    @Override
-                    public void copy(int sIdx, int tIdx) {
-                        tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx));
-                    }
-                };
-            } else {
-                throw unimplemented();
-            }
-            if (byRow != 0) {
-                int sIdx = 0;
-                for (int i = 0; i < tRows; i++) {
-                    int tIdx = i;
-                    for (int j = 0; j < tCols; j++) {
-                        c.copy(sIdx, tIdx);
-                        sIdx++;
-                        if (sIdx >= sLen) {
-                            sIdx -= sLen;
+        RAbstractVector target = guaranteeInstanceOf(t, RAbstractVector.class);
+        RAbstractVector source = guaranteeInstanceOf(RRuntime.asAbstractVector(s), RAbstractVector.class);
+
+        VectorAccess targetAccess = target.slowPathAccess();
+        VectorAccess sourceAccess = source.slowPathAccess();
+
+        try (SequentialIterator sourceIter = sourceAccess.access(source)) {
+            if (byRow != 0) { // copy by row
+                int tRows = RRuntime.nrows(target);
+                int tCols = RRuntime.ncols(target);
+                try (RandomIterator targetIter = targetAccess.randomAccess(target)) {
+                    for (int i = 0; i < tRows; i++) {
+                        int tIdx = i;
+                        for (int j = 0; j < tCols; j++) {
+                            sourceAccess.nextWithWrap(sourceIter);
+                            targetAccess.setFromSameType(targetIter, tIdx, sourceAccess, sourceIter);
+                            tIdx += tRows;
                         }
-                        tIdx += tRows;
                     }
                 }
-            } else { // Copy by column
-                int tLen = ((RAbstractContainer) t).getLength();
-                if (sLen >= tLen) {
-                    for (int i = 0; i < tLen; i++) {
-                        c.copy(i, i);
-                    }
-                } else { // Recycle needed
-                    int sIdx = 0;
-                    for (int i = 0; i < tLen; i++) {
-                        c.copy(sIdx, i);
-                        sIdx++;
-                        if (sIdx >= sLen) {
-                            sIdx -= sLen;
-                        }
+            } else { // copy by column
+                try (SequentialIterator targetIter = targetAccess.access(target)) {
+                    while (targetAccess.next(targetIter)) {
+                        sourceAccess.nextWithWrap(sourceIter);
+                        targetAccess.setFromSameType(targetIter, sourceAccess, sourceIter);
                     }
                 }
             }
-        } else { // source is non-RAbstractContainer
-            throw unimplemented();
         }
     }
 
-    /**
-     * Helper interface for {@link #Rf_copyMatrix(java.lang.Object, java.lang.Object, int)} that
-     * copies from source index in an (internally held) source container into target index in a
-     * target container.
-     */
-    interface ContainerItemCopier {
-
-        void copy(int sIdx, int tIdx);
-    }
-
     @Override
     @TruffleBoundary
     public Object R_tryEval(Object expr, Object env, int silent) {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java
index 9e8c18a8c8da56b9fea99f90ae32870a4102a380..61fa874e2c41ff9556ba9ef288fc7eb4fd5b9d25 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java
@@ -49,7 +49,6 @@ import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypes;
-import com.oracle.truffle.r.runtime.data.nodes.GetDataCopy;
 
 /**
  * Nodes that implement {@code CAR}, {@code CDR}, etc. N.B. GNU R does not error check the
@@ -170,7 +169,6 @@ public final class ListAccessNodes {
 
         @Specialization
         protected Object cdr(RList list,
-                        @Cached("create()") GetDataCopy.String getDataCopyNode,
                         @Cached("create()") GetNamesAttributeNode getNamesNode,
                         @Cached("create()") SetNamesAttributeNode setNamesNode) {
             if (list.getLength() == 1) {
@@ -179,7 +177,7 @@ public final class ListAccessNodes {
             RStringVector names = getNamesNode.getNames(list);
             RList copy = RDataFactory.createList(list.getDataCopy());
             if (names != null) {
-                String[] namesDataCopy = getDataCopyNode.execute(names);
+                String[] namesDataCopy = names.getDataCopy();
                 setNamesNode.setNames(copy, RDataFactory.createStringVector(namesDataCopy, true));
             }
             return copy;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
index 1c6562db6396bdce9c7600220ce3fcbee4ee6afd..c42616fccf5020f685de15630ff0640d6549dfb4 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
@@ -43,7 +43,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNames
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctionsFactory.SetNamesAttributeNodeGen;
 import com.oracle.truffle.r.nodes.builtin.EnvironmentNodes.GetFunctionEnvironmentNode;
 import com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder;
-import com.oracle.truffle.r.nodes.builtin.casts.fluent.HeadPhaseBuilder;
 import com.oracle.truffle.r.nodes.objects.NewObject;
 import com.oracle.truffle.r.nodes.objects.NewObjectNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastNode;
@@ -57,8 +56,6 @@ import com.oracle.truffle.r.runtime.data.RRawVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypes;
 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.nodes.GetDataAt;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 
@@ -266,26 +263,17 @@ public final class MiscNodes {
         @Specialization
         protected RRawVector octSize(Object size,
                         @Cached("create()") SizeToOctalRawNode sizeToOctal,
-                        @Cached("createCast()") CastNode castToDoubleNode,
-                        @Cached("create()") GetDataAt.Double getDataNode) {
-
-            Object val = castToDoubleNode.doCast(size);
-            if (val instanceof RAbstractDoubleVector) {
-                RAbstractDoubleVector vec = (RAbstractDoubleVector) val;
-                return sizeToOctal.execute(getDataNode.get(vec, vec.getInternalStore(), 0));
-            }
-            return sizeToOctal.execute(val);
+                        @Cached("createCast()") CastNode castToDoubleNode) {
+            return sizeToOctal.execute(castToDoubleNode.doCast(size));
 
         }
 
         protected CastNode createCast() {
-            HeadPhaseBuilder<Double> findFirst = CastNodeBuilder.newCastBuilder().mustNotBeMissing().allowNull().asDoubleVector().findFirst();
-            return findFirst.buildCastNode();
+            return CastNodeBuilder.newCastBuilder().mustNotBeMissing().allowNull().asDoubleVector().findFirst().buildCastNode();
         }
 
         public static OctSizeNode create() {
             return OctSizeNodeGen.create();
         }
     }
-
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
index 6c7e397ee82032a85b9aacb020447351289f4de8..2693615f508a0d1ff9bdfd3af494c667e2385d05 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
@@ -36,6 +36,7 @@ import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RObject;
 import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.RScalarList;
+import com.oracle.truffle.r.runtime.data.RScalarVector;
 import com.oracle.truffle.r.runtime.data.RSequence;
 
 public abstract class FFIWrapNode extends Node {
@@ -92,7 +93,11 @@ public abstract class FFIWrapNode extends Node {
         return wrap(RDataFactory.createComplexVectorFromScalar(value));
     }
 
-    @Specialization
+    protected static boolean isRScalarVector(RObject value) {
+        return value instanceof RScalarVector;
+    }
+
+    @Specialization(guards = "!isRScalarVector(value)")
     protected static Object wrap(RObject value) {
         return value;
     }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java
index 87ac3095c6689f05bc93ba6516e6732797683790..1bdce4fb65e441e2951aeb3a516f2f6457ea8a23 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java
@@ -38,6 +38,7 @@ 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.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 final class DoSetViewPort {
@@ -74,7 +75,7 @@ final class DoSetViewPort {
         pushedViewPort.setDataAt(ViewPort.PVP_DEVWIDTHCM, scalar(Unit.inchesToCm(currentDevice.getWidth())));
         pushedViewPort.setDataAt(ViewPort.PVP_DEVHEIGHTCM, scalar(Unit.inchesToCm(currentDevice.getHeight())));
 
-        assert pushedViewPort.verify();
+        assert RAbstractVector.verify(pushedViewPort);
         return pushedViewPort;
     }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java
index c1cfe4461c2f329c6d60fda68c3fe648c2db9791..77f8e4293eab0192390b1f6552f99e863b47a582 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java
@@ -18,6 +18,7 @@ import com.oracle.truffle.r.library.fastrGrid.device.GridDevice;
 import com.oracle.truffle.r.library.fastrGrid.grDevices.FileDevUtils;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 public final class GridState {
@@ -104,7 +105,7 @@ public final class GridState {
 
     public void initGPar(GridDevice currentDevice) {
         devState.gpar = GPar.createNew(currentDevice);
-        assert devState.gpar.verify();
+        assert RAbstractVector.verify(devState.gpar);
     }
 
     /**
@@ -143,7 +144,7 @@ public final class GridState {
     }
 
     public void setViewPort(RList viewPort) {
-        assert viewPort.verify();
+        assert RAbstractVector.verify(viewPort);
         devState.viewPort = viewPort;
     }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCairo.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCairo.java
index e8051d5c63c0263639650ca2a42699774dc20f65..371fe577b934023e585821fb963aaff0067f9172 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCairo.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCairo.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.library.fastrGrid.grDevices;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.library.fastrGrid.GridContext;
 import com.oracle.truffle.r.library.fastrGrid.device.SVGDevice;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
@@ -36,6 +37,7 @@ public class DevCairo extends RExternalBuiltinNode {
     }
 
     @Override
+    @TruffleBoundary
     protected Object call(RArgsValuesAndNames args) {
         if (args.getLength() < 4) {
             throw error(Message.ARGUMENTS_REQUIRED_COUNT, args.getLength(), "devCairo", 4);
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 cffbaad71f9c59b41e3cae935605ccf4bf441156..1d88093b56227120073c643e15d546084b029479 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
@@ -12,9 +12,9 @@
  */
 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.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.runtime.nmath.MathConstants.DBL_MIN;
 
 import com.oracle.truffle.api.dsl.Cached;
@@ -25,8 +25,6 @@ import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
-import com.oracle.truffle.r.runtime.data.nodes.ReadAccessor;
-import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -34,9 +32,12 @@ 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.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
+
     private static final NACheck naCheck = NACheck.create();
 
     @Child private GetFixedAttributeNode getNamesAttrNode = GetFixedAttributeNode.createNames();
@@ -49,9 +50,10 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         casts.arg(3).asDoubleVector().findFirst();
     }
 
-    @Specialization(guards = "method == cachedMethod")
-    protected RDoubleVector cdist(RAbstractDoubleVector x, @SuppressWarnings("unused") int method, RList list, double p, @SuppressWarnings("unused") @Cached("method") int cachedMethod,
-                    @Cached("create()") VectorReadAccess.Double xAccess,
+    @Specialization(guards = {"method == cachedMethod", "xAccess.supports(x)"})
+    protected RDoubleVector cdist(RAbstractDoubleVector x, @SuppressWarnings("unused") int method, RList list, double p,
+                    @Cached("method") @SuppressWarnings("unused") int cachedMethod,
+                    @Cached("x.access()") VectorAccess xAccess,
                     @Cached("getMethod(method)") Method methodObj,
                     @Cached("create()") SetAttributeNode setAttrNode,
                     @Cached("create()") SetClassAttributeNode setClassAttrNode,
@@ -60,8 +62,10 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         int nc = getDimNode.ncols(x);
         int n = nr * (nr - 1) / 2; /* avoid int overflow for N ~ 50,000 */
         double[] ans = new double[n];
-        RDoubleVector xm = x.materialize();
-        rdistance(new ReadAccessor.Double(x, xAccess), nr, nc, ans, false, methodObj, p);
+
+        try (RandomIterator xIter = xAccess.randomAccess(x)) {
+            rdistance(xAccess, xIter, nr, nc, ans, false, methodObj, p);
+        }
         RDoubleVector result = RDataFactory.createDoubleVector(ans, naCheck.neverSeenNA());
         DynamicObject resultAttrs = result.initAttributes();
 
@@ -81,6 +85,14 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         return result;
     }
 
+    @Specialization(replaces = "cdist")
+    protected RDoubleVector cdistGeneric(RAbstractDoubleVector x, int method, RList list, double p,
+                    @Cached("create()") SetAttributeNode setAttrNode,
+                    @Cached("create()") SetClassAttributeNode setClassAttrNode,
+                    @Cached("create()") GetDimAttributeNode getDimNode) {
+        return cdist(x, method, list, p, method, x.slowPathAccess(), getMethod(method), setAttrNode, setClassAttrNode, getDimNode);
+    }
+
     private static boolean bothNonNAN(double a, double b) {
         return !RRuntime.isNAorNaN(a) && !RRuntime.isNAorNaN(b);
     }
@@ -96,7 +108,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         return Method.values()[method - 1];
     }
 
-    private void rdistance(ReadAccessor.Double xAccess, int nr, int nc, double[] d, boolean diag, Method method, double p) {
+    private void rdistance(VectorAccess xAccess, RandomIterator xIter, 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) {
@@ -109,7 +121,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(xAccess, nr, nc, i, j, p);
+                double r = method.dist(xAccess, xIter, nr, nc, i, j, p);
                 naCheck.check(r);
                 d[ij++] = r;
             }
@@ -119,7 +131,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
     public enum Method {
         EUCLIDEAN {
             @Override
-            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -130,8 +142,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 count = 0;
                 dist = 0;
                 for (j = 0; j < nc; j++) {
-                    if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
-                        dev = (xAccess.getDataAt(i1) - xAccess.getDataAt(i2));
+                    if (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) {
+                        dev = (xAccess.getDouble(xIter, i1) - xAccess.getDouble(xIter, i2));
                         if (!RRuntime.isNAorNaN(dev)) {
                             dist += dev * dev;
                             count++;
@@ -152,7 +164,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         MAXIMUM {
             @Override
-            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -163,8 +175,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 count = 0;
                 dist = -Double.MAX_VALUE;
                 for (j = 0; j < nc; j++) {
-                    if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
-                        dev = Math.abs(xAccess.getDataAt(i1) - xAccess.getDataAt(i2));
+                    if (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) {
+                        dev = Math.abs(xAccess.getDouble(xIter, i1) - xAccess.getDouble(xIter, i2));
                         if (!RRuntime.isNAorNaN(dev)) {
                             if (dev > dist) {
                                 dist = dev;
@@ -184,7 +196,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         MANHATTAN {
             @Override
-            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -195,8 +207,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 count = 0;
                 dist = 0;
                 for (j = 0; j < nc; j++) {
-                    if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
-                        dev = Math.abs(xAccess.getDataAt(i1) - xAccess.getDataAt(i2));
+                    if (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) {
+                        dev = Math.abs(xAccess.getDouble(xIter, i1) - xAccess.getDouble(xIter, i2));
                         if (!RRuntime.isNAorNaN(dev)) {
                             dist += dev;
                             count++;
@@ -217,7 +229,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         CANBERRA {
             @Override
-            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -230,9 +242,9 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 count = 0;
                 dist = 0;
                 for (j = 0; j < nc; j++) {
-                    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 (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) {
+                        sum = Math.abs(xAccess.getDouble(xIter, i1) + xAccess.getDouble(xIter, i2));
+                        diff = Math.abs(xAccess.getDouble(xIter, i1) - xAccess.getDouble(xIter, i2));
                         if (sum > DBL_MIN || diff > DBL_MIN) {
                             dev = diff / sum;
                             if (!RRuntime.isNAorNaN(dev) ||
@@ -258,7 +270,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         BINARY {
             @Override
-            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 int total;
@@ -271,13 +283,13 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 dist = 0;
 
                 for (j = 0; j < nc; j++) {
-                    if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
-                        if (!bothFinite(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
+                    if (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) {
+                        if (!bothFinite(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) {
                             RError.warning(RError.SHOW_CALLER2, RError.Message.GENERIC, "treating non-finite values as NA");
                         } else {
-                            if (xAccess.getDataAt(i1) != 0. || xAccess.getDataAt(i2) != 0.) {
+                            if (xAccess.getDouble(xIter, i1) != 0. || xAccess.getDouble(xIter, i2) != 0.) {
                                 count++;
-                                if (!(xAccess.getDataAt(i1) != 0. && xAccess.getDataAt(i2) != 0.)) {
+                                if (!(xAccess.getDouble(xIter, i1) != 0. && xAccess.getDouble(xIter, i2) != 0.)) {
                                     dist++;
                                 }
                             }
@@ -300,7 +312,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         MINKOWSKI {
             @Override
-            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -311,8 +323,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 count = 0;
                 dist = 0;
                 for (j = 0; j < nc; j++) {
-                    if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
-                        dev = (xAccess.getDataAt(i1) - xAccess.getDataAt(i2));
+                    if (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) {
+                        dev = (xAccess.getDouble(xIter, i1) - xAccess.getDouble(xIter, i2));
                         if (!RRuntime.isNAorNaN(dev)) {
                             dist += Math.pow(Math.abs(dev), p);
                             count++;
@@ -331,6 +343,6 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
             }
         };
 
-        public abstract double dist(ReadAccessor.Double xAccess, int nr, int nc, int i1, int i2, double p);
+        public abstract double dist(VectorAccess xAccess, RandomIterator xIter, 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 0a07a8b78c67ee7965a500d2cb61c1561e9feffc..8c0052139f253fd4233b127aeefe7f0cedaeb1df 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
@@ -20,7 +20,8 @@ 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.VectorReadAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 
 // translated from library/stats/src/hclust_utils.c
 
@@ -32,10 +33,10 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
         casts.arg(1).mustNotBeMissing().mapIf(nullValue(), emptyIntegerVector()).asIntegerVector();
     }
 
-    @Specialization
+    @Specialization(guards = {"mergeAccess.supports(merge)", "whichAccess.supports(which)"})
     protected RIntVector cutree(RAbstractIntVector merge, RAbstractIntVector which,
-                    @Cached("create()") VectorReadAccess.Int mergeAccess,
-                    @Cached("create()") VectorReadAccess.Int whichAccess,
+                    @Cached("merge.access()") VectorAccess mergeAccess,
+                    @Cached("which.access()") VectorAccess whichAccess,
                     @Cached("create()") GetDimAttributeNode getDimNode) {
         int whichLen = which.getLength();
 
@@ -59,92 +60,96 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
         int[] z = new int[n];
 
         int[] iAns = new int[n * whichLen];
-        Object mergeStore = mergeAccess.getDataStore(merge);
-        Object whichStore = whichAccess.getDataStore(which);
+        try (RandomIterator mergeIter = mergeAccess.randomAccess(merge); RandomIterator whichIter = whichAccess.randomAccess(which)) {
 
-        // for (k = 1; k <= n; k++) {
-        for (k = 0; k < n; k++) {
-            sing[k] = true; /* is k-th obs. still alone in cluster ? */
-            mNr[k] = 0; /* containing last merge-step number of k-th obs. */
-        }
+            // for (k = 1; k <= n; k++) {
+            for (k = 0; k < n; k++) {
+                sing[k] = true; /* is k-th obs. still alone in cluster ? */
+                mNr[k] = 0; /* containing last merge-step number of k-th obs. */
+            }
 
-        for (k = 1; k <= n - 1; k++) {
-            /* k-th merge, from n-k+1 to n-k atoms: (m1,m2) = merge[ k , ] */
-            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;
-                sing[adj(-m1)] = sing[adj(-m2)] = false;
-            } else if (m1 < 0 || m2 < 0) { /* the other >= 0 */
-                if (m1 < 0) {
-                    j = -m1;
-                    m1 = m2;
-                } else {
-                    j = -m2;
-                }
-                /* merging atom j & cluster m1 */
-                for (l = 1; l <= n; l++) {
-                    if (mNr[adj(l)] == m1) {
-                        mNr[adj(l)] = k;
+            for (k = 1; k <= n - 1; k++) {
+                /* k-th merge, from n-k+1 to n-k atoms: (m1,m2) = merge[ k , ] */
+                m1 = mergeAccess.getInt(mergeIter, k - 1);
+                m2 = mergeAccess.getInt(mergeIter, n - 1 + k - 1);
+
+                if (m1 < 0 && m2 < 0) { /* merging atoms [-m1] and [-m2] */
+                    mNr[adj(-m1)] = mNr[adj(-m2)] = k;
+                    sing[adj(-m1)] = sing[adj(-m2)] = false;
+                } else if (m1 < 0 || m2 < 0) { /* the other >= 0 */
+                    if (m1 < 0) {
+                        j = -m1;
+                        m1 = m2;
+                    } else {
+                        j = -m2;
                     }
-                }
-                mNr[adj(j)] = k;
-                sing[adj(j)] = false;
-            } else { /* both m1, m2 >= 0 */
-                for (l = 1; l <= n; l++) {
-                    if (mNr[adj(l)] == m1 || mNr[adj(l)] == m2) {
-                        mNr[adj(l)] = k;
+                    /* merging atom j & cluster m1 */
+                    for (l = 1; l <= n; l++) {
+                        if (mNr[adj(l)] == m1) {
+                            mNr[adj(l)] = k;
+                        }
+                    }
+                    mNr[adj(j)] = k;
+                    sing[adj(j)] = false;
+                } else { /* both m1, m2 >= 0 */
+                    for (l = 1; l <= n; l++) {
+                        if (mNr[adj(l)] == m1 || mNr[adj(l)] == m2) {
+                            mNr[adj(l)] = k;
+                        }
                     }
                 }
-            }
 
-            /*
-             * does this k-th merge belong to a desired group size which[j] ? if yes, find j (maybe
-             * multiple ones):
-             */
-            foundJ = false;
-            for (j = 0; j < whichLen; j++) {
-                if (whichAccess.getDataAt(which, whichStore, j) == n - k) {
-                    if (!foundJ) { /* first match (and usually only one) */
-                        foundJ = true;
-                        // for (l = 1; l <= n; l++)
-                        for (l = 0; l < n; l++) {
-                            z[l] = 0;
-                        }
-                        nclust = 0;
-                        mm = j * n; /* may want to copy this column of ans[] */
-                        for (l = 1, m1 = mm; l <= n; l++, m1++) {
-                            if (sing[adj(l)]) {
-                                iAns[m1] = ++nclust;
-                            } else {
-                                if (z[adj(mNr[adj(l)])] == 0) {
-                                    z[adj(mNr[adj(l)])] = ++nclust;
+                /*
+                 * does this k-th merge belong to a desired group size which[j] ? if yes, find j
+                 * (maybe multiple ones):
+                 */
+                foundJ = false;
+                for (j = 0; j < whichLen; j++) {
+                    if (whichAccess.getInt(whichIter, j) == n - k) {
+                        if (!foundJ) { /* first match (and usually only one) */
+                            foundJ = true;
+                            // for (l = 1; l <= n; l++)
+                            for (l = 0; l < n; l++) {
+                                z[l] = 0;
+                            }
+                            nclust = 0;
+                            mm = j * n; /* may want to copy this column of ans[] */
+                            for (l = 1, m1 = mm; l <= n; l++, m1++) {
+                                if (sing[adj(l)]) {
+                                    iAns[m1] = ++nclust;
+                                } else {
+                                    if (z[adj(mNr[adj(l)])] == 0) {
+                                        z[adj(mNr[adj(l)])] = ++nclust;
+                                    }
+                                    iAns[m1] = z[adj(mNr[adj(l)])];
                                 }
-                                iAns[m1] = z[adj(mNr[adj(l)])];
+                            }
+                        } else { /* found_j: another which[j] == n-k : copy column */
+                            for (l = 1, m1 = j * n, m2 = mm; l <= n; l++, m1++, m2++) {
+                                iAns[m1] = iAns[m2];
                             }
                         }
-                    } else { /* found_j: another which[j] == n-k : copy column */
-                        for (l = 1, m1 = j * n, m2 = mm; l <= n; l++, m1++, m2++) {
-                            iAns[m1] = iAns[m2];
-                        }
+                    } /* if ( match ) */
+                } /* for(j .. which[j] ) */
+            } /* for(k ..) {merge} */
+
+            /* Dealing with trivial case which[] = n : */
+            for (j = 0; j < whichLen; j++) {
+                if (whichAccess.getInt(whichIter, j) == n) {
+                    for (l = 1, m1 = j * n; l <= n; l++, m1++) {
+                        iAns[m1] = l;
                     }
-                } /* if ( match ) */
-            } /* for(j .. which[j] ) */
-        } /* for(k ..) {merge} */
-
-        /* Dealing with trivial case which[] = n : */
-        for (j = 0; j < whichLen; j++) {
-            if (whichAccess.getDataAt(which, whichStore, j) == n) {
-                for (l = 1, m1 = j * n; l <= n; l++, m1++) {
-                    iAns[m1] = l;
                 }
             }
         }
 
-        RIntVector result = RDataFactory.createIntVector(iAns, RDataFactory.COMPLETE_VECTOR, new int[]{n, whichLen});
-        return result;
+        return RDataFactory.createIntVector(iAns, RDataFactory.COMPLETE_VECTOR, new int[]{n, whichLen});
+    }
 
+    @Specialization(replaces = "cutree")
+    protected RIntVector cutreeGeneric(RAbstractIntVector merge, RAbstractIntVector which,
+                    @Cached("create()") GetDimAttributeNode getDimNode) {
+        return cutree(merge, which, merge.slowPathAccess(), which.slowPathAccess(), getDimNode);
     }
 
     private static int adj(int i) {
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 62883376e19d6cccdc6e3ab014c7765086f15e4e..a817389e28340b1a2cca0112feefc0260960de6f 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,56 +10,63 @@
  */
 package com.oracle.truffle.r.library.stats;
 
-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;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 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.SetDataAt;
-import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorReuse;
 
 public abstract class DoubleCentre extends RExternalBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(DoubleCentre.class);
-        casts.arg(0).mustBe(missingValue().not()).mustBe(nullValue().not(), RError.Message.MACRO_CAN_BE_APPLIED_TO, "REAL()", "numeric", "NULL").asDoubleVector();
+        casts.arg(0).mustNotBeNull(RError.Message.MACRO_CAN_BE_APPLIED_TO, "REAL()", "numeric", "NULL").mustNotBeMissing().asDoubleVector();
     }
 
-    @Specialization
-    protected RDoubleVector doubleCentre(RAbstractDoubleVector aVecAbs,
-                    @Cached("create()") VectorReadAccess.Double aAccess,
-                    @Cached("create()") SetDataAt.Double aSetter,
+    @Specialization(guards = {"aAccess.supports(a)", "reuse.supports(a)"})
+    protected RAbstractDoubleVector doubleCentre(RAbstractDoubleVector a,
+                    @Cached("a.access()") VectorAccess aAccess,
+                    @Cached("createNonShared(a)") VectorReuse reuse,
                     @Cached("create()") GetDimAttributeNode getDimNode) {
-        RDoubleVector aVec = aVecAbs.materialize();
-        int n = getDimNode.nrows(aVec);
-        Object aStore = aAccess.getDataStore(aVec);
-        for (int i = 0; i < n; i++) {
-            double sum = 0;
-            for (int j = 0; j < n; j++) {
-                sum += aAccess.getDataAt(aVec, aStore, i + j * n);
-            }
-            sum /= n;
-            for (int j = 0; j < n; j++) {
-                double val = aAccess.getDataAt(aVec, aStore, i + j * n);
-                aSetter.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 += aAccess.getDataAt(aVec, aStore, i + j * n);
-            }
-            sum /= n;
-            for (int i = 0; i < n; i++) {
-                double val = aAccess.getDataAt(aVec, aStore, i + j * n);
-                aSetter.setDataAt(aVec, aStore, i + j * n, val - sum);
+        int n = getDimNode.nrows(a);
+
+        try (RandomIterator aIter = aAccess.randomAccess(a)) {
+            RAbstractDoubleVector result = reuse.getResult(a);
+            VectorAccess resultAccess = reuse.access(result);
+            try (RandomIterator resultIter = resultAccess.randomAccess(result)) {
+                for (int i = 0; i < n; i++) {
+                    double sum = 0;
+                    for (int j = 0; j < n; j++) {
+                        sum += aAccess.getDouble(aIter, i + j * n);
+                    }
+                    sum /= n;
+                    for (int j = 0; j < n; j++) {
+                        resultAccess.setDouble(resultIter, i + j * n, aAccess.getDouble(aIter, i + j * n) - sum);
+                    }
+                }
+                for (int j = 0; j < n; j++) {
+                    double sum = 0;
+                    for (int i = 0; i < n; i++) {
+                        sum += resultAccess.getDouble(aIter, i + j * n);
+                    }
+                    sum /= n;
+                    for (int i = 0; i < n; i++) {
+                        resultAccess.setDouble(resultIter, i + j * n, resultAccess.getDouble(aIter, i + j * n) - sum);
+                    }
+                }
             }
+            return result;
         }
-        return aVec;
+    }
+
+    @Specialization(replaces = "doubleCentre")
+    protected RAbstractDoubleVector doubleCentreGeneric(RAbstractDoubleVector a,
+                    @Cached("createNonSharedGeneric()") VectorReuse reuse,
+                    @Cached("create()") GetDimAttributeNode getDimNode) {
+        return doubleCentre(a, a.slowPathAccess(), reuse, getDimNode);
     }
 }
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 56fa2752f569d2701e8f2239d05775022b239357..0fcd70396e68153561ab018f2ac36a6f3b5083e1 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
@@ -27,18 +27,15 @@ import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
-import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode;
 import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.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.ReadAccessor;
-import com.oracle.truffle.r.runtime.data.nodes.SetDataAt;
-import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 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;
@@ -49,8 +46,15 @@ import com.oracle.truffle.r.runtime.rng.RRNG;
  * Implements the vectorization of {@link RMultinom}.
  */
 public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 {
+
     private final Rbinom rbinom = new Rbinom();
 
+    private final ValueProfile randGeneratorClassProfile = ValueProfile.createClassProfile();
+    private final ConditionProfile hasAttributesProfile = ConditionProfile.createBinaryProfile();
+    @Child private UpdateShareableChildValueNode updateSharedAttributeNode = UpdateShareableChildValueNode.create();
+    @Child private GetFixedAttributeNode getNamesNode = GetFixedAttributeNode.createNames();
+    @Child private SetFixedAttributeNode setDimNamesNode = SetFixedAttributeNode.createDimNames();
+
     public static RMultinomNode create() {
         return RMultinomNodeGen.create();
     }
@@ -68,63 +72,69 @@ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 {
     }
 
     @Specialization
-    protected RIntVector doMultinom(int n, int size, RAbstractDoubleVector probsVec,
-                    @Cached("create()") VectorReadAccess.Double probsAccess,
-                    @Cached("create()") SetDataAt.Double probsSetter,
-                    @Cached("create()") ReuseNonSharedNode reuseNonSharedNode,
-                    @Cached("createClassProfile()") ValueProfile randGeneratorClassProfile,
-                    @Cached("createBinaryProfile()") ConditionProfile hasAttributesProfile,
-                    @Cached("create()") UpdateShareableChildValueNode updateSharedAttributeNode,
-                    @Cached("createNames()") GetFixedAttributeNode getNamesNode,
-                    @Cached("createDimNames()") SetFixedAttributeNode setDimNamesNode) {
-        RDoubleVector nonSharedProbs = ((RAbstractDoubleVector) reuseNonSharedNode.execute(probsVec)).materialize();
-        ReadAccessor.Double probs = new ReadAccessor.Double(nonSharedProbs, probsAccess);
-        fixupProb(nonSharedProbs, probs, probsSetter);
-
-        RRNG.getRNGState();
-        RandomNumberProvider rand = new RandomNumberProvider(randGeneratorClassProfile.profile(RRNG.currentGenerator()), RRNG.currentNormKind());
-        int k = nonSharedProbs.getLength();
-        int[] result = new int[k * n];
-        boolean isComplete = true;
-        for (int i = 0, ik = 0; i < n; i++, ik += k) {
-            isComplete &= RMultinom.rmultinom(size, probs, k, result, ik, rand, rbinom);
-        }
-        RRNG.putRNGState();
+    protected RIntVector doMultinom(int n, int size, RAbstractDoubleVector probs,
+                    @Cached("probs.access()") VectorAccess probsAccess) {
+        try (SequentialIterator probsIter = probsAccess.access(probs)) {
+            double sum = 0.0;
+            while (probsAccess.next(probsIter)) {
+                double prob = probsAccess.getDouble(probsIter);
+                if (!Double.isFinite(prob)) {
+                    throw error(NA_IN_PROB_VECTOR);
+                }
+                if (prob < 0.0) {
+                    throw error(NEGATIVE_PROBABILITY);
+                }
+                sum += prob;
+            }
+            if (sum == 0) {
+                throw error(NO_POSITIVE_PROBABILITIES);
+            }
 
-        // take names from probVec (if any) as row names in the result
-        RIntVector resultVec = RDataFactory.createIntVector(result, isComplete, new int[]{k, n});
-        if (hasAttributesProfile.profile(probsVec.getAttributes() != null)) {
-            Object probsNames = getNamesNode.execute(probsVec.getAttributes());
-            updateSharedAttributeNode.execute(probsVec, probsNames);
-            Object[] dimnamesData = new Object[]{probsNames, RNull.instance};
-            setDimNamesNode.execute(resultVec.getAttributes(), RDataFactory.createList(dimnamesData));
-        }
-        return resultVec;
-    }
+            RRNG.getRNGState();
+            RandomNumberProvider rand = new RandomNumberProvider(randGeneratorClassProfile.profile(RRNG.currentGenerator()), RRNG.currentNormKind());
+            int[] result = new int[probsAccess.getLength(probsIter) * n];
+            if (size > 0) {
+                for (int i = 0, ik = 0; i < n; i++, ik += probsAccess.getLength(probsIter)) {
+                    double currentSum = sum;
+                    int currentSize = size;
+                    /* Generate the first K-1 obs. via binomials */
+                    probsAccess.reset(probsIter);
+                    for (int k = 0; probsAccess.next(probsIter) && k < probsAccess.getLength(probsIter) - 1; k++) {
+                        /* (p_tot, n) are for "remaining binomial" */
+                        /* LDOUBLE */double probK = probsAccess.getDouble(probsIter);
+                        if (probK != 0.) {
+                            double pp = probK / currentSum;
+                            int value = (pp < 1.) ? (int) rbinom.execute(currentSize, pp, rand) : currentSize;
+                            /*
+                             * >= 1; > 1 happens because of rounding
+                             */
+                            result[ik + k] = value;
+                            currentSize -= value;
+                        } else {
+                            result[ik + k] = 0;
+                        }
+                        if (n <= 0) {
+                            /* we have all */
+                            break;
+                        }
+                        /* i.e. = sum(prob[(k+1):K]) */
+                        currentSum -= probK;
+                    }
 
-    private void fixupProb(RDoubleVector p, ReadAccessor.Double pAccess, SetDataAt.Double pSetter) {
-        double sum = 0.0;
-        int npos = 0;
-        int pLength = p.getLength();
-        for (int i = 0; i < pLength; i++) {
-            double prob = pAccess.getDataAt(i);
-            if (!Double.isFinite(prob)) {
-                throw error(NA_IN_PROB_VECTOR);
+                    result[ik + probsAccess.getLength(probsIter) - 1] = currentSize;
+                }
             }
-            if (prob < 0.0) {
-                throw error(NEGATIVE_PROBABILITY);
-            }
-            if (prob > 0.0) {
-                npos++;
-                sum += prob;
+            RRNG.putRNGState();
+
+            // take names from probVec (if any) as row names in the result
+            RIntVector resultVec = RDataFactory.createIntVector(result, true, new int[]{probsAccess.getLength(probsIter), n});
+            if (hasAttributesProfile.profile(probs.getAttributes() != null)) {
+                Object probsNames = getNamesNode.execute(probs.getAttributes());
+                updateSharedAttributeNode.execute(probs, probsNames);
+                Object[] dimnamesData = new Object[]{probsNames, RNull.instance};
+                setDimNamesNode.execute(resultVec.getAttributes(), RDataFactory.createList(dimnamesData));
             }
-        }
-        if (npos == 0) {
-            throw error(NO_POSITIVE_PROBABILITIES);
-        }
-        for (int i = 0; i < pLength; i++) {
-            double prob = pAccess.getDataAt(i);
-            pSetter.setDataAt(p, pAccess.getStore(), i, prob / sum);
+            return resultVec;
         }
     }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java
index f8b8ad866ba0f07df2f543055be4ad89d74ca373..e40046305732232a588eeecfb36dea7c2b6402ee 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java
@@ -16,12 +16,13 @@ package com.oracle.truffle.r.library.stats;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
 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.runtime.RError.Message.INVALID_UNNAMED_ARGUMENTS;
 import static com.oracle.truffle.r.runtime.RError.SHOW_CALLER;
+import static com.oracle.truffle.r.runtime.RError.Message.INVALID_UNNAMED_ARGUMENTS;
 
 import java.util.Arrays;
+import java.util.function.Function;
+import java.util.function.Supplier;
 
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
@@ -31,19 +32,22 @@ import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.ConvertToLen
 import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction1NodeGen;
 import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction2NodeGen;
 import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction3NodeGen;
+import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen;
+import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunctionExecutorBaseNodeGen;
+import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunctionIntExecutorNodeGen;
 import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
 import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDouble;
 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.RAbstractVector;
-import com.oracle.truffle.r.runtime.data.nodes.VectorIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandFunction1_Double;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandFunction2_Double;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandFunction3_Double;
@@ -57,7 +61,7 @@ import com.oracle.truffle.r.runtime.rng.RRNG;
  * {@link RandFunction3_Double}, {@link RandFunction2_Double} or {@link RandFunction1_Double}.
  */
 public final class RandFunctionsNodes {
-    @CompilationFinal private static final RDouble DUMMY_VECTOR = RDouble.valueOf(1);
+    private static final RDouble DUMMY_VECTOR = RDouble.valueOf(1);
 
     private RandFunctionsNodes() {
         // static class
@@ -101,53 +105,65 @@ public final class RandFunctionsNodes {
      * {@link RandFunction3_Double}.
      */
     protected abstract static class RandFunctionExecutorBase extends RBaseNode {
-        static final class RandGenerationNodeData {
-            final BranchProfile nanResult = BranchProfile.create();
-            final BranchProfile nan = BranchProfile.create();
-            final VectorLengthProfile resultVectorLengthProfile = VectorLengthProfile.create();
-            final LoopConditionProfile loopConditionProfile = LoopConditionProfile.createCountingProfile();
-
-            public static RandGenerationNodeData create() {
-                return new RandGenerationNodeData();
-            }
+
+        protected final Function<Supplier<? extends RandFunction3_Double>, RandFunctionIterator> iteratorFactory;
+        protected final Supplier<? extends RandFunction3_Double> functionFactory;
+
+        protected RandFunctionExecutorBase(Function<Supplier<? extends RandFunction3_Double>, RandFunctionIterator> iteratorFactory, Supplier<? extends RandFunction3_Double> functionFactory) {
+            this.iteratorFactory = iteratorFactory;
+            this.functionFactory = functionFactory;
         }
 
+        public abstract RAbstractVector execute(RAbstractVector length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand);
+
+        @Child private ConvertToLength convertToLength = ConvertToLengthNodeGen.create();
+        private final VectorLengthProfile resultVectorLengthProfile = VectorLengthProfile.create();
+
         @Override
-        protected RBaseNode getErrorContext() {
+        protected final RBaseNode getErrorContext() {
             return RError.SHOW_CALLER;
         }
 
-        public abstract Object execute(RAbstractVector length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand);
-
-        @Child private ConvertToLength convertToLength = ConvertToLengthNodeGen.create();
+        protected final RandFunctionIterator createIterator() {
+            return iteratorFactory.apply(functionFactory);
+        }
 
         @Specialization(guards = {"randCached.isSame(rand)"})
-        protected final Object evaluateWithCached(RAbstractVector lengthVec, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c,
+        protected final RAbstractVector evaluateWithCached(RAbstractVector lengthVec, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c,
                         @SuppressWarnings("unused") RandomNumberProvider rand,
                         @Cached("rand") RandomNumberProvider randCached,
-                        @Cached("create()") RandGenerationNodeData nodeData) {
-            return evaluateWrapper(lengthVec, a, b, c, randCached, nodeData);
+                        @Cached("createIterator()") RandFunctionIterator iterator) {
+            int length = resultVectorLengthProfile.profile(convertToLength.execute(lengthVec));
+            RBaseNode.reportWork(this, length);
+            return iterator.execute(length, a, b, c, randCached);
         }
 
         @Specialization(replaces = "evaluateWithCached")
-        protected final Object evaluateFallback(RAbstractVector lengthVec, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand,
-                        @Cached("create()") RandGenerationNodeData nodeData) {
-            return evaluateWrapper(lengthVec, a, b, c, rand, nodeData);
+        protected final RAbstractVector evaluateFallback(RAbstractVector lengthVec, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand,
+                        @Cached("createIterator()") RandFunctionIterator iterator) {
+            int length = resultVectorLengthProfile.profile(convertToLength.execute(lengthVec));
+            RBaseNode.reportWork(this, length);
+            return iterator.execute(length, a, b, c, rand);
         }
+    }
 
-        private Object evaluateWrapper(RAbstractVector lengthVec, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand,
-                        RandGenerationNodeData nodeData) {
-            int length = nodeData.resultVectorLengthProfile.profile(convertToLength.execute(lengthVec));
-            RBaseNode.reportWork(this, length);
-            return evaluate(length, a, b, c, nodeData, rand);
+    protected abstract static class RandFunctionIterator extends RBaseNode {
+
+        protected final Supplier<? extends RandFunction3_Double> functionFactory;
+        protected final BranchProfile nanResult = BranchProfile.create();
+        protected final BranchProfile nan = BranchProfile.create();
+        protected final LoopConditionProfile loopConditionProfile = LoopConditionProfile.createCountingProfile();
+
+        protected RandFunctionIterator(Supplier<? extends RandFunction3_Double> functionFactory) {
+            this.functionFactory = functionFactory;
         }
 
-        @SuppressWarnings("unused")
-        Object evaluate(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandGenerationNodeData nodeData, RandomNumberProvider randProvider) {
-            // DSL generates code for this class too, with abstract method it would not compile
-            throw RInternalError.shouldNotReachHere("must be overridden");
+        protected final RandFunction3_Double createFunction() {
+            return functionFactory.get();
         }
 
+        public abstract RAbstractVector execute(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand);
+
         static void putRNGState() {
             // Note: we call putRNGState only if we actually changed the state, i.e. called random
             // number generation. We do not need to getRNGState() because the parent wrapper node
@@ -160,105 +176,107 @@ public final class RandFunctionsNodes {
         }
     }
 
-    protected abstract static class RandFunctionIntExecutorNode extends RandFunctionExecutorBase {
-        @Child private RandFunction3_Double function;
-        @Child private VectorIterator.Double aIterator = VectorIterator.Double.createWrapAround();
-        @Child private VectorIterator.Double bIterator = VectorIterator.Double.createWrapAround();
-        @Child private VectorIterator.Double cIterator = VectorIterator.Double.createWrapAround();
+    protected abstract static class RandFunctionIntExecutorNode extends RandFunctionIterator {
 
-        protected RandFunctionIntExecutorNode(RandFunction3_Double function) {
-            this.function = function;
+        protected RandFunctionIntExecutorNode(Supplier<? extends RandFunction3_Double> functionFactory) {
+            super(functionFactory);
         }
 
-        @Override
-        protected RAbstractIntVector evaluate(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandGenerationNodeData nodeData,
-                        RandomNumberProvider randProvider) {
-            int aLength = a.getLength();
-            int bLength = b.getLength();
-            int cLength = c.getLength();
-            if (aLength == 0 || bLength == 0 || cLength == 0) {
-                nodeData.nanResult.enter();
-                showNAWarning();
-                int[] nansResult = new int[length];
-                Arrays.fill(nansResult, RRuntime.INT_NA);
-                return RDataFactory.createIntVector(nansResult, false);
-            }
+        @Specialization(guards = {"aAccess.supports(a)", "bAccess.supports(b)", "cAccess.supports(c)"})
+        protected RAbstractIntVector cached(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider randProvider,
+                        @Cached("createFunction()") RandFunction3_Double function,
+                        @Cached("a.access()") VectorAccess aAccess,
+                        @Cached("b.access()") VectorAccess bAccess,
+                        @Cached("c.access()") VectorAccess cAccess) {
+            try (SequentialIterator aIter = aAccess.access(a); SequentialIterator bIter = bAccess.access(b); SequentialIterator cIter = cAccess.access(c)) {
+                if (aAccess.getLength(aIter) == 0 || bAccess.getLength(bIter) == 0 || cAccess.getLength(cIter) == 0) {
+                    nanResult.enter();
+                    showNAWarning();
+                    int[] nansResult = new int[length];
+                    Arrays.fill(nansResult, RRuntime.INT_NA);
+                    return RDataFactory.createIntVector(nansResult, false);
+                }
 
-            Object aIt = aIterator.init(a);
-            Object bIt = bIterator.init(b);
-            Object cIt = cIterator.init(c);
-            boolean nans = false;
-            int[] result = new int[length];
-            nodeData.loopConditionProfile.profileCounted(length);
-            for (int i = 0; nodeData.loopConditionProfile.inject(i < length); i++) {
-                double aValue = aIterator.next(a, aIt);
-                double bValue = bIterator.next(b, bIt);
-                double cValue = cIterator.next(c, cIt);
-                double value = function.execute(aValue, bValue, cValue, randProvider);
-                if (Double.isNaN(value) || value <= Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
-                    nodeData.nan.enter();
-                    nans = true;
-                    result[i] = RRuntime.INT_NA;
-                } else {
-                    result[i] = (int) value;
+                boolean nans = false;
+                int[] result = new int[length];
+                loopConditionProfile.profileCounted(length);
+                for (int i = 0; loopConditionProfile.inject(i < length); i++) {
+                    aAccess.nextWithWrap(aIter);
+                    bAccess.nextWithWrap(bIter);
+                    cAccess.nextWithWrap(cIter);
+                    double value = function.execute(aAccess.getDouble(aIter), bAccess.getDouble(bIter), cAccess.getDouble(cIter), randProvider);
+                    if (Double.isNaN(value) || value <= Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
+                        nan.enter();
+                        nans = true;
+                        result[i] = RRuntime.INT_NA;
+                    } else {
+                        result[i] = (int) value;
+                    }
                 }
+                putRNGState();
+                if (nans) {
+                    showNAWarning();
+                }
+                return RDataFactory.createIntVector(result, !nans);
             }
-            putRNGState();
-            if (nans) {
-                showNAWarning();
-            }
-            return RDataFactory.createIntVector(result, !nans);
+        }
+
+        @Specialization(replaces = "cached")
+        protected RAbstractIntVector generic(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider randProvider,
+                        @Cached("createFunction()") RandFunction3_Double function) {
+            return cached(length, a, b, c, randProvider, function, a.slowPathAccess(), b.slowPathAccess(), c.slowPathAccess());
         }
     }
 
-    protected abstract static class RandFunctionDoubleExecutorNode extends RandFunctionExecutorBase {
-        @Child private RandFunction3_Double function;
-        @Child private VectorIterator.Double aIterator = VectorIterator.Double.createWrapAround();
-        @Child private VectorIterator.Double bIterator = VectorIterator.Double.createWrapAround();
-        @Child private VectorIterator.Double cIterator = VectorIterator.Double.createWrapAround();
+    protected abstract static class RandFunctionDoubleExecutorNode extends RandFunctionIterator {
 
-        protected RandFunctionDoubleExecutorNode(RandFunction3_Double function) {
-            this.function = function;
+        protected RandFunctionDoubleExecutorNode(Supplier<? extends RandFunction3_Double> functionFactory) {
+            super(functionFactory);
         }
 
-        @Override
-        protected RAbstractDoubleVector evaluate(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandGenerationNodeData nodeData,
-                        RandomNumberProvider randProvider) {
-            int aLength = a.getLength();
-            int bLength = b.getLength();
-            int cLength = c.getLength();
-            if (aLength == 0 || bLength == 0 || cLength == 0) {
-                nodeData.nanResult.enter();
-                showNAWarning();
-                double[] nansResult = new double[length];
-                Arrays.fill(nansResult, RRuntime.DOUBLE_NA);
-                return RDataFactory.createDoubleVector(nansResult, false);
-            }
+        @Specialization(guards = {"aAccess.supports(a)", "bAccess.supports(b)", "cAccess.supports(c)"})
+        protected RAbstractDoubleVector cached(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider randProvider,
+                        @Cached("createFunction()") RandFunction3_Double function,
+                        @Cached("a.access()") VectorAccess aAccess,
+                        @Cached("b.access()") VectorAccess bAccess,
+                        @Cached("c.access()") VectorAccess cAccess) {
+            try (SequentialIterator aIter = aAccess.access(a); SequentialIterator bIter = bAccess.access(b); SequentialIterator cIter = cAccess.access(c)) {
+                if (aAccess.getLength(aIter) == 0 || bAccess.getLength(bIter) == 0 || cAccess.getLength(cIter) == 0) {
+                    nanResult.enter();
+                    showNAWarning();
+                    double[] nansResult = new double[length];
+                    Arrays.fill(nansResult, RRuntime.DOUBLE_NA);
+                    return RDataFactory.createDoubleVector(nansResult, false);
+                }
 
-            Object aIt = aIterator.init(a);
-            Object bIt = bIterator.init(b);
-            Object cIt = cIterator.init(c);
-            boolean nans = false;
-            double[] result;
-            result = new double[length];
-            nodeData.loopConditionProfile.profileCounted(length);
-            for (int i = 0; nodeData.loopConditionProfile.inject(i < length); i++) {
-                double aValue = aIterator.next(a, aIt);
-                double bValue = bIterator.next(b, bIt);
-                double cValue = cIterator.next(c, cIt);
-                double value = function.execute(aValue, bValue, cValue, randProvider);
-                if (Double.isNaN(value) || RRuntime.isNA(value)) {
-                    nodeData.nan.enter();
-                    nans = true;
+                boolean nans = false;
+                double[] result = new double[length];
+                loopConditionProfile.profileCounted(length);
+                for (int i = 0; loopConditionProfile.inject(i < length); i++) {
+                    aAccess.nextWithWrap(aIter);
+                    bAccess.nextWithWrap(bIter);
+                    cAccess.nextWithWrap(cIter);
+                    double value = function.execute(aAccess.getDouble(aIter), bAccess.getDouble(bIter), cAccess.getDouble(cIter), randProvider);
+                    if (Double.isNaN(value) || RRuntime.isNA(value)) {
+                        nan.enter();
+                        nans = true;
+                    }
+                    result[i] = value;
                 }
-                result[i] = value;
-            }
-            putRNGState();
-            if (nans) {
-                showNAWarning();
+                putRNGState();
+                if (nans) {
+                    showNAWarning();
+                }
+                return RDataFactory.createDoubleVector(result, !nans);
             }
-            return RDataFactory.createDoubleVector(result, !nans);
         }
+
+        @Specialization(replaces = "cached")
+        protected RAbstractDoubleVector generic(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider randProvider,
+                        @Cached("createFunction()") RandFunction3_Double function) {
+            return cached(length, a, b, c, randProvider, function, a.slowPathAccess(), b.slowPathAccess(), c.slowPathAccess());
+        }
+
     }
 
     public abstract static class RandFunction3Node extends RExternalBuiltinNode.Arg4 {
@@ -268,13 +286,13 @@ public final class RandFunctionsNodes {
             this.inner = inner;
         }
 
-        public static RandFunction3Node createInt(RandFunction3_Double function) {
-            return RandFunction3NodeGen.create(RandFunctionsNodesFactory.RandFunctionIntExecutorNodeGen.create(function));
+        public static RandFunction3Node createInt(Supplier<RandFunction3_Double> function) {
+            return RandFunction3NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionIntExecutorNodeGen::create, function));
         }
 
         // Note: for completeness of the API
-        public static RandFunction3Node createDouble(RandFunction3_Double function) {
-            return RandFunction3NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function));
+        public static RandFunction3Node createDouble(Supplier<RandFunction3_Double> function) {
+            return RandFunction3NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionDoubleExecutorNodeGen::create, function));
         }
 
         static {
@@ -286,7 +304,7 @@ public final class RandFunctionsNodes {
         }
 
         @Specialization
-        protected Object evaluate(RAbstractVector length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c) {
+        protected RAbstractVector evaluate(RAbstractVector length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c) {
             RRNG.getRNGState();
             return inner.execute(length, a, b, c, RandomNumberProvider.fromCurrentRNG());
         }
@@ -299,12 +317,12 @@ public final class RandFunctionsNodes {
             this.inner = inner;
         }
 
-        public static RandFunction2Node createInt(RandFunction2_Double function) {
-            return RandFunction2NodeGen.create(RandFunctionsNodesFactory.RandFunctionIntExecutorNodeGen.create(function));
+        public static RandFunction2Node createInt(Supplier<RandFunction2_Double> function) {
+            return RandFunction2NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionIntExecutorNodeGen::create, function));
         }
 
-        public static RandFunction2Node createDouble(RandFunction2_Double function) {
-            return RandFunction2NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function));
+        public static RandFunction2Node createDouble(Supplier<RandFunction2_Double> function) {
+            return RandFunction2NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionDoubleExecutorNodeGen::create, function));
         }
 
         static {
@@ -328,12 +346,12 @@ public final class RandFunctionsNodes {
             this.inner = inner;
         }
 
-        public static RandFunction1Node createInt(RandFunction1_Double function) {
-            return RandFunction1NodeGen.create(RandFunctionsNodesFactory.RandFunctionIntExecutorNodeGen.create(function));
+        public static RandFunction1Node createInt(Supplier<RandFunction1_Double> function) {
+            return RandFunction1NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionIntExecutorNodeGen::create, function));
         }
 
-        public static RandFunction1Node createDouble(RandFunction1_Double function) {
-            return RandFunction1NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function));
+        public static RandFunction1Node createDouble(Supplier<RandFunction1_Double> function) {
+            return RandFunction1NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionDoubleExecutorNodeGen::create, function));
         }
 
         static {
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 ebba5274acc538099ba8d71b3b7b69dfcbbbc888..51564fd6f8bdcf5eb948c22d3c11ea76d7cc89bf 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java
@@ -46,8 +46,9 @@ 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.ReadAccessor;
-import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 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;
@@ -374,10 +375,11 @@ public final class StatsFunctionsNodes {
             casts.arg(6).asDoubleVector().findFirst();
         }
 
-        @Specialization
+        @Specialization(guards = {"xAccess.supports(x)", "yAccess.supports(y)", "vAccess.supports(v)"})
         protected RDoubleVector approx(RAbstractDoubleVector x, RAbstractDoubleVector y, RAbstractDoubleVector v, int method, double yl, double yr, double f,
-                        @Cached("create()") VectorReadAccess.Double xAccess,
-                        @Cached("create()") VectorReadAccess.Double yAccess) {
+                        @Cached("x.access()") VectorAccess xAccess,
+                        @Cached("y.access()") VectorAccess yAccess,
+                        @Cached("v.access()") VectorAccess vAccess) {
             int nx = x.getLength();
             int nout = v.getLength();
             double[] yout = new double[nout];
@@ -390,14 +392,21 @@ public final class StatsFunctionsNodes {
             apprMeth.yhigh = yr;
             naCheck.enable(true);
 
-            ReadAccessor.Double xAccessor = new ReadAccessor.Double(x, xAccess);
-            ReadAccessor.Double yAccessor = new ReadAccessor.Double(y, yAccess);
-            for (int i = 0; i < nout; i++) {
-                double xouti = v.getDataAt(i);
-                yout[i] = RRuntime.isNAorNaN(xouti) ? xouti : approx1(xouti, xAccessor, yAccessor, nx, apprMeth);
-                naCheck.check(yout[i]);
+            try (RandomIterator xIter = xAccess.randomAccess(x); RandomIterator yIter = yAccess.randomAccess(y); SequentialIterator vIter = vAccess.access(v)) {
+                int i = 0;
+                while (vAccess.next(vIter)) {
+                    double xouti = vAccess.getDouble(vIter);
+                    yout[i] = RRuntime.isNAorNaN(xouti) ? xouti : approx1(xouti, xAccess, xIter, yAccess, yIter, nx, apprMeth);
+                    naCheck.check(yout[i]);
+                    i++;
+                }
+                return RDataFactory.createDoubleVector(yout, naCheck.neverSeenNA());
             }
-            return RDataFactory.createDoubleVector(yout, naCheck.neverSeenNA());
+        }
+
+        @Specialization(replaces = "approx")
+        protected RDoubleVector approxGeneric(RAbstractDoubleVector x, RAbstractDoubleVector y, RAbstractDoubleVector v, int method, double yl, double yr, double f) {
+            return approx(x, y, v, method, yl, yr, f, x.slowPathAccess(), y.slowPathAccess(), v.slowPathAccess());
         }
 
         private static class ApprMeth {
@@ -408,32 +417,29 @@ public final class StatsFunctionsNodes {
             int kind;
         }
 
-        private static double approx1(double v, ReadAccessor.Double x, ReadAccessor.Double y, int n,
+        private static double approx1(double v, VectorAccess xAccess, RandomIterator xIter, VectorAccess yAccess, RandomIterator yIter, int n,
                         ApprMeth apprMeth) {
             /* Approximate y(v), given (x,y)[i], i = 0,..,n-1 */
-            int i;
-            int j;
-            int ij;
 
             if (n == 0) {
                 return RRuntime.DOUBLE_NA;
             }
 
-            i = 0;
-            j = n - 1;
-
+            int i = 0;
+            int j = n - 1;
             /* handle out-of-domain points */
-            if (v < x.getDataAt(i)) {
+            if (v < xAccess.getDouble(xIter, i)) {
                 return apprMeth.ylow;
             }
-            if (v > x.getDataAt(j)) {
+            if (v > xAccess.getDouble(xIter, j)) {
                 return apprMeth.yhigh;
             }
 
             /* find the correct interval by bisection */
             while (i < j - 1) { /* x.getDataAt(i) <= v <= x.getDataAt(j) */
-                ij = (i + j) / 2; /* i+1 <= ij <= j-1 */
-                if (v < x.getDataAt(ij)) {
+                int ij = (i + j) / 2;
+                /* i+1 <= ij <= j-1 */
+                if (v < xAccess.getDouble(xIter, ij)) {
                     j = ij;
                 } else {
                     i = ij;
@@ -444,18 +450,22 @@ public final class StatsFunctionsNodes {
 
             /* interpolation */
 
-            if (v == x.getDataAt(j)) {
-                return y.getDataAt(j);
+            double xJ = xAccess.getDouble(xIter, j);
+            double yJ = yAccess.getDouble(yIter, j);
+            if (v == xJ) {
+                return yJ;
             }
-            if (v == x.getDataAt(i)) {
-                return y.getDataAt(i);
+            double xI = xAccess.getDouble(xIter, i);
+            double yI = yAccess.getDouble(yIter, i);
+            if (v == xI) {
+                return yI;
             }
             /* impossible: if(x.getDataAt(j) == x.getDataAt(i)) return y.getDataAt(i); */
 
             if (apprMeth.kind == 1) { /* linear */
-                return y.getDataAt(i) + (y.getDataAt(j) - y.getDataAt(i)) * ((v - x.getDataAt(i)) / (x.getDataAt(j) - x.getDataAt(i)));
+                return yI + (yJ - yI) * ((v - xI) / (xJ - xI));
             } else { /* 2 : constant */
-                return (apprMeth.f1 != 0.0 ? y.getDataAt(i) * apprMeth.f1 : 0.0) + (apprMeth.f2 != 0.0 ? y.getDataAt(j) * apprMeth.f2 : 0.0);
+                return (apprMeth.f1 != 0.0 ? yI * apprMeth.f1 : 0.0) + (apprMeth.f2 != 0.0 ? yJ * apprMeth.f2 : 0.0);
             }
         }/* approx1() */
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java
index 515d57eec9c176430c07e87124e1c292f75e5d93..8ee5500175998956147d01d844bca7b1ed517ce0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java
@@ -27,6 +27,7 @@ import static com.oracle.truffle.r.runtime.RDispatch.INTERNAL_GENERIC;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE_SUMMARY;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ValueProfile;
@@ -39,19 +40,23 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.ops.na.NACheck;
+import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
 @RBuiltin(name = "anyNA", kind = PRIMITIVE, parameterNames = {"x", "recursive"}, dispatch = INTERNAL_GENERIC, behavior = PURE_SUMMARY)
 public abstract class AnyNA extends RBuiltinNode.Arg2 {
 
-    private final NACheck naCheck = NACheck.create();
+    // true if this is the first recursive level
+    protected final boolean isRecursive;
+
+    protected AnyNA() {
+        this.isRecursive = false;
+    }
+
+    protected AnyNA(boolean isRecursive) {
+        this.isRecursive = isRecursive;
+    }
 
     public abstract byte execute(Object value, boolean recursive);
 
@@ -65,117 +70,132 @@ public abstract class AnyNA extends RBuiltinNode.Arg2 {
         return new Object[]{RMissing.instance, RRuntime.LOGICAL_FALSE};
     }
 
-    private static byte doScalar(boolean isNA) {
-        return RRuntime.asLogical(isNA);
-    }
-
-    @FunctionalInterface
-    private interface VectorIndexPredicate<T extends RAbstractVector> {
-        boolean apply(T vector, int index);
-    }
-
-    private <T extends RAbstractVector> byte doVector(T vector, VectorIndexPredicate<T> predicate) {
-        naCheck.enable(vector);
-        for (int i = 0; i < vector.getLength(); i++) {
-            if (predicate.apply(vector, i)) {
-                return RRuntime.LOGICAL_TRUE;
-            }
-        }
-        return RRuntime.LOGICAL_FALSE;
-    }
-
     @Specialization
     protected byte isNA(byte value, @SuppressWarnings("unused") boolean recursive) {
-        return doScalar(RRuntime.isNA(value));
+        return RRuntime.asLogical(RRuntime.isNA(value));
     }
 
     @Specialization
     protected byte isNA(int value, @SuppressWarnings("unused") boolean recursive) {
-        return doScalar(RRuntime.isNA(value));
+        return RRuntime.asLogical(RRuntime.isNA(value));
     }
 
     @Specialization
     protected byte isNA(double value, @SuppressWarnings("unused") boolean recursive) {
-        return doScalar(RRuntime.isNAorNaN(value));
+        return RRuntime.asLogical(RRuntime.isNAorNaN(value));
     }
 
     @Specialization
     protected byte isNA(RComplex value, @SuppressWarnings("unused") boolean recursive) {
-        return doScalar(RRuntime.isNA(value));
+        return RRuntime.asLogical(RRuntime.isNA(value));
     }
 
     @Specialization
     protected byte isNA(String value, @SuppressWarnings("unused") boolean recursive) {
-        return doScalar(RRuntime.isNA(value));
+        return RRuntime.asLogical(RRuntime.isNA(value));
     }
 
     @Specialization
     @SuppressWarnings("unused")
     protected byte isNA(RRaw value, boolean recursive) {
-        return doScalar(false);
+        return RRuntime.LOGICAL_FALSE;
     }
 
     @Specialization
     protected byte isNA(@SuppressWarnings("unused") RNull value, @SuppressWarnings("unused") boolean recursive) {
-        return doScalar(false);
-    }
-
-    @Specialization
-    protected byte isNA(RAbstractIntVector vector, @SuppressWarnings("unused") boolean recursive) {
-        return doVector(vector, (v, i) -> naCheck.check(v.getDataAt(i)));
-    }
-
-    @Specialization
-    protected byte isNA(RAbstractDoubleVector vector, @SuppressWarnings("unused") boolean recursive) {
-        // since
-        return doVector(vector, (v, i) -> naCheck.checkNAorNaN(v.getDataAt(i)));
+        return RRuntime.LOGICAL_FALSE;
     }
 
-    @Specialization
-    protected byte isNA(RAbstractComplexVector vector, @SuppressWarnings("unused") boolean recursive) {
-        return doVector(vector, (v, i) -> naCheck.check(v.getDataAt(i)));
+    @Specialization(guards = "xAccess.supports(x)")
+    protected byte anyNACached(RAbstractAtomicVector x, @SuppressWarnings("unused") boolean recursive,
+                    @Cached("x.access()") VectorAccess xAccess) {
+        switch (xAccess.getType()) {
+            case Logical:
+            case Integer:
+            case Character:
+                // shortcut when we know there's no NAs
+                if (!x.isComplete()) {
+                    try (SequentialIterator iter = xAccess.access(x)) {
+                        while (xAccess.next(iter)) {
+                            if (xAccess.isNA(iter)) {
+                                return RRuntime.LOGICAL_TRUE;
+                            }
+                        }
+                    }
+                }
+                break;
+            case Raw:
+                return RRuntime.LOGICAL_FALSE;
+            case Double:
+                // we need to check for NaNs
+                try (SequentialIterator iter = xAccess.access(x)) {
+                    while (xAccess.next(iter)) {
+                        if (xAccess.na.checkNAorNaN(xAccess.getDouble(iter))) {
+                            return RRuntime.LOGICAL_TRUE;
+                        }
+                    }
+                }
+                break;
+            case Complex:
+                // we need to check for NaNs
+                try (SequentialIterator iter = xAccess.access(x)) {
+                    while (xAccess.next(iter)) {
+                        if (xAccess.na.checkNAorNaN(xAccess.getComplexR(iter)) || xAccess.na.checkNAorNaN(xAccess.getComplexR(iter))) {
+                            return RRuntime.LOGICAL_TRUE;
+                        }
+                    }
+                }
+                break;
+        }
+        return RRuntime.LOGICAL_FALSE;
     }
 
-    @Specialization
-    protected byte isNA(RAbstractStringVector vector, @SuppressWarnings("unused") boolean recursive) {
-        return doVector(vector, (v, i) -> naCheck.check(v.getDataAt(i)));
+    @Specialization(replaces = "anyNACached")
+    protected byte anyNAGeneric(RAbstractAtomicVector x, boolean recursive) {
+        return anyNACached(x, recursive, x.slowPathAccess());
     }
 
-    @Specialization
-    protected byte isNA(RAbstractLogicalVector vector, @SuppressWarnings("unused") boolean recursive) {
-        return doVector(vector, (v, i) -> naCheck.check(v.getDataAt(i)));
+    protected AnyNA createRecursive() {
+        return AnyNANodeGen.create(true);
     }
 
-    @Specialization
-    protected byte isNA(@SuppressWarnings("unused") RAbstractRawVector vector, @SuppressWarnings("unused") boolean recursive) {
-        return doScalar(false);
+    @Specialization(guards = {"isRecursive", "recursive == cachedRecursive"})
+    protected byte isNARecursive(RList list, boolean recursive,
+                    @Cached("recursive") boolean cachedRecursive,
+                    @Cached("createClassProfile()") ValueProfile elementProfile,
+                    @Cached("create()") RLengthNode length) {
+        if (cachedRecursive) {
+            for (int i = 0; i < list.getLength(); i++) {
+                Object value = elementProfile.profile(list.getDataAt(i));
+                if (length.executeInteger(value) > 0) {
+                    if (recursive(recursive, value) == RRuntime.LOGICAL_TRUE) {
+                        return RRuntime.LOGICAL_TRUE;
+                    }
+                }
+            }
+        }
+        return RRuntime.LOGICAL_FALSE;
     }
 
-    protected AnyNA createRecursive() {
-        return AnyNANodeGen.create();
+    @TruffleBoundary
+    private byte recursive(boolean recursive, Object value) {
+        return execute(value, recursive);
     }
 
-    @Specialization(guards = "recursive")
+    @Specialization(guards = {"!isRecursive", "recursive == cachedRecursive"})
     protected byte isNA(RList list, boolean recursive,
+                    @Cached("recursive") boolean cachedRecursive,
                     @Cached("createRecursive()") AnyNA recursiveNode,
                     @Cached("createClassProfile()") ValueProfile elementProfile,
                     @Cached("create()") RLengthNode length) {
-
         for (int i = 0; i < list.getLength(); i++) {
             Object value = elementProfile.profile(list.getDataAt(i));
-            if (length.executeInteger(value) > 0) {
-                byte result = recursiveNode.execute(value, recursive);
-                if (result == RRuntime.LOGICAL_TRUE) {
+            if (cachedRecursive || length.executeInteger(value) == 1) {
+                if (recursiveNode.execute(value, recursive) == RRuntime.LOGICAL_TRUE) {
                     return RRuntime.LOGICAL_TRUE;
                 }
             }
         }
         return RRuntime.LOGICAL_FALSE;
     }
-
-    @Specialization(guards = "!recursive")
-    @SuppressWarnings("unused")
-    protected byte isNA(RList list, boolean recursive) {
-        return RRuntime.LOGICAL_FALSE;
-    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java
index 533a4b2caa36879ed71a8fe176522ab6b9c50ee8..f23c6fd39aecbd44a4aa4cfbec5c28731bc57317 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java
@@ -30,46 +30,27 @@ 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.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.Utils;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
-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.RDataFactory.VectorFactory;
 import com.oracle.truffle.r.runtime.data.RList;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.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.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
-/**
- * The {@code} .Internal part of the {@code array} function. The R code may alter the arguments
- * before calling {@code .Internal}.
- *
- * <pre>
- * array <- function(data = NA, dim = length(data), dimnames = NULL) { .Internal.array(data, dim, dimnames) }
- * </pre>
- *
- * TODO complete. This is sufficient for the b25 benchmark use.
- */
 @RBuiltin(name = "array", kind = INTERNAL, parameterNames = {"data", "dim", "dimnames"}, behavior = PURE)
 public abstract class Array extends RBuiltinNode.Arg3 {
 
     @Child private UpdateDimNames updateDimNames;
-    private final ConditionProfile nonEmptyVectorProfile = ConditionProfile.createBinaryProfile();
 
     // it's OK for the following method to update dimnames in-place as the container is "fresh"
     private void updateDimNames(RAbstractContainer container, Object o) {
@@ -87,227 +68,76 @@ public abstract class Array extends RBuiltinNode.Arg3 {
         casts.arg("dimnames").defaultError(RError.Message.DIMNAMES_LIST).allowNull().mustBe(instanceOf(RList.class));
     }
 
-    private int dimDataHelper(RAbstractIntVector dim, int[] dimData) {
+    @Specialization(guards = {"dataAccess.supports(data)", "dimAccess.supports(dim)"})
+    protected RAbstractVector arrayCached(RAbstractVector data, RAbstractIntVector dim, Object dimNames,
+                    @Cached("data.access()") VectorAccess dataAccess,
+                    @Cached("dim.access()") VectorAccess dimAccess,
+                    @Cached("createNew(dataAccess.getType())") VectorAccess resultAccess,
+                    @Cached("createBinaryProfile()") ConditionProfile hasDimNames,
+                    @Cached("createBinaryProfile()") ConditionProfile isEmpty,
+                    @Cached("create()") VectorFactory factory) {
+        // extract dimensions and compute total length
+        int[] dimArray;
         int totalLength = 1;
-        int seenNegative = 0;
-        for (int i = 0; i < dim.getLength(); i++) {
-            dimData[i] = dim.getDataAt(i);
-            if (dimData[i] < 0) {
-                seenNegative++;
+        boolean negativeDims = false;
+        try (SequentialIterator dimIter = dimAccess.access(dim)) {
+            dimArray = new int[dimAccess.getLength(dimIter)];
+            while (dimAccess.next(dimIter)) {
+                int dimValue = dimAccess.getInt(dimIter);
+                if (dimValue < 0) {
+                    negativeDims = true;
+                }
+                totalLength *= dimValue;
+                dimArray[dimIter.getIndex()] = dimValue;
             }
-            totalLength *= dimData[i];
         }
-        if (seenNegative == dim.getLength() && seenNegative != 0) {
-            throw error(RError.Message.DIMS_CONTAIN_NEGATIVE_VALUES);
-        } else if (seenNegative > 0) {
+        if (totalLength < 0) {
             throw error(RError.Message.NEGATIVE_LENGTH_VECTORS_NOT_ALLOWED);
+        } else if (negativeDims) {
+            throw error(RError.Message.DIMS_CONTAIN_NEGATIVE_VALUES);
         }
-        return totalLength;
-    }
-
-    private RIntVector doArrayInt(RAbstractIntVector vec, RAbstractIntVector dim) {
-        int[] dimData = new int[dim.getLength()];
-        int totalLength = dimDataHelper(dim, dimData);
-        int[] data = new int[totalLength];
-        int vecLength = vec.getLength();
-        if (nonEmptyVectorProfile.profile(totalLength > 0 && vecLength > 0)) {
-            for (int i = 0; i < totalLength; i++) {
-                data[i] = vec.getDataAt(i % vec.getLength());
-            }
-            return RDataFactory.createIntVector(data, vec.isComplete(), dimData);
-        } else {
-            for (int i = 0; i < totalLength; i++) {
-                data[i] = RRuntime.INT_NA;
-            }
-            return RDataFactory.createIntVector(data, RDataFactory.INCOMPLETE_VECTOR, dimData);
-        }
-    }
-
-    @Specialization
-    protected RIntVector doArrayNoDimNames(RAbstractIntVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) {
-        return doArrayInt(vec, dim);
-    }
-
-    @Specialization
-    protected RIntVector doArray(RAbstractIntVector vec, RAbstractIntVector dim, RList dimnames) {
-        RIntVector ret = doArrayInt(vec, dim);
-        updateDimNames(ret, dimnames);
-        return ret;
-    }
-
-    private RDoubleVector doArrayDouble(RAbstractDoubleVector vec, RAbstractIntVector dim) {
-        int[] dimData = new int[dim.getLength()];
-        int totalLength = dimDataHelper(dim, dimData);
-        double[] data = new double[totalLength];
-        int vecLength = vec.getLength();
-        if (totalLength > 0 && vecLength > 0) {
-            for (int i = 0; i < totalLength; i++) {
-                data[i] = vec.getDataAt(i % vec.getLength());
-            }
-            return RDataFactory.createDoubleVector(data, vec.isComplete(), dimData);
-        } else {
-            for (int i = 0; i < totalLength; i++) {
-                data[i] = RRuntime.DOUBLE_NA;
-            }
-            return RDataFactory.createDoubleVector(data, RDataFactory.INCOMPLETE_VECTOR, dimData);
-        }
-    }
-
-    @Specialization
-    protected RDoubleVector doArrayNoDimNames(RAbstractDoubleVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) {
-        return doArrayDouble(vec, dim);
-    }
-
-    @Specialization
-    protected RDoubleVector doArray(RAbstractDoubleVector vec, RAbstractIntVector dim, RList dimnames) {
-        RDoubleVector ret = doArrayDouble(vec, dim);
-        updateDimNames(ret, dimnames);
-        return ret;
-    }
-
-    private RLogicalVector doArrayLogical(RAbstractLogicalVector vec, RAbstractIntVector dim) {
-        int[] dimData = new int[dim.getLength()];
-        int totalLength = dimDataHelper(dim, dimData);
-        byte[] data = new byte[totalLength];
-        int vecLength = vec.getLength();
-        if (totalLength > 0 && vecLength > 0) {
-            for (int i = 0; i < totalLength; i++) {
-                data[i] = vec.getDataAt(i % vec.getLength());
-            }
-            return RDataFactory.createLogicalVector(data, vec.isComplete(), dimData);
-        } else {
-            for (int i = 0; i < totalLength; i++) {
-                data[i] = RRuntime.LOGICAL_NA;
-            }
-            return RDataFactory.createLogicalVector(data, RDataFactory.INCOMPLETE_VECTOR, dimData);
-        }
-    }
-
-    @Specialization
-    protected RLogicalVector doArrayNoDimNames(RAbstractLogicalVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) {
-        return doArrayLogical(vec, dim);
-    }
-
-    @Specialization
-    protected RLogicalVector doArray(RAbstractLogicalVector vec, RAbstractIntVector dim, RList dimnames) {
-        RLogicalVector ret = doArrayLogical(vec, dim);
-        updateDimNames(ret, dimnames);
-        return ret;
-    }
-
-    private RStringVector doArrayString(RAbstractStringVector vec, RAbstractIntVector dim) {
-        int[] dimData = new int[dim.getLength()];
-        int totalLength = dimDataHelper(dim, dimData);
-        String[] data = new String[totalLength];
-        int vecLength = vec.getLength();
-        if (totalLength > 0 && vecLength > 0) {
-            for (int i = 0; i < totalLength; i++) {
-                data[i] = vec.getDataAt(i % vec.getLength());
-            }
-            return RDataFactory.createStringVector(data, vec.isComplete(), dimData);
-        } else {
-            String empty = Utils.intern("");
-            for (int i = 0; i < totalLength; i++) {
-                data[i] = empty;
-            }
-            return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR, dimData);
-        }
-    }
-
-    @Specialization
-    protected RStringVector doArrayNoDimNames(RAbstractStringVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) {
-        return doArrayString(vec, dim);
-    }
 
-    @Specialization
-    protected RStringVector doArray(RAbstractStringVector vec, RAbstractIntVector dim, RList dimnames) {
-        RStringVector ret = doArrayString(vec, dim);
-        updateDimNames(ret, dimnames);
-        return ret;
-    }
-
-    private RComplexVector doArrayComplex(RAbstractComplexVector vec, RAbstractIntVector dim) {
-        int[] dimData = new int[dim.getLength()];
-        int totalLength = dimDataHelper(dim, dimData);
-        double[] data = new double[totalLength << 1];
-        int ind = 0;
-        int vecLength = vec.getLength();
-        if (totalLength > 0 && vecLength > 0) {
-            for (int i = 0; i < totalLength; i++) {
-                RComplex d = vec.getDataAt(i % vec.getLength());
-                data[ind++] = d.getRealPart();
-                data[ind++] = d.getImaginaryPart();
-            }
-            return RDataFactory.createComplexVector(data, vec.isComplete(), dimData);
-        } else {
-            for (int i = 0; i < totalLength; i++) {
-                data[ind++] = RRuntime.COMPLEX_NA_REAL_PART;
-                data[ind++] = RRuntime.COMPLEX_NA_IMAGINARY_PART;
+        RAbstractVector result = factory.createUninitializedVector(dataAccess.getType(), totalLength, dimArray, null, null);
+
+        try (SequentialIterator resultIter = resultAccess.access(result); SequentialIterator dataIter = dataAccess.access(data)) {
+            if (isEmpty.profile(dataAccess.getLength(dataIter) == 0)) {
+                if (dataAccess.getType() == RType.Character) {
+                    // character vectors are initialized with "" instead of NA
+                    while (resultAccess.next(resultIter)) {
+                        resultAccess.setString(resultIter, "");
+                    }
+                    result.setComplete(true);
+                } else {
+                    while (resultAccess.next(resultIter)) {
+                        resultAccess.setNA(resultIter);
+                    }
+                    result.setComplete(false);
+                }
+            } else {
+                while (resultAccess.next(resultIter)) {
+                    dataAccess.nextWithWrap(dataIter);
+                    resultAccess.setFromSameType(resultIter, dataAccess, dataIter);
+                }
+                result.setComplete(!dataAccess.na.isEnabled());
             }
-            return RDataFactory.createComplexVector(data, RDataFactory.INCOMPLETE_VECTOR, dimData);
         }
-    }
-
-    @Specialization
-    protected RComplexVector doArrayNoDimNames(RAbstractComplexVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) {
-        return doArrayComplex(vec, dim);
-    }
-
-    @Specialization
-    protected RComplexVector doArray(RAbstractComplexVector vec, RAbstractIntVector dim, RList dimnames) {
-        RComplexVector ret = doArrayComplex(vec, dim);
-        updateDimNames(ret, dimnames);
-        return ret;
-    }
 
-    private RRawVector doArrayRaw(RAbstractRawVector vec, RAbstractIntVector dim) {
-        int[] dimData = new int[dim.getLength()];
-        int totalLength = dimDataHelper(dim, dimData);
-        byte[] data = new byte[totalLength];
-        int vecLength = vec.getLength();
-        if (totalLength > 0 && vecLength > 0) {
-            for (int i = 0; i < totalLength; i++) {
-                data[i] = vec.getRawDataAt(i % vec.getLength());
-            }
+        // dimensions are set as a separate step so they are checked for validity
+        if (hasDimNames.profile(dimNames instanceof RList)) {
+            updateDimNames(result, dimNames);
         } else {
-            for (int i = 0; i < totalLength; i++) {
-                data[i] = 0;
-            }
-        }
-        return RDataFactory.createRawVector(data, dimData);
-    }
-
-    @Specialization
-    protected RRawVector doArrayNoDimNames(RAbstractRawVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) {
-        return doArrayRaw(vec, dim);
-    }
-
-    @Specialization
-    protected RRawVector doArray(RAbstractRawVector vec, RAbstractIntVector dim, RList dimnames) {
-        RRawVector ret = doArrayRaw(vec, dim);
-        updateDimNames(ret, dimnames);
-        return ret;
-    }
-
-    private RList doArrayList(RList vec, RAbstractIntVector dim) {
-        int[] dimData = new int[dim.getLength()];
-        int totalLength = dimDataHelper(dim, dimData);
-        Object[] data = new Object[totalLength];
-        for (int i = 0; i < totalLength; i++) {
-            data[i] = vec.getDataAt(i % vec.getLength());
+            assert dimNames instanceof RNull;
         }
-        return RDataFactory.createList(data, dimData);
-    }
-
-    @Specialization
-    protected RList doArrayNoDimeNames(RList vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) {
-        return doArrayList(vec, dim);
+        return result;
     }
 
-    @Specialization
-    protected RList doArray(RList vec, RAbstractIntVector dim, RList dimnames) {
-        RList ret = doArrayList(vec, dim);
-        updateDimNames(ret, dimnames);
-        return ret;
+    @Specialization(replaces = "arrayCached")
+    @TruffleBoundary
+    protected RAbstractVector arrayGeneric(RAbstractVector data, RAbstractIntVector dim, Object dimNames,
+                    @Cached("createBinaryProfile()") ConditionProfile hasDimNames,
+                    @Cached("createBinaryProfile()") ConditionProfile isEmpty,
+                    @Cached("create()") VectorFactory factory) {
+        VectorAccess dataAccess = data.slowPathAccess();
+        return arrayCached(data, dim, dimNames, dataAccess, dim.slowPathAccess(), VectorAccess.createSlowPathNew(dataAccess.getType()), hasDimNames, isEmpty, factory);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
index a4b42e74a116a60e55c8384be8784d202d142c7b..cee07fbd4bbce686c77f167e96131042d7bf0c49 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
@@ -141,11 +141,11 @@ public abstract class Cat extends RBuiltinNode.Arg6 {
                 } else {
                     validateType(i + 1, obj);
                     for (int j = 0; j < objVec.getLength(); j++) {
-                        stringVecs.add(toString.executeString(objVec.getDataAtAsObject(j), false, ""));
+                        stringVecs.add(toString.executeString(objVec.getDataAtAsObject(j), ""));
                     }
                 }
             } else {
-                stringVecs.add(toString.executeString(obj, false, ""));
+                stringVecs.add(toString.executeString(obj, ""));
             }
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
index 17668e2b790690063a1eec62765b5357b37ca4a6..96b23862edb16fb271658697755d570303163c1a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
@@ -59,6 +59,7 @@ import java.nio.ShortBuffer;
 import java.nio.channels.ByteChannel;
 import java.nio.charset.Charset;
 import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -90,7 +91,6 @@ import com.oracle.truffle.r.runtime.conn.SocketConnections.RSocketConnection;
 import com.oracle.truffle.r.runtime.conn.TextConnections.TextRConnection;
 import com.oracle.truffle.r.runtime.conn.URLConnections.URLRConnection;
 import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
@@ -106,13 +106,12 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypes;
 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;
 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.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
@@ -1066,90 +1065,83 @@ public abstract class ConnectionFunctions {
             return WriteDataNodeGen.create();
         }
 
+        @TruffleBoundary
         private static ByteBuffer allocate(int capacity, boolean swap) {
             ByteBuffer buffer = ByteBuffer.allocate(capacity);
             checkOrder(buffer, swap);
             return buffer;
         }
 
-        @Specialization
-        protected ByteBuffer writeInteger(RAbstractIntVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) {
-            int length = object.getLength();
-            ByteBuffer buffer = allocate(4 * length, swap);
-            for (int i = 0; i < length; i++) {
-                int value = object.getDataAt(i);
-                buffer.putInt(value);
-            }
-            return buffer;
-        }
-
-        @Specialization
-        protected ByteBuffer writeDouble(RAbstractDoubleVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) {
-            int length = object.getLength();
-            ByteBuffer buffer = allocate(8 * length, swap);
-            for (int i = 0; i < length; i++) {
-                double value = object.getDataAt(i);
-                buffer.putDouble(value);
-            }
-            return buffer;
-        }
-
-        @Specialization
-        protected ByteBuffer writeComplex(RAbstractComplexVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) {
-            int length = object.getLength();
-            ByteBuffer buffer = allocate(16 * length, swap);
-            for (int i = 0; i < length; i++) {
-                RComplex complex = object.getDataAt(i);
-                double re = complex.getRealPart();
-                double im = complex.getImaginaryPart();
-                buffer.putDouble(re);
-                buffer.putDouble(im);
-            }
-            return buffer;
-        }
-
-        @Specialization
         @TruffleBoundary
-        protected ByteBuffer writeString(RAbstractStringVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) {
-            int length = object.getLength();
-            byte[][] data = new byte[length][];
-            int totalLength = 0;
-            for (int i = 0; i < length; i++) {
-                String s = object.getDataAt(i);
-                // There is no special encoding for NA_character_
-                data[i] = s.getBytes();
-                totalLength = totalLength + data[i].length + 1; // zero pad
-            }
-
-            ByteBuffer buffer = allocate(totalLength, swap);
-            for (int i = 0; i < length; i++) {
-                buffer.put(data[i]);
-                buffer.put((byte) 0);
-            }
-            return buffer;
-        }
+        private static byte[] encodeString(String s) {
+            return s.getBytes(StandardCharsets.UTF_8);
+        }
+
+        @Specialization(guards = "objectAccess.supports(object)")
+        protected ByteBuffer write(RAbstractVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes,
+                        @Cached("object.access()") VectorAccess objectAccess) {
+            try (SequentialIterator iter = objectAccess.access(object)) {
+                int length = objectAccess.getLength(iter);
+
+                ByteBuffer buffer;
+                switch (objectAccess.getType()) {
+                    case Integer:
+                        buffer = allocate(4 * length, swap);
+                        while (objectAccess.next(iter)) {
+                            buffer.putInt(objectAccess.getInt(iter));
+                        }
+                        return buffer;
+                    case Double:
+                        buffer = allocate(8 * length, swap);
+                        while (objectAccess.next(iter)) {
+                            buffer.putDouble(objectAccess.getDouble(iter));
+                        }
+                        return buffer;
+                    case Complex:
+                        buffer = allocate(16 * length, swap);
+                        while (objectAccess.next(iter)) {
+                            buffer.putDouble(objectAccess.getComplexR(iter));
+                            buffer.putDouble(objectAccess.getComplexI(iter));
+                        }
+                        return buffer;
+                    case Character:
+                        byte[][] data = new byte[length][];
+                        int totalLength = 0;
+                        while (objectAccess.next(iter)) {
+                            // There is no special encoding for NA_character_
+                            data[iter.getIndex()] = encodeString(objectAccess.getString(iter));
+                            // zero pad
+                            totalLength = totalLength + data[iter.getIndex()].length + 1;
+                        }
 
-        @Specialization
-        protected ByteBuffer writeLogical(RAbstractLogicalVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) {
-            // encoded as ints, with FALSE=0, TRUE=1, NA=Integer_NA_
-            int length = object.getLength();
-            ByteBuffer buffer = allocate(4 * length, swap);
-            for (int i = 0; i < length; i++) {
-                byte value = object.getDataAt(i);
-                int encoded = RRuntime.isNA(value) ? RRuntime.INT_NA : value == RRuntime.LOGICAL_FALSE ? 0 : 1;
-                buffer.putInt(encoded);
+                        buffer = allocate(totalLength, swap);
+                        for (int i = 0; i < length; i++) {
+                            buffer.put(data[i]);
+                            buffer.put((byte) 0);
+                        }
+                        return buffer;
+                    case Logical:
+                        buffer = allocate(4 * length, swap);
+                        while (objectAccess.next(iter)) {
+                            buffer.putInt(objectAccess.getInt(iter)); // converted to int
+                        }
+                        return buffer;
+                    case Raw:
+                        buffer = allocate(length, swap);
+                        while (objectAccess.next(iter)) {
+                            buffer.put(objectAccess.getRaw(iter));
+                        }
+                        return buffer;
+                    default:
+                        throw RInternalError.shouldNotReachHere();
+                }
             }
-            return buffer;
         }
 
-        @Specialization
-        protected ByteBuffer writeRaw(RAbstractRawVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) {
-            int length = object.getLength();
-            ByteBuffer buffer = allocate(length, swap);
-            for (int i = 0; i < length; i++) {
-                buffer.put(object.getRawDataAt(i));
-            }
-            return buffer;
+        @Specialization(replaces = "write")
+        @TruffleBoundary
+        protected ByteBuffer writeGeneric(RAbstractVector object, int size, boolean swap, boolean useBytes) {
+            return write(object, size, swap, useBytes, object.slowPathAccess());
         }
     }
 
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 e88dada037ba1aa458c38711edc7073277dca85c..38067a8c5101e45ac6c4ccac6e3bc2d266395b41 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
@@ -80,7 +80,7 @@ public abstract class CrossprodCommon extends RBuiltinNode.Arg2 {
         return CrossprodCommonNodeGen.create(false);
     }
 
-    @Specialization(guards = {"x.isMatrix()", "y.isMatrix()"})
+    @Specialization(guards = {"getXDimsNode.isMatrix(x)", "getYDimsNode.isMatrix(y)"})
     protected RDoubleVector crossprod(RAbstractDoubleVector x, RAbstractDoubleVector y,
                     @Cached("create()") GetDimAttributeNode getXDimsNode,
                     @Cached("create()") GetDimAttributeNode getYDimsNode) {
@@ -100,7 +100,7 @@ public abstract class CrossprodCommon extends RBuiltinNode.Arg2 {
         return copyDimNames(x, y, (RAbstractVector) matMult.executeObject(transposeX(x), transposeY(y)));
     }
 
-    @Specialization(guards = "x.isMatrix()")
+    @Specialization(guards = "getDimsNode.isMatrix(x)")
     protected RDoubleVector crossprodDoubleMatrix(RAbstractDoubleVector x, @SuppressWarnings("unused") RNull y,
                     @Cached("create()") GetReadonlyData.Double getReadonlyData,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java
index 69767d4e3dd9bf4cd91cdf9c527a677e1d101a19..c89d7c817a7af2462be489289b92eece6e822f67 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java
@@ -19,6 +19,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import java.util.Arrays;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -32,16 +33,14 @@ import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
-import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "cumprod", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE)
 public abstract class CumProd extends RBuiltinNode.Arg1 {
 
-    private final NACheck na = NACheck.create();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
-
     @Child private BinaryArithmetic mul = BinaryArithmetic.MULTIPLY.createOperation();
 
     static {
@@ -55,63 +54,63 @@ public abstract class CumProd extends RBuiltinNode.Arg1 {
     }
 
     @Specialization
-    protected RDoubleVector cumNull(@SuppressWarnings("unused") RNull rnull) {
+    protected RDoubleVector cumNull(@SuppressWarnings("unused") RNull x) {
         return RDataFactory.createEmptyDoubleVector();
     }
 
-    @Specialization(guards = "emptyVec.getLength()==0")
-    protected RAbstractVector cumEmpty(RAbstractComplexVector emptyVec) {
-        return RDataFactory.createComplexVector(new double[0], true, emptyVec.getNames());
+    @Specialization(guards = "xAccess.supports(x)")
+    protected RDoubleVector cumprodDouble(RAbstractDoubleVector x,
+                    @Cached("x.access()") VectorAccess xAccess) {
+        try (SequentialIterator iter = xAccess.access(x)) {
+            double[] array = new double[xAccess.getLength(iter)];
+            double prev = 1;
+            while (xAccess.next(iter)) {
+                double value = xAccess.getDouble(iter);
+                if (xAccess.na.check(value)) {
+                    Arrays.fill(array, iter.getIndex(), array.length, RRuntime.DOUBLE_NA);
+                    break;
+                }
+                if (xAccess.na.checkNAorNaN(value)) {
+                    Arrays.fill(array, iter.getIndex(), array.length, Double.NaN);
+                    break;
+                }
+                prev = mul.op(prev, value);
+                assert !RRuntime.isNA(prev) : "double multiplication should not introduce NAs";
+                array[iter.getIndex()] = prev;
+            }
+            return RDataFactory.createDoubleVector(array, xAccess.na.neverSeenNA(), getNamesNode.getNames(x));
+        }
     }
 
-    @Specialization(guards = "emptyVec.getLength()==0")
-    protected RAbstractVector cumEmpty(RAbstractDoubleVector emptyVec) {
-        return RDataFactory.createDoubleVector(new double[0], true, emptyVec.getNames());
+    @Specialization(replaces = "cumprodDouble")
+    protected RDoubleVector cumprodDoubleGeneric(RAbstractDoubleVector x) {
+        return cumprodDouble(x, x.slowPathAccess());
     }
 
-    @Specialization
-    protected RDoubleVector cumprod(RAbstractDoubleVector arg) {
-        double[] array = new double[arg.getLength()];
-        na.enable(arg);
-        double prev = 1;
-        int i;
-        for (i = 0; i < arg.getLength(); i++) {
-            double value = arg.getDataAt(i);
-            if (na.check(value)) {
-                Arrays.fill(array, i, array.length, RRuntime.DOUBLE_NA);
-                break;
-            }
-            if (na.checkNAorNaN(value)) {
-                Arrays.fill(array, i, array.length, Double.NaN);
-                break;
+    @Specialization(guards = "xAccess.supports(x)")
+    protected RComplexVector cumprodComplex(RAbstractComplexVector x,
+                    @Cached("x.access()") VectorAccess xAccess) {
+        try (SequentialIterator iter = xAccess.access(x)) {
+            double[] array = new double[xAccess.getLength(iter) * 2];
+            RComplex prev = RDataFactory.createComplex(1, 0);
+            while (xAccess.next(iter)) {
+                double real = xAccess.getComplexR(iter);
+                double imag = xAccess.getComplexI(iter);
+                if (xAccess.na.check(real, imag)) {
+                    Arrays.fill(array, 2 * iter.getIndex(), array.length, RRuntime.DOUBLE_NA);
+                    break;
+                }
+                prev = mul.op(prev.getRealPart(), prev.getImaginaryPart(), real, imag);
+                assert !RRuntime.isNA(prev) : "complex multiplication should not introduce NAs";
+                array[iter.getIndex() * 2] = prev.getRealPart();
+                array[iter.getIndex() * 2 + 1] = prev.getImaginaryPart();
             }
-            prev = mul.op(prev, value);
-            array[i] = prev;
+            return RDataFactory.createComplexVector(array, xAccess.na.neverSeenNA(), getNamesNode.getNames(x));
         }
-        return RDataFactory.createDoubleVector(array, na.neverSeenNA(), getNamesNode.getNames(arg));
     }
 
-    @Specialization
-    protected RComplexVector cumprod(RAbstractComplexVector arg) {
-        double[] array = new double[arg.getLength() * 2];
-        na.enable(arg);
-        RComplex prev = RDataFactory.createComplex(1, 0);
-        int i;
-        for (i = 0; i < arg.getLength(); i++) {
-            RComplex value = arg.getDataAt(i);
-            if (na.check(value)) {
-                break;
-            }
-            prev = mul.op(prev.getRealPart(), prev.getImaginaryPart(), value.getRealPart(), value.getImaginaryPart());
-            if (na.check(prev)) {
-                break;
-            }
-            array[i * 2] = prev.getRealPart();
-            array[i * 2 + 1] = prev.getImaginaryPart();
-        }
-        if (!na.neverSeenNA()) {
-            Arrays.fill(array, 2 * i, array.length, RRuntime.DOUBLE_NA);
-        }
-        return RDataFactory.createComplexVector(array, na.neverSeenNA(), getNamesNode.getNames(arg));
+    @Specialization(replaces = "cumprodComplex")
+    protected RComplexVector cumprodComplexGeneric(RAbstractComplexVector x) {
+        return cumprodComplex(x, x.slowPathAccess());
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java
index f0b47f2e76becdd87dc3801075fdd341d1a594bb..a84d226b6aa3e719e9a0865df57368ac10a44e67 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java
@@ -36,6 +36,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import java.util.Arrays;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -46,22 +47,20 @@ import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
-import com.oracle.truffle.r.runtime.data.RIntSequence;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
-import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "cumsum", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE)
 public abstract class CumSum extends RBuiltinNode.Arg1 {
 
-    private final NACheck na = NACheck.create();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
-
     @Child private BinaryArithmetic add = BinaryArithmetic.ADD.createOperation();
 
     static {
@@ -81,100 +80,107 @@ public abstract class CumSum extends RBuiltinNode.Arg1 {
     }
 
     @Specialization
-    protected RDoubleVector cumNull(@SuppressWarnings("unused") RNull rnull) {
+    protected RDoubleVector cumNull(@SuppressWarnings("unused") RNull x) {
         return RDataFactory.createEmptyDoubleVector();
     }
 
-    @Specialization(guards = "emptyVec.getLength()==0")
-    protected RAbstractVector cumEmpty(RAbstractComplexVector emptyVec) {
-        return RDataFactory.createComplexVector(new double[0], true, emptyVec.getNames());
+    @Specialization(guards = "x.getLength()==0")
+    protected RAbstractVector cumEmpty(RAbstractComplexVector x) {
+        return RDataFactory.createComplexVector(new double[0], true, getNamesNode.getNames(x));
     }
 
-    @Specialization(guards = "emptyVec.getLength()==0")
-    protected RAbstractVector cumEmpty(RAbstractDoubleVector emptyVec) {
-        return RDataFactory.createDoubleVector(new double[0], true, emptyVec.getNames());
+    @Specialization(guards = "x.getLength()==0")
+    protected RAbstractVector cumEmpty(RAbstractDoubleVector x) {
+        return RDataFactory.createDoubleVector(new double[0], true, getNamesNode.getNames(x));
     }
 
-    @Specialization(guards = "emptyVec.getLength()==0")
-    protected RAbstractVector cumEmpty(RAbstractIntVector emptyVec) {
-        return RDataFactory.createIntVector(new int[0], true, emptyVec.getNames());
+    @Specialization(guards = "x.getLength()==0")
+    protected RAbstractVector cumEmpty(RAbstractIntVector x) {
+        return RDataFactory.createIntVector(new int[0], true, getNamesNode.getNames(x));
     }
 
-    @Specialization
-    protected RIntVector cumsum(RIntSequence arg) {
-        int[] res = new int[arg.getLength()];
-        int current = arg.getStart();
-        int prev = 0;
-        na.enable(true);
-        for (int i = 0; i < arg.getLength(); i++) {
-            prev = add.op(prev, current);
-            if (na.check(prev)) {
-                Arrays.fill(res, i, res.length, RRuntime.INT_NA);
-                break;
+    @Specialization(guards = "xAccess.supports(x)")
+    protected RIntVector cumsumInt(RAbstractIntVector x,
+                    @Cached("x.access()") VectorAccess xAccess) {
+        try (SequentialIterator iter = xAccess.access(x)) {
+            int[] array = new int[xAccess.getLength(iter)];
+            int prev = 0;
+            while (xAccess.next(iter)) {
+                int value = xAccess.getInt(iter);
+                if (xAccess.na.check(value)) {
+                    Arrays.fill(array, iter.getIndex(), array.length, RRuntime.INT_NA);
+                    break;
+                }
+                prev = add.op(prev, value);
+                // integer addition can introduce NAs
+                if (add.introducesNA() && RRuntime.isNA(prev)) {
+                    Arrays.fill(array, iter.getIndex(), array.length, RRuntime.INT_NA);
+                    break;
+                }
+                array[iter.getIndex()] = prev;
             }
-            current += arg.getStride();
-            res[i] = prev;
+            return RDataFactory.createIntVector(array, xAccess.na.neverSeenNA() && !add.introducesNA(), getNamesNode.getNames(x));
         }
-        return RDataFactory.createIntVector(res, na.neverSeenNA(), getNamesNode.getNames(arg));
     }
 
-    @Specialization
-    protected RDoubleVector cumsum(RAbstractDoubleVector arg) {
-        double[] res = new double[arg.getLength()];
-        double prev = 0.0;
-        na.enable(true);
-        for (int i = 0; i < arg.getLength(); i++) {
-            double value = arg.getDataAt(i);
-            // cumsum behaves different than cumprod for NaNs:
-            if (na.check(value)) {
-                Arrays.fill(res, i, res.length, RRuntime.DOUBLE_NA);
-                break;
-            } else if (na.checkNAorNaN(value)) {
-                Arrays.fill(res, i, res.length, Double.NaN);
-                break;
-            }
-            prev = add.op(prev, value);
-            res[i] = prev;
-        }
-        return RDataFactory.createDoubleVector(res, na.neverSeenNA(), getNamesNode.getNames(arg));
+    @Specialization(replaces = "cumsumInt")
+    protected RIntVector cumsumIntGeneric(RAbstractIntVector x) {
+        return cumsumInt(x, x.slowPathAccess());
     }
 
-    @Specialization
-    protected RIntVector cumsum(RAbstractIntVector arg) {
-        int[] res = new int[arg.getLength()];
-        int prev = 0;
-        int i;
-        na.enable(true);
-        for (i = 0; i < arg.getLength(); i++) {
-            if (na.check(arg.getDataAt(i))) {
-                break;
-            }
-            prev = add.op(prev, arg.getDataAt(i));
-            if (na.check(prev)) {
-                break;
+    @Specialization(guards = "xAccess.supports(x)")
+    protected RDoubleVector cumsumDouble(RAbstractDoubleVector x,
+                    @Cached("x.access()") VectorAccess xAccess) {
+        try (SequentialIterator iter = xAccess.access(x)) {
+            double[] array = new double[xAccess.getLength(iter)];
+            double prev = 0;
+            while (xAccess.next(iter)) {
+                double value = xAccess.getDouble(iter);
+                if (xAccess.na.check(value)) {
+                    Arrays.fill(array, iter.getIndex(), array.length, RRuntime.DOUBLE_NA);
+                    break;
+                }
+                if (xAccess.na.checkNAorNaN(value)) {
+                    Arrays.fill(array, iter.getIndex(), array.length, Double.NaN);
+                    break;
+                }
+                prev = add.op(prev, value);
+                assert !RRuntime.isNA(prev) : "double addition should not introduce NAs";
+                array[iter.getIndex()] = prev;
             }
-            res[i] = prev;
+            return RDataFactory.createDoubleVector(array, xAccess.na.neverSeenNA(), getNamesNode.getNames(x));
         }
-        if (!na.neverSeenNA()) {
-            Arrays.fill(res, i, res.length, RRuntime.INT_NA);
-        }
-        return RDataFactory.createIntVector(res, na.neverSeenNA(), getNamesNode.getNames(arg));
     }
 
-    @Specialization
-    protected RComplexVector cumsum(RAbstractComplexVector arg) {
-        double[] res = new double[arg.getLength() * 2];
-        RComplex prev = RDataFactory.createComplex(0.0, 0.0);
-        na.enable(true);
-        for (int i = 0; i < arg.getLength(); i++) {
-            prev = add.op(prev.getRealPart(), prev.getImaginaryPart(), arg.getDataAt(i).getRealPart(), arg.getDataAt(i).getImaginaryPart());
-            if (na.check(arg.getDataAt(i))) {
-                Arrays.fill(res, 2 * i, res.length, RRuntime.DOUBLE_NA);
-                break;
+    @Specialization(replaces = "cumsumDouble")
+    protected RDoubleVector cumsumDoubleGeneric(RAbstractDoubleVector x) {
+        return cumsumDouble(x, x.slowPathAccess());
+    }
+
+    @Specialization(guards = "xAccess.supports(x)")
+    protected RComplexVector cumsumComplex(RAbstractComplexVector x,
+                    @Cached("x.access()") VectorAccess xAccess) {
+        try (SequentialIterator iter = xAccess.access(x)) {
+            double[] array = new double[xAccess.getLength(iter) * 2];
+            RComplex prev = RDataFactory.createComplex(0, 0);
+            while (xAccess.next(iter)) {
+                double real = xAccess.getComplexR(iter);
+                double imag = xAccess.getComplexI(iter);
+                if (xAccess.na.check(real, imag)) {
+                    Arrays.fill(array, 2 * iter.getIndex(), array.length, RRuntime.DOUBLE_NA);
+                    break;
+                }
+                prev = add.op(prev.getRealPart(), prev.getImaginaryPart(), real, imag);
+                assert !RRuntime.isNA(prev) : "complex addition should not introduce NAs";
+                array[iter.getIndex() * 2] = prev.getRealPart();
+                array[iter.getIndex() * 2 + 1] = prev.getImaginaryPart();
             }
-            res[2 * i] = prev.getRealPart();
-            res[2 * i + 1] = prev.getImaginaryPart();
+            return RDataFactory.createComplexVector(array, xAccess.na.neverSeenNA(), getNamesNode.getNames(x));
         }
-        return RDataFactory.createComplexVector(res, na.neverSeenNA(), getNamesNode.getNames(arg));
+    }
+
+    @Specialization(replaces = "cumsumComplex")
+    protected RComplexVector cumsumComplexGeneric(RAbstractComplexVector x) {
+        return cumsumComplex(x, x.slowPathAccess());
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java
index ca1cda7f78336c92bba9dfc5fa216436a663e481..a3e832046227da221745e0023bed1b3cac7d97fe 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java
@@ -14,26 +14,26 @@ package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asDoubleVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.complexValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte0;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
 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.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
-import com.oracle.truffle.api.CompilerDirectives;
+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.Message;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
 @RBuiltin(name = "diag", kind = INTERNAL, parameterNames = {"x", "nrow", "ncol"}, behavior = PURE)
 public abstract class Diag extends RBuiltinNode.Arg3 {
@@ -48,7 +48,6 @@ public abstract class Diag extends RBuiltinNode.Arg3 {
     private int checkX(RAbstractVector x, int nrow, int ncol) {
         int mn = (nrow < ncol) ? nrow : ncol;
         if (mn > 0 && x.getLength() == 0) {
-            CompilerDirectives.transferToInterpreter();
             throw error(Message.POSITIVE_LENGTH, "x");
         }
         return mn;
@@ -56,8 +55,8 @@ public abstract class Diag extends RBuiltinNode.Arg3 {
 
     @Specialization
     protected Object diag(@SuppressWarnings("unused") RNull x, int nrow, int ncol) {
-        if (nrow == 0 && ncol == 0) {
-            return RDataFactory.createDoubleVector(new double[]{}, true, new int[]{0, 0});
+        if (nrow == 0 || ncol == 0) {
+            return RDataFactory.createDoubleVector(new double[]{}, true, new int[]{nrow, ncol});
         } else {
             throw error(Message.X_NUMERIC);
         }
@@ -74,43 +73,31 @@ public abstract class Diag extends RBuiltinNode.Arg3 {
         return RDataFactory.createDoubleVector(data, !RRuntime.isNA(x), new int[]{nrow, ncol});
     }
 
-    @Specialization
-    protected Object diag(RAbstractComplexVector x, int nrow, int ncol) {
+    @Specialization(guards = "xAccess.supports(x)")
+    protected RAbstractVector diagCached(RAbstractVector x, int nrow, int ncol,
+                    @Cached("x.access()") VectorAccess xAccess,
+                    @Cached("createNew(xAccess.getType())") VectorAccess resultAccess,
+                    @Cached("create()") VectorFactory factory) {
         int mn = checkX(x, nrow, ncol);
 
-        double[] data = new double[nrow * ncol * 2];
-        int nx = x.getLength();
-        for (int j = 0; j < mn; j++) {
-            RComplex value = x.getDataAt(j % nx);
-            int index = j * (nrow + 1) * 2;
-            data[index] = value.getRealPart();
-            data[index + 1] = value.getImaginaryPart();
-        }
-        return RDataFactory.createComplexVector(data, x.isComplete(), new int[]{nrow, ncol});
-    }
-
-    @Specialization
-    protected Object diag(RAbstractDoubleVector source, int nrow, int ncol) {
-        int mn = checkX(source, nrow, ncol);
-
-        double[] data = new double[nrow * ncol];
-        int nx = source.getLength();
-        for (int j = 0; j < mn; j++) {
-            data[j * (nrow + 1)] = source.getDataAt(j % nx);
+        try (SequentialIterator xIter = xAccess.access(x)) {
+            RAbstractVector result = factory.createUninitializedVector(xAccess.getType(), nrow * ncol, new int[]{nrow, ncol}, null, null);
+            try (RandomIterator resultIter = resultAccess.randomAccess(result)) {
+                int resultIndex = 0;
+                for (int j = 0; j < mn; j++) {
+                    xAccess.nextWithWrap(xIter);
+                    resultAccess.setFromSameType(resultIter, resultIndex, xAccess, xIter);
+                    resultIndex += nrow + 1;
+                }
+            }
+            result.setComplete(x.isComplete());
+            return result;
         }
-        return RDataFactory.createDoubleVector(data, source.isComplete(), new int[]{nrow, ncol});
     }
 
-    @Specialization
-    protected Object diag(RAbstractLogicalVector source, int nrow, int ncol) {
-        int mn = checkX(source, nrow, ncol);
-
-        byte[] data = new byte[nrow * ncol];
-        int nx = source.getLength();
-        for (int j = 0; j < mn; j++) {
-            data[j * (nrow + 1)] = source.getDataAt(j % nx);
-        }
-        return RDataFactory.createLogicalVector(data, source.isComplete(), new int[]{nrow, ncol});
+    @Specialization(replaces = "diagCached")
+    protected RAbstractVector diagGeneric(RAbstractVector x, int nrow, int ncol,
+                    @Cached("create()") VectorFactory factory) {
+        return diagCached(x, nrow, ncol, x.slowPathAccess(), VectorAccess.createSlowPathNew(x.getRType()), factory);
     }
-
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java
index aa20ab830cb4c4a1ef9ff37b5afc90c34a03b4d4..c58f3020137ad9a68eaede21ba87a484355e5688 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java
@@ -70,6 +70,7 @@ public abstract class Expression extends RBuiltinNode.Arg1 {
     }
 
     @Specialization
+    @TruffleBoundary
     protected Object doExpression(RPromise language) {
         return RDataFactory.createExpression(new Object[]{convert(language)});
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
index c1c66e7f6d09059fe7f3a70fcc8f35dc0e766857..972ed1ade43a577e5cdfd9f91ca678b2519c8708 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
@@ -51,7 +51,6 @@ import com.oracle.truffle.r.nodes.function.RCallerHelper;
 import com.oracle.truffle.r.nodes.function.call.CallRFunctionCachedNode;
 import com.oracle.truffle.r.nodes.function.call.CallRFunctionCachedNodeGen;
 import com.oracle.truffle.r.nodes.objects.GetS4DataSlot;
-import com.oracle.truffle.r.nodes.objects.GetS4DataSlotNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RCaller;
@@ -146,7 +145,7 @@ public class GetFunctions {
 
     public static final class S4ToEnvNode extends CastNode {
 
-        @Child private GetS4DataSlot getS4Data = GetS4DataSlotNodeGen.create(RType.Environment);
+        @Child private GetS4DataSlot getS4Data = GetS4DataSlot.create(RType.Environment);
 
         @Override
         public Object execute(Object obj) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
index 05cbcbc30395a817ec2ee19a832c87018dced4ef..37d8da2fa8707921e44f38ef3b1093974fe2838c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
@@ -27,46 +27,41 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
-import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
-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.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
 @ImportStatic(RRuntime.class)
 @RBuiltin(name = "is.na", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
 public abstract class IsNA extends RBuiltinNode.Arg1 {
 
     @Child private IsNA recursiveIsNA;
-    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
+
+    @Child private VectorFactory factory = VectorFactory.create();
     @Child private GetDimAttributeNode getDimsNode = GetDimAttributeNode.create();
-    @Child private SetDimNamesAttributeNode setDimNamesNode = SetDimNamesAttributeNode.create();
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
     @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
 
-    private final ConditionProfile nullDimNamesProfile = ConditionProfile.createBinaryProfile();
-
     static {
         Casts.noCasts(IsNA.class);
     }
@@ -86,93 +81,21 @@ public abstract class IsNA extends RBuiltinNode.Arg1 {
         return RRuntime.asLogical(RRuntime.isNA(value));
     }
 
-    @Specialization
-    protected RLogicalVector isNA(RAbstractIntVector vector) {
-        byte[] resultVector = new byte[vector.getLength()];
-        for (int i = 0; i < vector.getLength(); i++) {
-            resultVector[i] = RRuntime.asLogical(RRuntime.isNA(vector.getDataAt(i)));
-        }
-        return createResult(resultVector, vector);
-    }
-
     @Specialization
     protected byte isNA(double value) {
         return RRuntime.asLogical(RRuntime.isNAorNaN(value));
     }
 
-    @Specialization
-    protected RLogicalVector isNA(RAbstractDoubleVector vector) {
-        byte[] resultVector = new byte[vector.getLength()];
-        for (int i = 0; i < vector.getLength(); i++) {
-            resultVector[i] = RRuntime.asLogical(RRuntime.isNAorNaN(vector.getDataAt(i)));
-        }
-        return createResult(resultVector, vector);
-    }
-
-    @Specialization
-    protected RLogicalVector isNA(RComplexVector vector) {
-        byte[] resultVector = new byte[vector.getLength()];
-        for (int i = 0; i < vector.getLength(); i++) {
-            RComplex complex = vector.getDataAt(i);
-            resultVector[i] = RRuntime.asLogical(RRuntime.isNA(complex));
-        }
-        return createResult(resultVector, vector);
-    }
-
     @Specialization
     protected byte isNA(String value) {
         return RRuntime.asLogical(RRuntime.isNA(value));
     }
 
-    @Specialization
-    protected RLogicalVector isNA(RStringVector vector) {
-        byte[] resultVector = new byte[vector.getLength()];
-        for (int i = 0; i < vector.getLength(); i++) {
-            resultVector[i] = RRuntime.asLogical(RRuntime.isNA(vector.getDataAt(i)));
-        }
-        return createResult(resultVector, vector);
-    }
-
-    @Specialization
-    protected RLogicalVector isNA(RList list) {
-        byte[] resultVector = new byte[list.getLength()];
-        for (int i = 0; i < list.getLength(); i++) {
-            Object result = isNARecursive(list.getDataAt(i));
-            byte isNAResult;
-            if (result instanceof Byte) {
-                isNAResult = (Byte) result;
-            } else if (result instanceof RLogicalVector) {
-                RLogicalVector vector = (RLogicalVector) result;
-                // result is false unless that element is a length-one atomic vector
-                // and the single element of that vector is regarded as NA
-                isNAResult = (vector.getLength() == 1) ? vector.getDataAt(0) : RRuntime.LOGICAL_FALSE;
-            } else {
-                throw fail("unhandled return type in isNA(list)");
-            }
-            resultVector[i] = isNAResult;
-        }
-        return RDataFactory.createLogicalVector(resultVector, RDataFactory.COMPLETE_VECTOR);
-    }
-
-    @TruffleBoundary
-    private static UnsupportedOperationException fail(String message) {
-        throw new UnsupportedOperationException(message);
-    }
-
     @Specialization
     protected byte isNA(byte value) {
         return RRuntime.asLogical(RRuntime.isNA(value));
     }
 
-    @Specialization
-    protected RLogicalVector isNA(RLogicalVector vector) {
-        byte[] resultVector = new byte[vector.getLength()];
-        for (int i = 0; i < vector.getLength(); i++) {
-            resultVector[i] = (RRuntime.isNA(vector.getDataAt(i)) ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE);
-        }
-        return createResult(resultVector, vector);
-    }
-
     @Specialization
     protected byte isNA(RComplex value) {
         return RRuntime.asLogical(RRuntime.isNA(value));
@@ -183,19 +106,62 @@ public abstract class IsNA extends RBuiltinNode.Arg1 {
         return RRuntime.LOGICAL_FALSE;
     }
 
-    @Specialization
-    protected RLogicalVector isNA(RRawVector vector) {
-        byte[] resultVector = new byte[vector.getLength()];
-        for (int i = 0; i < vector.getLength(); i++) {
-            resultVector[i] = RRuntime.LOGICAL_FALSE;
+    private RLogicalVector isNAVector(RAbstractVector vector, VectorAccess access) {
+        try (SequentialIterator iter = access.access(vector)) {
+            byte[] data = new byte[access.getLength(iter)];
+            while (access.next(iter)) {
+                boolean isNA;
+                switch (access.getType()) {
+                    case Double:
+                        isNA = access.na.checkNAorNaN(access.getDouble(iter));
+                        break;
+                    case Character:
+                    case Complex:
+                    case Integer:
+                    case Logical:
+                        isNA = access.isNA(iter);
+                        break;
+                    case Raw:
+                        isNA = false;
+                        break;
+                    case List:
+                        Object result = isNARecursive(access.getListElement(iter));
+                        if (result instanceof Byte) {
+                            isNA = ((byte) result) == RRuntime.LOGICAL_TRUE;
+                        } else if (result instanceof RLogicalVector) {
+                            RLogicalVector recVector = (RLogicalVector) result;
+                            // result is false unless that element is a length-one atomic vector
+                            // and the single element of that vector is regarded as NA
+                            isNA = (recVector.getLength() == 1) ? recVector.getDataAt(0) == RRuntime.LOGICAL_TRUE : false;
+                        } else {
+                            throw RInternalError.shouldNotReachHere("unhandled return type in isNA(list)");
+                        }
+                        break;
+                    default:
+                        throw RInternalError.shouldNotReachHere();
+
+                }
+                data[iter.getIndex()] = RRuntime.asLogical(isNA);
+            }
+            return factory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR, getDimsNode.getDimensions(vector), getNamesNode.getNames(vector), getDimNamesNode.getDimNames(vector));
         }
-        return createResult(resultVector, vector);
+    }
+
+    @Specialization(guards = "access.supports(vector)")
+    protected RLogicalVector isNACached(RAbstractVector vector,
+                    @Cached("vector.access()") VectorAccess access) {
+        return isNAVector(vector, access);
+    }
+
+    @Specialization(replaces = "isNACached")
+    protected RLogicalVector isNAGeneric(RAbstractVector vector) {
+        return isNAVector(vector, vector.slowPathAccess());
     }
 
     @Specialization
     protected RLogicalVector isNA(RNull value) {
         warning(RError.Message.IS_NA_TO_NON_VECTOR, value.getRType().getName());
-        return RDataFactory.createEmptyLogicalVector();
+        return factory.createEmptyLogicalVector();
     }
 
     @Specialization(guards = "isForeignObject(obj)")
@@ -203,20 +169,9 @@ public abstract class IsNA extends RBuiltinNode.Arg1 {
         return RRuntime.LOGICAL_FALSE;
     }
 
-    // Note: all the primitive values have specialization, so we can only get RTypedValue in
-    // fallback
     @Fallback
     protected byte isNA(Object value) {
-        warning(RError.Message.IS_NA_TO_NON_VECTOR, value instanceof RTypedValue ? ((RTypedValue) value).getRType().getName() : value);
+        warning(RError.Message.IS_NA_TO_NON_VECTOR, Predef.typeName().apply(value));
         return RRuntime.LOGICAL_FALSE;
     }
-
-    private RLogicalVector createResult(byte[] data, RAbstractVector originalVector) {
-        RLogicalVector result = RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR, getDimsNode.getDimensions(originalVector), getNamesNode.getNames(originalVector));
-        RList dimNames = getDimNamesNode.getDimNames(originalVector);
-        if (nullDimNamesProfile.profile(dimNames != null)) {
-            setDimNamesNode.setDimNames(result, dimNames);
-        }
-        return result;
-    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
index 1c8e9a467c3778ce3db3195961695c17e40ca341..dee51d150d82e3b75710a984716eb785e812ae04 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
@@ -41,6 +41,7 @@ import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetClassAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctionsFactory.GetDimAttributeNodeGen;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -59,6 +60,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.RSymbol;
+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;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
@@ -72,17 +74,14 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
  */
 public class IsTypeFunctions {
 
-    protected abstract static class MissingAdapter extends RBuiltinNode.Arg1 {
-
-        protected static Casts createCasts(Class<? extends MissingAdapter> extCls) {
-            Casts casts = new Casts(extCls);
-            casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENT_MISSING, "x");
-            return casts;
-        }
+    protected static Casts createCasts(Class<? extends RBuiltinNode> extCls) {
+        Casts casts = new Casts(extCls);
+        casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENT_MISSING, "x");
+        return casts;
     }
 
     @RBuiltin(name = "is.array", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-    public abstract static class IsArray extends MissingAdapter {
+    public abstract static class IsArray extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsArray.class);
@@ -106,7 +105,7 @@ public class IsTypeFunctions {
 
     @ImportStatic(RRuntime.class)
     @RBuiltin(name = "is.recursive", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsRecursive extends MissingAdapter {
+    public abstract static class IsRecursive extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsRecursive.class);
@@ -144,9 +143,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.atomic", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsAtomic extends MissingAdapter {
-
-        @Child private InheritsCheckNode inheritsFactorCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR);
+    public abstract static class IsAtomic extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsAtomic.class);
@@ -157,28 +154,19 @@ public class IsTypeFunctions {
             return RRuntime.LOGICAL_TRUE;
         }
 
-        @Specialization(guards = {"!isRList(arg)", "!isRExpression(arg)"})
-        protected byte isAtomic(@SuppressWarnings("unused") RAbstractVector arg) {
+        @Specialization
+        protected byte isAtomic(@SuppressWarnings("unused") RAbstractAtomicVector arg) {
             return RRuntime.LOGICAL_TRUE;
         }
 
-        protected static boolean isNonListVector(Object value) {
-            return value instanceof Integer || value instanceof Double || value instanceof RComplex || value instanceof String || value instanceof RRaw ||
-                            (value instanceof RAbstractVector && !(value instanceof RListBase));
-        }
-
-        protected boolean isFactor(Object value) {
-            return inheritsFactorCheck.execute(value);
-        }
-
-        @Specialization(guards = {"!isRMissing(value)", "!isRNull(value)", "!isFactor(value)", "!isNonListVector(value)"})
+        @Fallback
         protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
 
     @RBuiltin(name = "is.call", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsCall extends MissingAdapter {
+    public abstract static class IsCall extends RBuiltinNode.Arg1 {
 
         static {
             Casts.noCasts(IsCall.class);
@@ -196,7 +184,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.character", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsCharacter extends MissingAdapter {
+    public abstract static class IsCharacter extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsCharacter.class);
@@ -218,7 +206,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.complex", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsComplex extends MissingAdapter {
+    public abstract static class IsComplex extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsComplex.class);
@@ -240,7 +228,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.double", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsDouble extends MissingAdapter {
+    public abstract static class IsDouble extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsDouble.class);
@@ -262,7 +250,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.expression", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsExpression extends MissingAdapter {
+    public abstract static class IsExpression extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsExpression.class);
@@ -280,7 +268,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.function", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsFunction extends MissingAdapter {
+    public abstract static class IsFunction extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsFunction.class);
@@ -298,7 +286,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.integer", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsInteger extends MissingAdapter {
+    public abstract static class IsInteger extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsInteger.class);
@@ -320,7 +308,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.language", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsLanguage extends MissingAdapter {
+    public abstract static class IsLanguage extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsLanguage.class);
@@ -348,7 +336,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.list", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsList extends MissingAdapter {
+    public abstract static class IsList extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsList.class);
@@ -373,7 +361,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.logical", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsLogical extends MissingAdapter {
+    public abstract static class IsLogical extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsLogical.class);
@@ -395,7 +383,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.matrix", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-    public abstract static class IsMatrix extends MissingAdapter {
+    public abstract static class IsMatrix extends RBuiltinNode.Arg1 {
 
         private final ConditionProfile isMatrixProfile = ConditionProfile.createBinaryProfile();
         @Child private GetDimAttributeNode getDim = GetDimAttributeNodeGen.create();
@@ -416,7 +404,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.name", aliases = {"is.symbol"}, kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsName extends MissingAdapter {
+    public abstract static class IsName extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsName.class);
@@ -434,12 +422,18 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.numeric", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-    public abstract static class IsNumeric extends MissingAdapter {
+    public abstract static class IsNumeric extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsNumeric.class);
         }
 
+        @Child private InheritsCheckNode inheritsCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR);
+
+        protected boolean isFactor(Object o) {
+            return inheritsCheck.execute(o);
+        }
+
         @Specialization(guards = "!isFactor(value)")
         protected byte isType(@SuppressWarnings("unused") RAbstractIntVector value) {
             return RRuntime.LOGICAL_TRUE;
@@ -459,20 +453,14 @@ public class IsTypeFunctions {
             return value instanceof Integer || value instanceof Double || value instanceof RAbstractIntVector || value instanceof RAbstractDoubleVector;
         }
 
-        @Specialization(guards = {"!isRMissing(value)", "!isAnyNumeric(value)"})
+        @Fallback
         protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
-
-        @Child private InheritsCheckNode inheritsCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR);
-
-        protected boolean isFactor(Object o) {
-            return inheritsCheck.execute(o);
-        }
     }
 
     @RBuiltin(name = "is.null", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsNull extends MissingAdapter {
+    public abstract static class IsNull extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsNull.class);
@@ -497,7 +485,7 @@ public class IsTypeFunctions {
      * {@code FALSE}.
      */
     @RBuiltin(name = "is.object", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsObject extends MissingAdapter {
+    public abstract static class IsObject extends RBuiltinNode.Arg1 {
 
         @Child private GetClassAttributeNode getClassNode = GetClassAttributeNode.create();
 
@@ -519,7 +507,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.pairlist", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsPairList extends MissingAdapter {
+    public abstract static class IsPairList extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsPairList.class);
@@ -542,7 +530,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.raw", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsRaw extends MissingAdapter {
+    public abstract static class IsRaw extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsRaw.class);
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 a0ccf139a825fec278a10995f7589705fa588b36..b1681c9175c0ecfe0cd9dd114104f0d67a80a4b5 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
@@ -65,7 +65,6 @@ 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.GetDataCopy;
 import com.oracle.truffle.r.runtime.data.nodes.GetReadonlyData;
 import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
@@ -751,7 +750,6 @@ public class LaFunctions {
 
         @Specialization
         protected Object doSvd(String ju, RAbstractDoubleVector x, RAbstractDoubleVector s, RAbstractDoubleVector u, RAbstractDoubleVector vt,
-                        @Cached("create()") GetDataCopy.Double getDataCopyNode,
                         @Cached("createCopyAllAttributes()") CopyAttributesNode copyAttrNode,
                         @Cached("create()") GetDimAttributeNode getDimsNode) {
 
@@ -767,10 +765,10 @@ public class LaFunctions {
 
             int[] iwork = new int[8 * Math.min(n, p)];
 
-            double[] xvals = getDataCopyNode.execute(x);
-            double[] sdata = getDataCopyNode.execute(s);
-            double[] udata = getDataCopyNode.execute(u);
-            double[] vtdata = getDataCopyNode.execute(vt);
+            double[] xvals = x.materialize().getDataTemp();
+            double[] sdata = s.materialize().getDataTemp();
+            double[] udata = u.materialize().getDataTemp();
+            double[] vtdata = vt.materialize().getDataTemp();
             double[] tmp = new double[1];
 
             int info = dgesddNode.execute(ju.charAt(0), n, p, xvals, n, sdata, udata, ldu, vtdata, ldvt, tmp, -1, iwork);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java
index 161972a2025762f48eb886d98d443d34169fd7e2..3630833bce79cfadd30c24afa80a8f1b8ca603ea 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java
@@ -35,6 +35,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RVector;
@@ -68,8 +69,8 @@ public abstract class Matrix extends RBuiltinNode.Arg7 {
     static {
         Casts casts = new Casts(Matrix.class);
         casts.arg("data").asVector().mustBe(instanceOf(RAbstractVector.class));
-        casts.arg("nrow").asIntegerVector().findFirst(RError.Message.NON_NUMERIC_MATRIX_EXTENT);
-        casts.arg("ncol").asIntegerVector().findFirst(RError.Message.NON_NUMERIC_MATRIX_EXTENT);
+        casts.arg("nrow").asIntegerVector().findFirst(Message.NON_NUMERIC_MATRIX_EXTENT).mustNotBeNA(Message.INVALID_LARGE_NA_VALUE, "nrow");
+        casts.arg("ncol").asIntegerVector().findFirst(Message.NON_NUMERIC_MATRIX_EXTENT).mustNotBeNA(Message.INVALID_LARGE_NA_VALUE, "ncol");
         casts.arg("byrow").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("dimnames").allowNull().mustBe(instanceOf(RAbstractListVector.class));
         casts.arg("missingNr").asLogicalVector().findFirst().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java
index 53a91f171580ab9796ecd04558e257dbee5a5ac3..a4f4732f9fe0504cdf94bfe4348ce04350b2ea76 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java
@@ -26,81 +26,79 @@ import static com.oracle.truffle.r.runtime.RDispatch.INTERNAL_GENERIC;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE_SUMMARY;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
+@ImportStatic(RType.class)
 @RBuiltin(name = "mean", kind = INTERNAL, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE_SUMMARY)
 public abstract class Mean extends RBuiltinNode.Arg1 {
 
-    private final BranchProfile emptyProfile = BranchProfile.create();
-
-    @Child private BinaryArithmetic add = BinaryArithmetic.ADD.createOperation();
-    @Child private BinaryArithmetic div = BinaryArithmetic.DIV.createOperation();
-
     static {
         Casts.noCasts(Mean.class);
     }
 
-    @Specialization
-    protected double mean(RAbstractDoubleVector x) {
-        if (x.getLength() == 0) {
-            emptyProfile.enter();
-            return Double.NaN;
+    @Specialization(guards = {"access.supports(x)", "access.getType() != Complex"})
+    protected double meanDoubleCached(RAbstractVector x,
+                    @Cached("x.access()") VectorAccess access,
+                    @Cached("createBinaryProfile()") ConditionProfile emptyProfile) {
+        try (SequentialIterator iter = access.access(x)) {
+            if (emptyProfile.profile(!access.next(iter))) {
+                return Double.NaN;
+            }
+            double sum = 0;
+            do {
+                double value = access.getDouble(iter);
+                if (access.na.checkNAorNaN(value)) {
+                    return value;
+                }
+                sum += value;
+            } while (access.next(iter));
+            return sum / access.getLength(iter);
         }
-        double sum = x.getDataAt(0);
-        for (int k = 1; k < x.getLength(); k++) {
-            sum = add.op(sum, x.getDataAt(k));
-        }
-        return div.op(sum, x.getLength());
     }
 
-    @Specialization
-    protected double mean(RAbstractIntVector x) {
-        if (x.getLength() == 0) {
-            emptyProfile.enter();
-            return Double.NaN;
-        }
-        double sum = x.getDataAt(0);
-        for (int k = 1; k < x.getLength(); k++) {
-            sum = add.op(sum, x.getDataAt(k));
-        }
-        return div.op(sum, x.getLength());
+    @Specialization(replaces = "meanDoubleCached", guards = "x.getRType() != Complex")
+    protected double meanDoubleGeneric(RAbstractVector x,
+                    @Cached("createBinaryProfile()") ConditionProfile emptyProfile) {
+        return meanDoubleCached(x, x.slowPathAccess(), emptyProfile);
     }
 
-    @Specialization
-    protected double mean(RAbstractLogicalVector x) {
-        if (x.getLength() == 0) {
-            emptyProfile.enter();
-            return Double.NaN;
-        }
-        double sum = x.getDataAt(0);
-        for (int k = 1; k < x.getLength(); k++) {
-            sum = add.op(sum, x.getDataAt(k));
+    @Specialization(guards = {"access.supports(x)", "access.getType() == Complex"})
+    protected RComplex meanComplexCached(RAbstractVector x,
+                    @Cached("x.access()") VectorAccess access,
+                    @Cached("createBinaryProfile()") ConditionProfile emptyProfile) {
+        try (SequentialIterator iter = access.access(x)) {
+            if (emptyProfile.profile(!access.next(iter))) {
+                return RComplex.valueOf(Double.NaN, Double.NaN);
+            }
+            double sumR = 0;
+            double sumI = 0;
+            do {
+                double valueR = access.getComplexR(iter);
+                double valueI = access.getComplexI(iter);
+                if (access.na.check(valueR, valueI)) {
+                    return RComplex.valueOf(valueR, valueI);
+                }
+                sumR += valueR;
+                sumI += valueI;
+            } while (access.next(iter));
+            int length = access.getLength(iter);
+            return RComplex.valueOf(sumR / length, sumI / length);
         }
-        return div.op(sum, x.getLength());
     }
 
-    @Specialization
-    protected RComplex mean(RAbstractComplexVector x) {
-        if (x.getLength() == 0) {
-            emptyProfile.enter();
-            return RDataFactory.createComplex(Double.NaN, Double.NaN);
-        }
-        RComplex sum = x.getDataAt(0);
-        RComplex comp;
-        for (int k = 1; k < x.getLength(); k++) {
-            comp = x.getDataAt(k);
-            sum = add.op(sum.getRealPart(), sum.getImaginaryPart(), comp.getRealPart(), comp.getImaginaryPart());
-        }
-        return div.op(sum.getRealPart(), sum.getImaginaryPart(), x.getLength(), 0);
+    @Specialization(replaces = "meanComplexCached", guards = "x.getRType() == Complex")
+    protected RComplex meanComplexGeneric(RAbstractVector x,
+                    @Cached("createBinaryProfile()") ConditionProfile emptyProfile) {
+        return meanComplexCached(x, x.slowPathAccess(), emptyProfile);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
index da39fe9bdec0bf28a7259cf9f31fb90fe5b65302..2ca65bc6427b9c391f9faf31de90e40cd2c9bb8e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
@@ -14,33 +14,30 @@ import static com.oracle.truffle.r.runtime.RDispatch.SUMMARY_GROUP_GENERIC;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE_SUMMARY;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
-import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 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.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
-import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
+@ImportStatic(RType.class)
 @RBuiltin(name = "prod", kind = PRIMITIVE, parameterNames = {"...", "na.rm"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE_SUMMARY)
 public abstract class Prod extends RBuiltinNode.Arg2 {
 
-    // TODO: handle multiple arguments, handle na.rm
-
     static {
-        Casts.noCasts(Prod.class);
+        Casts casts = new Casts(Prod.class);
+        casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(Predef.toBoolean());
     }
 
     @Override
@@ -48,139 +45,154 @@ public abstract class Prod extends RBuiltinNode.Arg2 {
         return new Object[]{RArgsValuesAndNames.EMPTY, RRuntime.LOGICAL_FALSE};
     }
 
-    @Child private Prod prodRecursive;
-
-    public abstract Object executeObject(Object x);
-
     @Child private BinaryArithmetic prod = BinaryArithmetic.MULTIPLY.createOperation();
 
-    @Specialization
-    protected Object prod(RArgsValuesAndNames args) {
-        int argsLen = args.getLength();
-        if (argsLen == 0) {
-            return 1d;
+    @ExplodeLoop
+    protected static boolean supports(RArgsValuesAndNames args, VectorAccess[] argAccess) {
+        if (args.getLength() != argAccess.length) {
+            return false;
         }
-        if (prodRecursive == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            prodRecursive = insert(ProdNodeGen.create());
+        for (int i = 0; i < argAccess.length; i++) {
+            if (!argAccess[i].supports(args.getArgument(i))) {
+                return false;
+            }
         }
-        Object ret = 1d;
-        if (argsLen > 0) {
-            double prodReal;
-            double prodImg;
-            boolean complex;
-            if (ret instanceof RComplex) {
-                RComplex c = (RComplex) ret;
-                prodReal = c.getRealPart();
-                prodImg = c.getImaginaryPart();
-                complex = true;
-            } else {
-                prodReal = (Double) ret;
-                prodImg = 0d;
-                complex = false;
+        return true;
+    }
+
+    protected static VectorAccess[] createAccess(RArgsValuesAndNames args, RType topmostType) {
+        VectorAccess[] result = new VectorAccess[args.getLength()];
+        for (int i = 0; i < result.length; i++) {
+            VectorAccess access = VectorAccess.create(args.getArgument(i));
+            if (access == null) {
+                return null;
             }
-            for (int i = 0; i < argsLen; i++) {
-                Object aProd = prodRecursive.executeObject(args.getArgument(i));
-                double aProdReal;
-                double aProdImg;
-                if (aProd instanceof RComplex) {
-                    RComplex c = (RComplex) aProd;
-                    if (RRuntime.isNA(c)) {
-                        return c;
-                    }
-                    aProdReal = c.getRealPart();
-                    aProdImg = c.getImaginaryPart();
-                    complex = true;
-                } else {
-                    aProdReal = (Double) aProd;
-                    aProdImg = 0d;
-                    if (RRuntime.isNA(aProdReal)) {
-                        return aProd;
-                    }
-                }
-                if (complex) {
-                    RComplex c = prod.op(prodReal, prodImg, aProdReal, aProdImg);
-                    prodReal = c.getRealPart();
-                    prodImg = c.getImaginaryPart();
-                } else {
-                    prodReal = prod.op(prodReal, aProdReal);
-                }
+            RType type = access.getType();
+            if (type != RType.Null && type != RType.Logical && type != RType.Integer && type != RType.Double && type != topmostType) {
+                return null;
             }
-            ret = complex ? RComplex.valueOf(prodReal, prodImg) : prodReal;
+            result[i] = access;
         }
-        return ret;
+        return result;
     }
 
-    private final ValueProfile intVecProfile = ValueProfile.createClassProfile();
-    private final NACheck naCheck = NACheck.create();
-
-    @Specialization
-    protected double prod(RAbstractDoubleVector x) {
-        RAbstractDoubleVector profiledVec = intVecProfile.profile(x);
-        double product = 1;
-        naCheck.enable(x);
-        for (int k = 0; k < profiledVec.getLength(); k++) {
-            double value = profiledVec.getDataAt(k);
-            if (naCheck.check(value)) {
-                return RRuntime.DOUBLE_NA;
+    @Specialization(guards = {"argAccess != null", "supports(args, argAccess)", "naRm == cachedNaRm"})
+    @ExplodeLoop
+    protected double prodDoubleCached(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean naRm,
+                    @Cached("naRm") boolean cachedNaRm,
+                    @Cached("createAccess(args, Double)") VectorAccess[] argAccess) {
+        double value = 1;
+        for (int i = 0; i < argAccess.length; i++) {
+            VectorAccess access = argAccess[i];
+            double element = prodDouble(args.getArgument(i), access, cachedNaRm);
+            if (!cachedNaRm && access.na.check(element)) {
+                return element;
             }
-            product = prod.op(product, value);
+            value *= element;
         }
-        return product;
+        return value;
     }
 
-    @Specialization
-    protected double prod(RAbstractIntVector x) {
-        RAbstractIntVector profiledVec = intVecProfile.profile(x);
-        double product = 1;
-        naCheck.enable(x);
-        for (int k = 0; k < profiledVec.getLength(); k++) {
-            int data = profiledVec.getDataAt(k);
-            if (naCheck.check(data)) {
-                return RRuntime.DOUBLE_NA;
+    @Specialization(guards = {"argAccess != null", "supports(args, argAccess)", "naRm == cachedNaRm"})
+    @ExplodeLoop
+    protected RComplex prodComplexCached(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean naRm,
+                    @Cached("naRm") boolean cachedNaRm,
+                    @Cached("createAccess(args, Complex)") VectorAccess[] argAccess) {
+        RComplex value = RComplex.valueOf(1, 0);
+        for (int i = 0; i < argAccess.length; i++) {
+            VectorAccess access = argAccess[i];
+            RComplex element = prodComplex(args.getArgument(i), access, cachedNaRm);
+            if (!cachedNaRm && access.na.check(element)) {
+                return element;
             }
-            product = prod.op(product, data);
+            value = prod.op(value.getRealPart(), value.getImaginaryPart(), element.getRealPart(), element.getImaginaryPart());
         }
-        return product;
+        return value;
     }
 
-    @Specialization
-    protected double prod(RAbstractLogicalVector x) {
-        RAbstractLogicalVector profiledVec = intVecProfile.profile(x);
-        double product = 1;
-        naCheck.enable(x);
-        for (int k = 0; k < profiledVec.getLength(); k++) {
-            byte value = profiledVec.getDataAt(k);
-            if (naCheck.check(value)) {
-                return RRuntime.DOUBLE_NA;
+    @Specialization(replaces = {"prodDoubleCached", "prodComplexCached"})
+    protected Object prodGeneric(RArgsValuesAndNames args, boolean naRm) {
+        int length = args.getLength();
+        double value = 1;
+        int i = 0;
+        for (; i < length; i++) {
+            Object arg = args.getArgument(i);
+            VectorAccess access = VectorAccess.createSlowPath(arg);
+            if (access == null) {
+                break;
+            }
+            RType type = access.getType();
+            if (type != RType.Null && type != RType.Logical && type != RType.Integer && type != RType.Double) {
+                break;
+            }
+            double element = prodDouble(arg, access, naRm);
+            if (!naRm && access.na.check(element)) {
+                return element;
             }
-            product = prod.op(product, value);
+            value *= element;
         }
-        return product;
+        if (i == length) {
+            return value;
+        }
+        RComplex complexValue = RComplex.valueOf(1, 0);
+        for (; i < length; i++) {
+            Object arg = args.getArgument(i);
+            VectorAccess access = VectorAccess.createSlowPath(arg);
+            if (access == null) {
+                break;
+            }
+            RType type = access.getType();
+            if (!type.isNumeric() && type != RType.Null) {
+                break;
+            }
+            RComplex element = prodComplex(arg, access, naRm);
+            if (!naRm && access.na.check(element)) {
+                return element;
+            }
+            complexValue = prod.op(complexValue.getRealPart(), complexValue.getImaginaryPart(), element.getRealPart(), element.getImaginaryPart());
+        }
+        if (i == length) {
+            return complexValue;
+        }
+        throw error(RError.Message.INVALID_TYPE_ARGUMENT, Predef.typeName().apply(args.getArgument(i)));
     }
 
-    @Specialization
-    protected RComplex prod(RAbstractComplexVector x) {
-        RAbstractComplexVector profiledVec = intVecProfile.profile(x);
-        RComplex product = RDataFactory.createComplexRealOne();
-        naCheck.enable(x);
-        for (int k = 0; k < profiledVec.getLength(); k++) {
-            RComplex a = profiledVec.getDataAt(k);
-            if (naCheck.check(a)) {
-                return a;
+    protected static double prodDouble(Object v, VectorAccess access, boolean naRm) {
+        try (SequentialIterator iter = access.access(v)) {
+            double value = 1;
+            while (access.next(iter)) {
+                double element = access.getDouble(iter);
+                if (access.na.check(element)) {
+                    if (!naRm) {
+                        return RRuntime.DOUBLE_NA;
+                    }
+                } else {
+                    value *= element;
+                }
             }
-            product = prod.op(product.getRealPart(), product.getImaginaryPart(), a.getRealPart(), a.getImaginaryPart());
+            return value;
         }
-        return product;
     }
 
-    @Specialization
-    protected double prod(@SuppressWarnings("unused") RNull n) {
-        return 1d;
+    protected RComplex prodComplex(Object v, VectorAccess access, boolean naRm) {
+        try (SequentialIterator iter = access.access(v)) {
+            RComplex value = RComplex.valueOf(1, 0);
+            while (access.next(iter)) {
+                RComplex element = access.getComplex(iter);
+                if (access.na.check(element)) {
+                    if (!naRm) {
+                        return element;
+                    }
+                } else {
+                    value = prod.op(value.getRealPart(), value.getImaginaryPart(), element.getRealPart(), element.getImaginaryPart());
+                }
+            }
+            return value;
+        }
     }
 
     @Fallback
-    protected Object prod(Object o) {
-        throw error(RError.Message.INVALID_TYPE_ARGUMENT, Predef.typeName().apply(o));
+    protected Object prod(Object v, @SuppressWarnings("unused") Object naRm) {
+        throw error(RError.Message.INVALID_TYPE_ARGUMENT, Predef.typeName().apply(v));
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java
index 9395c6682ce00d2918381fb53a963329567b0bf6..f269495c60854adbcf3695aa66ae4d1c7fa398e0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java
@@ -65,8 +65,8 @@ public abstract class Range extends RBuiltinNode.Arg3 {
 
     @Specialization(guards = "args.getLength() == 1")
     protected RVector<?> rangeLengthOne(RArgsValuesAndNames args, boolean naRm, boolean finite) {
-        Object min = minReduce.executeReduce(args.getArgument(0), naRm, finite);
-        Object max = maxReduce.executeReduce(args.getArgument(0), naRm, finite);
+        Object min = minReduce.executeReduce(args.getArgument(0), naRm || finite, finite);
+        Object max = maxReduce.executeReduce(args.getArgument(0), naRm || finite, finite);
         return createResult(min, max);
     }
 
@@ -84,8 +84,8 @@ public abstract class Range extends RBuiltinNode.Arg3 {
     protected RVector<?> range(RArgsValuesAndNames args, boolean naRm, boolean finite,
                     @Cached("create()") Combine combine) {
         Object combined = combine.executeCombine(args, false);
-        Object min = minReduce.executeReduce(combined, naRm, finite);
-        Object max = maxReduce.executeReduce(combined, naRm, finite);
+        Object min = minReduce.executeReduce(combined, naRm || finite, finite);
+        Object max = maxReduce.executeReduce(combined, naRm || finite, finite);
         return createResult(min, max);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java
index 7387acb53a474e1a3cc57427742902df405fc1ec..6d1ef76310482907a94d3283240d4d629a583f9c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java
@@ -40,9 +40,11 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
 /**
  * Conversion and manipulation of objects of type "raw".
@@ -57,17 +59,26 @@ public class RawFunctions {
             casts.arg("x").defaultError(RError.Message.ARG_MUST_BE_CHARACTER_VECTOR_LENGTH_ONE).mustBe(stringValue()).asStringVector().mustBe(notEmpty());
         }
 
-        @Specialization
-        protected RRawVector charToRaw(RAbstractStringVector x) {
-            if (x.getLength() > 1) {
-                warning(RError.Message.ARG_SHOULD_BE_CHARACTER_VECTOR_LENGTH_ONE);
-            }
-            String s = x.getDataAt(0);
-            byte[] data = new byte[s.length()];
-            for (int i = 0; i < data.length; i++) {
-                data[i] = (byte) s.charAt(i);
+        @Specialization(guards = "xAccess.supports(x)")
+        protected RRawVector charToRaw(RAbstractStringVector x,
+                        @Cached("x.access()") VectorAccess xAccess) {
+            try (RandomIterator iter = xAccess.randomAccess(x)) {
+                if (xAccess.getLength(iter) != 1) {
+                    warning(RError.Message.ARG_SHOULD_BE_CHARACTER_VECTOR_LENGTH_ONE);
+                }
+                String s = xAccess.getString(iter, 0);
+                byte[] data = new byte[s.length()];
+                for (int i = 0; i < data.length; i++) {
+                    data[i] = (byte) s.charAt(i);
+                }
+                return RDataFactory.createRawVector(data);
             }
-            return RDataFactory.createRawVector(data);
+        }
+
+        @Specialization(replaces = "charToRaw")
+        @TruffleBoundary
+        protected RRawVector charToRawGeneric(RAbstractStringVector x) {
+            return charToRaw(x, x.slowPathAccess());
         }
     }
 
@@ -80,28 +91,45 @@ public class RawFunctions {
             casts.arg("multiple").defaultError(RError.Message.INVALID_LOGICAL).asLogicalVector().findFirst().mustNotBeNA().map(toBoolean());
         }
 
-        @Specialization
         @TruffleBoundary
-        protected RStringVector rawToChar(RAbstractRawVector x, boolean multiple) {
-            RStringVector result;
-            if (multiple) {
-                String[] data = new String[x.getLength()];
-                for (int i = 0; i < data.length; i++) {
-                    data[i] = new String(new byte[]{x.getRawDataAt(i)});
-                }
-                result = RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR);
-            } else {
-                int j = 0;
-                byte[] data = new byte[x.getLength()];
-                for (int i = 0; i < data.length; i++) {
-                    byte b = x.getRawDataAt(i);
-                    if (b != 0) {
-                        data[j++] = b;
+        private static String createString(int j, byte[] data) {
+            return new String(data, 0, j);
+        }
+
+        @TruffleBoundary
+        private static String createString(byte value) {
+            return new String(new byte[]{value});
+        }
+
+        @Specialization(guards = "xAccess.supports(x)")
+        protected Object rawToChar(RAbstractRawVector x, boolean multiple,
+                        @Cached("x.access()") VectorAccess xAccess) {
+            try (SequentialIterator iter = xAccess.access(x)) {
+                if (multiple) {
+                    String[] data = new String[xAccess.getLength(iter)];
+                    while (xAccess.next(iter)) {
+                        byte value = xAccess.getRaw(iter);
+                        data[iter.getIndex()] = createString(value);
+                    }
+                    return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR);
+                } else {
+                    int j = 0;
+                    byte[] data = new byte[xAccess.getLength(iter)];
+                    while (xAccess.next(iter)) {
+                        byte b = xAccess.getRaw(iter);
+                        if (b != 0) {
+                            data[j++] = b;
+                        }
                     }
+                    return createString(j, data);
                 }
-                result = RDataFactory.createStringVectorFromScalar(new String(data, 0, j));
             }
-            return result;
+        }
+
+        @Specialization(replaces = "rawToChar")
+        @TruffleBoundary
+        protected Object rawToCharGeneric(RAbstractRawVector x, boolean multiple) {
+            return rawToChar(x, multiple, x.slowPathAccess());
         }
     }
 
@@ -114,23 +142,30 @@ public class RawFunctions {
             casts.arg("n").defaultError(RError.Message.MUST_BE_SMALL_INT, "shift").asIntegerVector().findFirst().mustNotBeNA().mustBe(gte(-8).and(lte(8)));
         }
 
-        @Specialization
+        @Specialization(guards = "xAccess.supports(x)")
         protected RRawVector rawShift(RAbstractRawVector x, int n,
-                        @Cached("createBinaryProfile()") ConditionProfile negativeShiftProfile) {
-            byte[] data = new byte[x.getLength()];
-            if (negativeShiftProfile.profile(n < 0)) {
-                for (int i = 0; i < data.length; i++) {
-                    data[i] = (byte) ((x.getRawDataAt(i) & 0xff) >> (-n));
-                }
-            } else {
-                for (int i = 0; i < data.length; i++) {
-                    data[i] = (byte) (x.getRawDataAt(i) << n);
+                        @Cached("createBinaryProfile()") ConditionProfile negativeShiftProfile,
+                        @Cached("x.access()") VectorAccess xAccess) {
+            try (SequentialIterator iter = xAccess.access(x)) {
+                byte[] data = new byte[xAccess.getLength(iter)];
+                if (negativeShiftProfile.profile(n < 0)) {
+                    while (xAccess.next(iter)) {
+                        data[iter.getIndex()] = (byte) ((xAccess.getRaw(iter) & 0xff) >> (-n));
+                    }
+                } else {
+                    while (xAccess.next(iter)) {
+                        data[iter.getIndex()] = (byte) (xAccess.getRaw(iter) << n);
+                    }
                 }
+                return RDataFactory.createRawVector(data);
             }
-            return RDataFactory.createRawVector(data);
         }
-    }
-
-    // TODO the rest of the functions
 
+        @Specialization(replaces = "rawShift")
+        @TruffleBoundary
+        protected RRawVector rawShiftGeneric(RAbstractRawVector x, int n,
+                        @Cached("createBinaryProfile()") ConditionProfile negativeShiftProfile) {
+            return rawShift(x, n, negativeShiftProfile, x.slowPathAccess());
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java
index 3afe3566f550717f1ebf1ee311c4e129a4659027..dddf8bfadbbfd7e0f40b5cf9b06f63686d688c4f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java
@@ -25,6 +25,8 @@ package com.oracle.truffle.r.nodes.builtin.base;
 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.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -32,6 +34,8 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
 @RBuiltin(name = "rawToBits", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
 public abstract class RawToBits extends RBuiltinNode.Arg1 {
@@ -41,17 +45,26 @@ public abstract class RawToBits extends RBuiltinNode.Arg1 {
         casts.arg("x").mustNotBeNull(RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x").mustBe(Predef.rawValue(), RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x");
     }
 
-    @Specialization
-    protected RAbstractRawVector rawToBits(RAbstractRawVector x) {
-        byte[] result = new byte[8 * x.getLength()];
-        int pos = 0;
-        for (int j = 0; j < x.getLength(); j++) {
-            byte temp = x.getRawDataAt(j);
-            for (int i = 0; i < 8; i++) {
-                result[pos++] = (byte) (temp & 1);
-                temp >>= 1;
+    @Specialization(guards = "xAccess.supports(x)")
+    protected RAbstractRawVector rawToBits(RAbstractRawVector x,
+                    @Cached("x.access()") VectorAccess xAccess) {
+        try (SequentialIterator iter = xAccess.access(x)) {
+            byte[] result = new byte[8 * x.getLength()];
+            int pos = 0;
+            while (xAccess.next(iter)) {
+                byte temp = xAccess.getRaw(iter);
+                for (int i = 0; i < 8; i++) {
+                    result[pos++] = (byte) (temp & 1);
+                    temp >>= 1;
+                }
             }
+            return RDataFactory.createRawVector(result);
         }
-        return RDataFactory.createRawVector(result);
+    }
+
+    @Specialization(replaces = "rawToBits")
+    @TruffleBoundary
+    protected RAbstractRawVector rawToBitsGeneric(RAbstractRawVector x) {
+        return rawToBits(x, x.slowPathAccess());
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java
index 9ece548f64e888b27287187d3d912401c354872f..0fade482ee9484506923c2d4d37feac2bc06bd62 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java
@@ -28,29 +28,19 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
-import java.util.function.IntFunction;
-
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
-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.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.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory;
+import com.oracle.truffle.r.runtime.data.RVector;
 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.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
 @RBuiltin(name = "rep.int", kind = INTERNAL, parameterNames = {"x", "times"}, behavior = PURE)
 public abstract class RepeatInternal extends RBuiltinNode.Arg2 {
@@ -64,136 +54,70 @@ public abstract class RepeatInternal extends RBuiltinNode.Arg2 {
                         RError.Message.INVALID_VALUE, "times");
     }
 
-    @FunctionalInterface
-    private interface ArrayUpdateFunction<ValueT, ArrayT> {
-        void update(ArrayT array, int pos, ValueT value, int index);
-    }
+    private RAbstractVector performRep(RAbstractVector value, RAbstractIntVector times, VectorFactory factory, VectorAccess valueAccess, VectorAccess timesAccess, VectorAccess resultAccess) {
+        try (SequentialIterator valueIter = valueAccess.access(value); SequentialIterator timesIter = timesAccess.access(times)) {
+            int valueLength = valueAccess.getLength(valueIter);
+            int timesLength = timesAccess.getLength(timesIter);
 
-    @FunctionalInterface
-    private interface CreateResultFunction<ResultT, ArrayT> {
-        ResultT create(ArrayT array, boolean complete);
-    }
-
-    private <ValueT extends RAbstractVector, ResultT extends ValueT, ArrayT> ResultT repInt(ValueT value, RAbstractIntVector times, IntFunction<ArrayT> arrayConstructor,
-                    ArrayUpdateFunction<ValueT, ArrayT> arrayUpdate, CreateResultFunction<ResultT, ArrayT> createResult) {
-        ArrayT result;
-        int timesLength = times.getLength();
-        int valueLength = value.getLength();
-        if (timesOneProfile.profile(timesLength == 1)) {
-            int timesValue = times.getDataAt(0);
-            if (timesValue < 0) {
-                throw error(RError.Message.INVALID_VALUE, "times");
-            }
-            int count = timesValue * valueLength;
-            result = arrayConstructor.apply(count);
-            int pos = 0;
-            for (int i = 0; i < timesValue; i++) {
-                for (int j = 0; j < valueLength; j++) {
-                    arrayUpdate.update(result, pos++, value, j);
-                }
-            }
-        } else if (timesLength == valueLength) {
-            int count = 0;
-            for (int i = 0; i < timesLength; i++) {
-                int data = times.getDataAt(i);
-                if (data < 0) {
+            RVector<?> result;
+            if (timesOneProfile.profile(timesLength == 1)) {
+                timesAccess.next(timesIter);
+                int timesValue = timesAccess.getInt(timesIter);
+                if (timesValue < 0) {
                     throw error(RError.Message.INVALID_VALUE, "times");
                 }
-                count += data;
-            }
-            result = arrayConstructor.apply(count);
-            int pos = 0;
-            for (int i = 0; i < valueLength; i++) {
-                int num = times.getDataAt(i);
-                for (int j = 0; j < num; j++) {
-                    arrayUpdate.update(result, pos++, value, i);
-                }
-            }
-        } else {
-            throw error(RError.Message.INVALID_VALUE, "times");
-        }
-        return createResult.create(result, value.isComplete());
-    }
-
-    @Specialization
-    protected RDoubleVector repInt(RAbstractDoubleVector value, RAbstractIntVector times) {
-        return repInt(value, times, double[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createDoubleVector);
-    }
-
-    @Specialization
-    protected RIntVector repInt(RAbstractIntVector value, RAbstractIntVector times) {
-        return repInt(value, times, int[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createIntVector);
-    }
-
-    @Specialization
-    protected RLogicalVector repInt(RAbstractLogicalVector value, RAbstractIntVector times) {
-        return repInt(value, times, byte[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createLogicalVector);
-    }
-
-    @Specialization
-    protected RStringVector repInt(RAbstractStringVector value, RAbstractIntVector times) {
-        return repInt(value, times, String[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createStringVector);
-    }
-
-    @Specialization
-    protected RRawVector repInt(RAbstractRawVector value, RAbstractIntVector times) {
-        return repInt(value, times, byte[]::new, (array, pos, val, index) -> array[pos] = val.getRawDataAt(index), (array, complete) -> RDataFactory.createRawVector(array));
-    }
-
-    @Specialization
-    protected RComplexVector repComplex(RAbstractComplexVector value, RAbstractIntVector times) {
-        int timesLength = times.getLength();
-        int valueLength = value.getLength();
-        double[] resultArray;
-        if (timesOneProfile.profile(timesLength == 1)) {
-            int timesValue = times.getDataAt(0);
-            if (timesValue < 0) {
-                throw error(RError.Message.INVALID_VALUE, "times");
-            }
-            resultArray = new double[(timesValue * valueLength) << 1];
-            int pos = 0;
-            for (int i = 0; i < timesValue; i++) {
-                for (int j = 0; j < valueLength; j++) {
-                    RComplex complex = value.getDataAt(j);
-                    resultArray[pos++] = complex.getRealPart();
-                    resultArray[pos++] = complex.getImaginaryPart();
+                result = factory.createVector(valueAccess.getType(), timesValue * valueLength, false);
+                try (SequentialIterator resultIter = resultAccess.access(result)) {
+                    for (int i = 0; i < timesValue; i++) {
+                        while (valueAccess.next(valueIter)) {
+                            resultAccess.next(resultIter);
+                            resultAccess.setFromSameType(resultIter, valueAccess, valueIter);
+                        }
+                        valueAccess.reset(valueIter);
+                    }
                 }
-            }
-        } else if (timesLength == valueLength) {
-            int count = 0;
-            for (int i = 0; i < timesLength; i++) {
-                int data = times.getDataAt(i);
-                if (data < 0) {
-                    throw error(RError.Message.INVALID_VALUE, "times");
+            } else if (timesLength == valueLength) {
+                int count = 0;
+                while (timesAccess.next(timesIter)) {
+                    int num = timesAccess.getInt(timesIter);
+                    if (num < 0) {
+                        throw error(RError.Message.INVALID_VALUE, "times");
+                    }
+                    count += num;
                 }
-                count += data;
-            }
-            resultArray = new double[count << 1];
-            int pos = 0;
-            for (int i = 0; i < valueLength; i++) {
-                int num = times.getDataAt(i);
-                RComplex complex = value.getDataAt(i);
-                for (int j = 0; j < num; j++) {
-                    resultArray[pos++] = complex.getRealPart();
-                    resultArray[pos++] = complex.getImaginaryPart();
+                result = factory.createVector(valueAccess.getType(), count, false);
+
+                timesAccess.reset(timesIter);
+                try (SequentialIterator resultIter = resultAccess.access(result)) {
+                    while (timesAccess.next(timesIter) && valueAccess.next(valueIter)) {
+                        int num = timesAccess.getInt(timesIter);
+                        for (int i = 0; i < num; i++) {
+                            resultAccess.next(resultIter);
+                            resultAccess.setFromSameType(resultIter, valueAccess, valueIter);
+                        }
+                    }
                 }
+            } else {
+                throw error(RError.Message.INVALID_VALUE, "times");
             }
-        } else {
-            throw error(RError.Message.INVALID_VALUE, "times");
+            result.setComplete(!valueAccess.na.isEnabled());
+            return result;
         }
-        return RDataFactory.createComplexVector(resultArray, value.isComplete());
     }
 
-    @Specialization
-    protected RList repList(RList value, int times) {
-        int oldLength = value.getLength();
-        int length = value.getLength() * times;
-        Object[] array = new Object[length];
-        for (int i = 0; i < times; i++) {
-            for (int j = 0; j < oldLength; j++) {
-                array[i * oldLength + j] = value.getDataAt(j);
-            }
-        }
-        return RDataFactory.createList(array);
+    @Specialization(guards = {"valueAccess.supports(value)", "timesAccess.supports(times)"})
+    protected RAbstractVector repCached(RAbstractVector value, RAbstractIntVector times,
+                    @Cached("create()") VectorFactory factory,
+                    @Cached("value.access()") VectorAccess valueAccess,
+                    @Cached("times.access()") VectorAccess timesAccess,
+                    @Cached("createNew(value.getRType())") VectorAccess resultAccess) {
+        return performRep(value, times, factory, valueAccess, timesAccess, resultAccess);
+    }
+
+    @Specialization(replaces = "repCached")
+    @TruffleBoundary
+    protected RAbstractVector repGeneric(RAbstractVector value, RAbstractIntVector times,
+                    @Cached("create()") VectorFactory factory) {
+        return performRep(value, times, factory, value.slowPathAccess(), times.slowPathAccess(), VectorAccess.createSlowPathNew(value.getRType()));
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
index cf0a608ef11441a88109cc56e1580643c41c4d5a..a66473e331cc373a18fa761822dd8e71279e0e4f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
@@ -12,40 +12,44 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notIntNA;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte0;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import java.util.Arrays;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RIntVector;
-import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.RRawVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
 @RBuiltin(name = "rep_len", kind = INTERNAL, parameterNames = {"x", "length.out"}, behavior = PURE)
 public abstract class RepeatLength extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(RepeatLength.class);
-        casts.arg("x").allowNull().mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE_NO_VECTOR);
-        // with default error message, SHOW_CALLER does not work
-        casts.arg("length.out").defaultError(RError.Message.INVALID_VALUE, "length.out").mustNotBeNull().asIntegerVector().mustBe(size(1)).findFirst().mustBe(notIntNA());
+        casts.arg("x").allowNull().mustBe(abstractVectorValue().or(instanceOf(RExpression.class)), RError.Message.ATTEMPT_TO_REPLICATE_NO_VECTOR);
+        casts.arg("length.out").defaultError(RError.Message.INVALID_VALUE, "length.out").mustNotBeNull().asIntegerVector().mustBe(singleElement()).findFirst().mustNotBeNA().mustBe(gte0());
     }
 
     @Specialization
@@ -106,72 +110,33 @@ public abstract class RepeatLength extends RBuiltinNode.Arg2 {
         return RDataFactory.createLogicalVector(array, value != RRuntime.LOGICAL_NA);
     }
 
-    //
-    // Specialization for vector values
-    //
-    @Specialization
-    protected RIntVector repLen(RAbstractIntVector value, int length) {
-        int[] array = new int[length];
-        for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) {
-            array[i] = value.getDataAt(j);
+    @Specialization(guards = "xAccess.supports(x)")
+    protected RAbstractVector repLenCached(RAbstractVector x, int length,
+                    @Cached("x.access()") VectorAccess xAccess,
+                    @Cached("createNew(xAccess.getType())") VectorAccess resultAccess,
+                    @Cached("createBinaryProfile()") ConditionProfile emptyProfile,
+                    @Cached("create()") VectorFactory factory) {
+        try (SequentialIterator xIter = xAccess.access(x)) {
+            if (emptyProfile.profile(xAccess.getLength(xIter) == 0)) {
+                return factory.createVector(xAccess.getType(), length, true);
+            }
+            RAbstractVector result = factory.createVector(xAccess.getType(), length, false);
+            try (SequentialIterator resultIter = resultAccess.access(result)) {
+                while (resultAccess.next(resultIter)) {
+                    xAccess.nextWithWrap(xIter);
+                    resultAccess.setFromSameType(resultIter, xAccess, xIter);
+                }
+            }
+            result.setComplete(x.isComplete());
+            return result;
         }
-        return RDataFactory.createIntVector(array, value.isComplete());
     }
 
-    @Specialization
-    protected RDoubleVector repLen(RDoubleVector value, int length) {
-        double[] array = new double[length];
-        for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) {
-            array[i] = value.getDataAt(j);
-        }
-        return RDataFactory.createDoubleVector(array, value.isComplete());
+    @Specialization(replaces = "repLenCached")
+    protected RAbstractVector repLenGeneric(RAbstractVector x, int length,
+                    @Cached("createBinaryProfile()") ConditionProfile emptyProfile,
+                    @Cached("create()") VectorFactory factory) {
+        return repLenCached(x, length, x.slowPathAccess(), VectorAccess.createSlowPathNew(x.getRType()), emptyProfile, factory);
     }
 
-    @Specialization
-    protected RStringVector repLen(RStringVector vectorToRepeat, int length) {
-        String[] result = new String[length];
-        int vectorToRepeatLength = vectorToRepeat.getLength();
-        for (int i = 0; i < length; i++) {
-            result[i] = vectorToRepeat.getDataAt(i % vectorToRepeatLength);
-        }
-        return RDataFactory.createStringVector(result, vectorToRepeat.isComplete());
-    }
-
-    @Specialization
-    protected RRawVector repLen(RRawVector value, int length) {
-        byte[] array = new byte[length];
-        for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) {
-            array[i] = value.getRawDataAt(j);
-        }
-        return RDataFactory.createRawVector(array);
-    }
-
-    @Specialization
-    protected RComplexVector repLen(RComplexVector value, int length) {
-        final int resultLength = length * 2;
-        double[] array = new double[resultLength];
-        for (int i = 0, j = 0; i < resultLength; i += 2, j = Utils.incMod(j, value.getLength())) {
-            array[i] = value.getDataAt(j).getRealPart();
-            array[i + 1] = value.getDataAt(j).getImaginaryPart();
-        }
-        return RDataFactory.createComplexVector(array, value.isComplete());
-    }
-
-    @Specialization
-    protected RLogicalVector repLen(RLogicalVector value, int length) {
-        byte[] array = new byte[length];
-        for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) {
-            array[i] = value.getDataAt(j);
-        }
-        return RDataFactory.createLogicalVector(array, value.isComplete());
-    }
-
-    @Specialization
-    protected RList repLen(RList list, int length) {
-        Object[] data = new Object[length];
-        for (int i = 0; i < length; i++) {
-            data[i] = list.getDataAt(i % list.getLength());
-        }
-        return RDataFactory.createList(data);
-    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java
index 407ce9faac3f31777368b02558b5ce92eb6a1b82..a3450d32ad3725485fdf7d5f1578e8245b392bcb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java
@@ -31,6 +31,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -52,6 +53,8 @@ public abstract class Round extends RBuiltinNode.Arg2 {
 
     @Child private RoundArithmetic roundOp = new RoundArithmetic();
 
+    private final ConditionProfile zeroDigitProfile = ConditionProfile.createBinaryProfile();
+
     private final NACheck check = NACheck.create();
 
     @Override
@@ -83,6 +86,13 @@ public abstract class Round extends RBuiltinNode.Arg2 {
         return check.check(x) ? RRuntime.DOUBLE_NA : x;
     }
 
+    @Specialization
+    protected double roundDigits(double x, double digits) {
+        check.enable(x);
+        int digitsInt = (int) Math.round(digits);
+        return check.check(x) ? RRuntime.DOUBLE_NA : zeroDigitProfile.profile(digitsInt == 0) ? roundOp.op(x) : roundOp.opd(x, digitsInt);
+    }
+
     @Specialization
     protected RDoubleVector round(RAbstractLogicalVector x, @SuppressWarnings("unused") double digits) {
         double[] data = new double[x.getLength()];
@@ -105,43 +115,18 @@ public abstract class Round extends RBuiltinNode.Arg2 {
         return RDataFactory.createDoubleVector(data, check.neverSeenNA());
     }
 
-    @Specialization(guards = "isZero(digits)")
-    protected double round(double x, @SuppressWarnings("unused") double digits) {
-        check.enable(x);
-        return check.check(x) ? RRuntime.DOUBLE_NA : roundOp.op(x);
-    }
-
     protected double roundDigits(double x, int digits) {
-        check.enable(x);
-        return check.check(x) ? RRuntime.DOUBLE_NA : roundOp.opd(x, digits);
-    }
-
-    @Specialization(guards = "!isZero(digits)")
-    protected double roundDigits(double x, double digits) {
-        return roundDigits(x, (int) Math.round(digits));
+        return check.check(x) ? RRuntime.DOUBLE_NA : zeroDigitProfile.profile(digits == 0) ? roundOp.op(x) : roundOp.opd(x, digits);
     }
 
-    @Specialization(guards = "isZero(digits)")
+    @Specialization
     protected RDoubleVector round(RAbstractDoubleVector x, double digits) {
         double[] result = new double[x.getLength()];
         check.enable(x);
+        int digitsInt = (int) Math.round(digits);
         for (int i = 0; i < x.getLength(); i++) {
             double value = x.getDataAt(i);
-            result[i] = check.check(value) ? RRuntime.DOUBLE_NA : round(value, digits);
-        }
-        RDoubleVector ret = RDataFactory.createDoubleVector(result, check.neverSeenNA());
-        ret.copyAttributesFrom(x);
-        return ret;
-    }
-
-    @Specialization(guards = "!isZero(dDigits)")
-    protected RDoubleVector roundDigits(RAbstractDoubleVector x, double dDigits) {
-        double[] result = new double[x.getLength()];
-        int digits = (int) Math.round(dDigits);
-        check.enable(x);
-        for (int i = 0; i < x.getLength(); i++) {
-            double value = x.getDataAt(i);
-            result[i] = check.check(value) ? RRuntime.DOUBLE_NA : roundDigits(value, digits);
+            result[i] = check.check(value) ? RRuntime.DOUBLE_NA : zeroDigitProfile.profile(digitsInt == 0) ? roundOp.op(value) : roundOp.opd(value, digitsInt);
         }
         RDoubleVector ret = RDataFactory.createDoubleVector(result, check.neverSeenNA());
         ret.copyAttributesFrom(x);
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 c760f844bb6b9edefe7a99821f79213d08e2009f..3a288c89a58e532a5082356475c88742234dad6e 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
@@ -27,24 +27,23 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import java.util.Arrays;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.base.SplitNodeGen.GetSplitNamesNodeGen;
 import com.oracle.truffle.r.nodes.helpers.RFactorNodes;
-import com.oracle.truffle.r.runtime.Utils;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
-import com.oracle.truffle.r.runtime.data.RRawVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-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.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.VectorReadAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
  * The {@code split} internal. Internal version of 'split' is invoked from 'split.default' function
@@ -60,11 +59,7 @@ import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
 public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Child private RFactorNodes.GetLevels getLevelNode = new RFactorNodes.GetLevels();
-    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
-
-    @SuppressWarnings("unused") private final ConditionProfile noStringLevels = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile namesProfile = ConditionProfile.createBinaryProfile();
-    @Child private VectorReadAccess.Int factorAccess = VectorReadAccess.Int.create();
+    @Child private GetSplitNames getSplitNames = GetSplitNamesNodeGen.create();
 
     private static final int INITIAL_SIZE = 5;
     private static final int SCALE_FACTOR = 2;
@@ -73,238 +68,234 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         Casts.noCasts(Split.class);
     }
 
-    @Specialization
-    protected RList split(RAbstractListVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.getDataStore(f);
-        RStringVector names = getLevelNode.execute(f);
-        final int nLevels = getNLevels(names);
-
-        // initialise result arrays
-        Object[][] collectResults = new Object[nLevels][];
-        int[] collectResultSize = new int[nLevels];
-        for (int i = 0; i < collectResults.length; i++) {
-            collectResults[i] = new Object[INITIAL_SIZE];
-        }
-
-        // perform split
-        int factorLen = f.getLength();
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
-                                                                         // int vector
-            Object[] collect = collectResults[resultIndex];
-            if (collect.length == collectResultSize[resultIndex]) {
-                collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
-                collect = collectResults[resultIndex];
+    @Specialization(limit = "4", guards = {"xAccess.supports(x)", "fAccess.supports(f)"})
+    protected RList split(RAbstractVector x, RAbstractIntVector f,
+                    @Cached("x.access()") VectorAccess xAccess,
+                    @Cached("f.access()") VectorAccess fAccess) {
+        try (SequentialIterator xIter = xAccess.access(x); SequentialIterator fIter = fAccess.access(f)) {
+            RStringVector names = getLevelNode.execute(f);
+            int nLevels = getNLevels(names);
+            int[] collectResultSize = new int[nLevels];
+            Object[] results = new Object[nLevels];
+
+            switch (xAccess.getType()) {
+                case Character: {
+                    // Initialize result arrays
+                    String[][] collectResults = new String[nLevels][INITIAL_SIZE];
+
+                    // perform split
+                    while (xAccess.next(xIter)) {
+                        fAccess.nextWithWrap(fIter);
+                        int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int
+                                                                     // vector
+                        String[] collect = collectResults[resultIndex];
+                        if (collect.length == collectResultSize[resultIndex]) {
+                            collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
+                        }
+                        collect[collectResultSize[resultIndex]++] = xAccess.getString(xIter);
+                    }
+
+                    RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, nLevels, collectResultSize);
+                    for (int i = 0; i < nLevels; i++) {
+                        results[i] = RDataFactory.createStringVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), x.isComplete(),
+                                        (resultNames != null) ? resultNames[i] : null);
+                    }
+                    break;
+                }
+                case Complex: {
+                    // Initialize result arrays
+                    double[][] collectResults = new double[nLevels][INITIAL_SIZE * 2];
+
+                    // perform split
+                    while (xAccess.next(xIter)) {
+                        fAccess.nextWithWrap(fIter);
+                        int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int
+                                                                     // vector
+                        double[] collect = collectResults[resultIndex];
+                        if (collect.length == collectResultSize[resultIndex] * 2) {
+                            collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
+                        }
+                        collect[collectResultSize[resultIndex] * 2] = xAccess.getComplexR(xIter);
+                        collect[collectResultSize[resultIndex] * 2 + 1] = xAccess.getComplexI(xIter);
+                        collectResultSize[resultIndex]++;
+                    }
+
+                    RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, nLevels, collectResultSize);
+                    for (int i = 0; i < nLevels; i++) {
+                        results[i] = RDataFactory.createComplexVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i] * 2), x.isComplete(),
+                                        (resultNames != null) ? resultNames[i] : null);
+                    }
+                    break;
+                }
+                case Double: {
+                    // Initialize result arrays
+                    double[][] collectResults = new double[nLevels][INITIAL_SIZE];
+
+                    // perform split
+                    while (xAccess.next(xIter)) {
+                        fAccess.nextWithWrap(fIter);
+                        int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int
+                                                                     // vector
+                        double[] collect = collectResults[resultIndex];
+                        if (collect.length == collectResultSize[resultIndex]) {
+                            collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
+                        }
+                        collect[collectResultSize[resultIndex]++] = xAccess.getDouble(xIter);
+                    }
+
+                    RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, nLevels, collectResultSize);
+                    for (int i = 0; i < nLevels; i++) {
+                        results[i] = RDataFactory.createDoubleVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), x.isComplete(),
+                                        (resultNames != null) ? resultNames[i] : null);
+                    }
+                    break;
+                }
+                case Integer: {
+                    // Initialize result arrays
+                    int[][] collectResults = new int[nLevels][INITIAL_SIZE];
+
+                    // perform split
+                    while (xAccess.next(xIter)) {
+                        fAccess.nextWithWrap(fIter);
+                        int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int
+                                                                     // vector
+                        int[] collect = collectResults[resultIndex];
+                        if (collect.length == collectResultSize[resultIndex]) {
+                            collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
+                        }
+                        collect[collectResultSize[resultIndex]++] = xAccess.getInt(xIter);
+                    }
+
+                    RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, 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);
+                    }
+                    break;
+                }
+                case List: {
+                    // Initialize result arrays
+                    Object[][] collectResults = new Object[nLevels][INITIAL_SIZE];
+
+                    // perform split
+                    while (xAccess.next(xIter)) {
+                        fAccess.nextWithWrap(fIter);
+                        int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int
+                                                                     // vector
+                        Object[] collect = collectResults[resultIndex];
+                        if (collect.length == collectResultSize[resultIndex]) {
+                            collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
+                        }
+                        collect[collectResultSize[resultIndex]++] = xAccess.getListElement(xIter);
+                    }
+
+                    RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, 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);
+                    }
+                    break;
+                }
+                case Logical: {
+                    // Initialize result arrays
+                    byte[][] collectResults = new byte[nLevels][INITIAL_SIZE];
+
+                    // perform split
+                    while (xAccess.next(xIter)) {
+                        fAccess.nextWithWrap(fIter);
+                        int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int
+                                                                     // vector
+                        byte[] collect = collectResults[resultIndex];
+                        if (collect.length == collectResultSize[resultIndex]) {
+                            collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
+                        }
+                        collect[collectResultSize[resultIndex]++] = xAccess.getLogical(xIter);
+                    }
+
+                    RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, 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);
+                    }
+                    break;
+                }
+                case Raw: {
+                    // Initialize result arrays
+                    byte[][] collectResults = new byte[nLevels][INITIAL_SIZE];
+
+                    // perform split
+                    while (xAccess.next(xIter)) {
+                        fAccess.nextWithWrap(fIter);
+                        int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int
+                                                                     // vector
+                        byte[] collect = collectResults[resultIndex];
+                        if (collect.length == collectResultSize[resultIndex]) {
+                            collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
+                        }
+                        collect[collectResultSize[resultIndex]++] = xAccess.getRaw(xIter);
+                    }
+
+                    RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, 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);
+                    }
+                    break;
+                }
+                default:
+                    throw error(Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, xAccess.getType().getName(), "split");
             }
-            collect[collectResultSize[resultIndex]++] = x.getDataAt(i);
-        }
-
-        Object[] results = new Object[nLevels];
-        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);
-        }
-        return RDataFactory.createList(results, names);
-    }
-
-    @Specialization
-    protected RList split(RAbstractIntVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.getDataStore(f);
-        RStringVector names = getLevelNode.execute(f);
-        final int nLevels = getNLevels(names);
-
-        // initialise result arrays
-        int[][] collectResults = new int[nLevels][];
-        int[] collectResultSize = new int[nLevels];
-        for (int i = 0; i < collectResults.length; i++) {
-            collectResults[i] = new int[INITIAL_SIZE];
-        }
-
-        // perform split
-        int factorLen = f.getLength();
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
-                                                                         // int vector
-            int[] collect = collectResults[resultIndex];
-            if (collect.length == collectResultSize[resultIndex]) {
-                collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
-                collect = collectResults[resultIndex];
-            }
-            collect[collectResultSize[resultIndex]++] = x.getDataAt(i);
-        }
-
-        Object[] results = new Object[nLevels];
-        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);
-        }
-        return RDataFactory.createList(results, names);
-    }
-
-    @Specialization
-    protected RList split(RAbstractDoubleVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.getDataStore(f);
-        RStringVector names = getLevelNode.execute(f);
-        final int nLevels = getNLevels(names);
-
-        // initialise result arrays
-        double[][] collectResults = new double[nLevels][];
-        int[] collectResultSize = new int[nLevels];
-        for (int i = 0; i < collectResults.length; i++) {
-            collectResults[i] = new double[INITIAL_SIZE];
-        }
-
-        // perform split
-        int factorLen = f.getLength();
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
-                                                                         // int vector
-            double[] collect = collectResults[resultIndex];
-            if (collect.length == collectResultSize[resultIndex]) {
-                collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
-                collect = collectResults[resultIndex];
-            }
-            collect[collectResultSize[resultIndex]++] = x.getDataAt(i);
-        }
-
-        Object[] results = new Object[nLevels];
-        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);
+            return RDataFactory.createList(results, names);
         }
-        return RDataFactory.createList(results, names);
     }
 
-    @Specialization
-    protected RList split(RAbstractStringVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.getDataStore(f);
-        RStringVector names = getLevelNode.execute(f);
-        final int nLevels = getNLevels(names);
-
-        // initialise result arrays
-        String[][] collectResults = new String[nLevels][];
-        int[] collectResultSize = new int[nLevels];
-        for (int i = 0; i < collectResults.length; i++) {
-            collectResults[i] = new String[INITIAL_SIZE];
-        }
-
-        // perform split
-        int factorLen = f.getLength();
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
-                                                                         // int vector
-            String[] collect = collectResults[resultIndex];
-            if (collect.length == collectResultSize[resultIndex]) {
-                collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
-                collect = collectResults[resultIndex];
-            }
-            collect[collectResultSize[resultIndex]++] = x.getDataAt(i);
-        }
-
-        Object[] results = new Object[nLevels];
-        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);
-        }
-        return RDataFactory.createList(results, names);
+    @Specialization(replaces = "split")
+    protected RList splitGeneric(RAbstractVector x, RAbstractIntVector f) {
+        return split(x, f, x.slowPathAccess(), f.slowPathAccess());
     }
 
-    @Specialization
-    protected RList split(RAbstractLogicalVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.getDataStore(f);
-        RStringVector names = getLevelNode.execute(f);
-        final int nLevels = getNLevels(names);
-
-        // initialise result arrays
-        byte[][] collectResults = new byte[nLevels][];
-        int[] collectResultSize = new int[nLevels];
-        for (int i = 0; i < collectResults.length; i++) {
-            collectResults[i] = new byte[INITIAL_SIZE];
-        }
-
-        // perform split
-        int factorLen = f.getLength();
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
-                                                                         // int vector
-            byte[] collect = collectResults[resultIndex];
-            if (collect.length == collectResultSize[resultIndex]) {
-                collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
-                collect = collectResults[resultIndex];
+    protected abstract static class GetSplitNames extends RBaseNode {
+
+        private final ConditionProfile namesProfile = ConditionProfile.createBinaryProfile();
+        @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
+
+        private RStringVector[] getNames(RAbstractVector x, VectorAccess fAccess, SequentialIterator fIter, int nLevels, int[] collectResultSize) {
+            RStringVector xNames = getNamesNode.getNames(x);
+            if (namesProfile.profile(xNames != null)) {
+                String[][] namesArr = new String[nLevels][];
+                int[] resultNamesIdxs = new int[nLevels];
+                for (int i = 0; i < nLevels; i++) {
+                    namesArr[i] = new String[collectResultSize[i]];
+                }
+                execute(fAccess, fIter, xNames, namesArr, resultNamesIdxs);
+                RStringVector[] resultNames = new RStringVector[nLevels];
+                for (int i = 0; i < nLevels; i++) {
+                    resultNames[i] = RDataFactory.createStringVector(namesArr[i], xNames.isComplete());
+                }
+                return resultNames;
             }
-            collect[collectResultSize[resultIndex]++] = x.getDataAt(i);
+            return null;
         }
 
-        Object[] results = new Object[nLevels];
-        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);
-        }
-        return RDataFactory.createList(results, names);
-    }
-
-    @Specialization
-    protected RList split(RRawVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.getDataStore(f);
-        RStringVector names = getLevelNode.execute(f);
-        final int nLevels = getNLevels(names);
-
-        // initialise result arrays
-        byte[][] collectResults = new byte[nLevels][];
-        int[] collectResultSize = new int[nLevels];
-        for (int i = 0; i < collectResults.length; i++) {
-            collectResults[i] = new byte[INITIAL_SIZE];
-        }
-
-        // perform split
-        int factorLen = f.getLength();
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
-                                                                         // int vector
-            byte[] collect = collectResults[resultIndex];
-            if (collect.length == collectResultSize[resultIndex]) {
-                collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
-                collect = collectResults[resultIndex];
+        protected abstract void execute(VectorAccess fAccess, SequentialIterator fIter, RStringVector names, String[][] namesArr, int[] resultNamesIdxs);
+
+        @Specialization(guards = "namesAccess.supports(names)")
+        protected void fillNames(VectorAccess fAccess, SequentialIterator fIter, RStringVector names, String[][] namesArr, int[] resultNamesIdxs,
+                        @Cached("names.access()") VectorAccess namesAccess) {
+            try (SequentialIterator namesIter = namesAccess.access(names)) {
+                while (namesAccess.next(namesIter)) {
+                    fAccess.nextWithWrap(fIter);
+                    int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int
+                                                                 // vector
+                    namesArr[resultIndex][resultNamesIdxs[resultIndex]++] = namesAccess.getString(namesIter);
+                }
             }
-            collect[collectResultSize[resultIndex]++] = x.getRawDataAt(i);
         }
 
-        Object[] results = new Object[nLevels];
-        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);
-        }
-        return RDataFactory.createList(results, names);
-    }
-
-    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][];
-            int[] resultNamesIdxs = new int[nLevels];
-            for (int i = 0; i < nLevels; i++) {
-                namesArr[i] = new String[collectResultSize[i]];
-            }
-            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];
-            for (int i = 0; i < nLevels; i++) {
-                resultNames[i] = RDataFactory.createStringVector(namesArr[i], xNames.isComplete());
-            }
-            return resultNames;
+        @Specialization(replaces = "fillNames")
+        protected void fillNamesGeneric(VectorAccess fAccess, SequentialIterator fIter, RStringVector names, String[][] namesArr, int[] resultNamesIdxs) {
+            fillNames(fAccess, fIter, names, namesArr, resultNamesIdxs, names.slowPathAccess());
         }
-        return null;
     }
 
     private static int getNLevels(RStringVector levels) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
index b61abc3dc009fa760ff99ca77b3bcb47ffc58f11..e48d76d60b510b783cc077266c62cd66f2114f8d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
@@ -15,10 +15,6 @@ package com.oracle.truffle.r.nodes.builtin.base;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
-import java.util.function.BiFunction;
-import java.util.function.Function;
-
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -35,27 +31,18 @@ import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
 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.RDataFactory.VectorFactory;
 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.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.data.nodes.SetDataAt;
-import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorReuse;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 @RBuiltin(name = "t.default", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
@@ -72,7 +59,7 @@ public abstract class Transpose extends RBuiltinNode.Arg1 {
     @Child private SetFixedAttributeNode putDimNames = SetFixedAttributeNode.createDimNames();
     @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
     @Child private GetNamesAttributeNode getAxisNamesNode = GetNamesAttributeNode.create();
-    @Child private GetDimAttributeNode getDimNode;
+    @Child private GetDimAttributeNode getDimNode = GetDimAttributeNode.create();
     @Child private ReuseNonSharedNode reuseNonShared = ReuseNonSharedNode.create();
 
     static {
@@ -81,210 +68,157 @@ public abstract class Transpose extends RBuiltinNode.Arg1 {
 
     public abstract Object execute(RAbstractVector o);
 
-    @FunctionalInterface
-    private interface WriteArray<T extends RAbstractVector, A> {
-        void apply(A array, T vector, int i, int j);
-    }
-
-    @FunctionalInterface
-    private interface Swap {
-        /** Swap element at (i, j) with element at (j, i). */
-        void swap(int i, int j);
+    protected boolean isSquare(RAbstractVector vector) {
+        int[] dims = getDimNode.getDimensions(vector);
+        if (GetDimAttributeNode.isMatrix(dims)) {
+            assert dims.length >= 2;
+            return dims[0] == dims[1];
+        }
+        return false;
     }
 
-    protected <T extends RAbstractVector, A> RVector<?> transposeInternal(T vector, Function<Integer, A> createArray, WriteArray<T, A> writeArray, BiFunction<A, Boolean, RVector<?>> createResult) {
-        int length = lengthProfile.profile(vector.getLength());
-        int firstDim;
-        int secondDim;
-        assert vector.isMatrix();
-        int[] dims = getDimensions(vector);
-        firstDim = dims[0];
-        secondDim = dims[1];
-        RBaseNode.reportWork(this, length);
-
-        A array = createArray.apply(length);
-        int j = 0;
-        loopProfile.profileCounted(length);
-        for (int i = 0; loopProfile.inject(i < length); i++, j += firstDim) {
-            if (j > (length - 1)) {
-                j -= (length - 1);
-            }
-            writeArray.apply(array, vector, i, j);
-        }
-        RVector<?> r = createResult.apply(array, vector.isComplete());
-        // copy attributes
-        copyRegAttributes.execute(vector, r);
-        // set new dimensions
-        int[] newDim = new int[]{secondDim, firstDim};
-        putNewDimensions(vector, r, newDim);
-        return r;
+    protected boolean isMatrix(RAbstractVector vector) {
+        return GetDimAttributeNode.isMatrix(getDimNode.getDimensions(vector));
     }
 
-    protected RVector<?> transposeSquareMatrixInPlace(RVector<?> vector, Object store, VectorReadAccess readAccess, SetDataAt setter, Swap swap) {
+    private void transposeSquareMatrixInPlace(RAbstractVector vector, RandomIterator iter, VectorAccess access) {
         int length = lengthProfile.profile(vector.getLength());
-        assert vector.isMatrix();
-        int[] dims = getDimensions(vector);
+        assert isMatrix(vector);
+        int[] dims = getDimNode.getDimensions(vector);
         assert dims.length == 2;
         assert dims[0] == dims[1];
         int dim = dims[0];
         RBaseNode.reportWork(this, length);
 
+        RType type = access.getType();
         loopProfile.profileCounted(length);
         for (int i = 0; loopProfile.inject(i < dim); i++) {
             for (int j = 0; j < i; j++) {
                 int swapi = i * dim + j;
                 int swapj = j * dim + i;
-                if (swap != null) {
-                    swap.swap(swapi, swapj);
-                } else {
-                    Object tmp = readAccess.getDataAtAsObject(vector, store, swapi);
-                    Object jVal = readAccess.getDataAtAsObject(vector, store, swapj);
-                    setter.setDataAtAsObject(vector, store, swapi, jVal);
-                    setter.setDataAtAsObject(vector, store, swapj, tmp);
+                switch (type) {
+                    case Character: {
+                        String tmp = access.getString(iter, swapi);
+                        access.setString(iter, swapi, access.getString(iter, swapj));
+                        access.setString(iter, swapj, tmp);
+                        break;
+                    }
+                    case Complex: {
+                        double tmpReal = access.getComplexR(iter, swapi);
+                        double tmpImaginary = access.getComplexI(iter, swapi);
+                        access.setComplex(iter, swapi, access.getComplexR(iter, swapj), access.getComplexI(iter, swapj));
+                        access.setComplex(iter, swapj, tmpReal, tmpImaginary);
+                        break;
+                    }
+                    case Double: {
+                        double tmp = access.getDouble(iter, swapi);
+                        access.setDouble(iter, swapi, access.getDouble(iter, swapj));
+                        access.setDouble(iter, swapj, tmp);
+                        break;
+                    }
+                    case Integer: {
+                        int tmp = access.getInt(iter, swapi);
+                        access.setInt(iter, swapi, access.getInt(iter, swapj));
+                        access.setInt(iter, swapj, tmp);
+                        break;
+                    }
+                    case List: {
+                        Object tmp = access.getListElement(iter, swapi);
+                        access.setListElement(iter, swapi, access.getListElement(iter, swapj));
+                        access.setListElement(iter, swapj, tmp);
+                        break;
+                    }
+                    case Logical: {
+                        byte tmp = access.getLogical(iter, swapi);
+                        access.setLogical(iter, swapi, access.getLogical(iter, swapj));
+                        access.setLogical(iter, swapj, tmp);
+                        break;
+                    }
+                    case Raw: {
+                        byte tmp = access.getRaw(iter, swapi);
+                        access.setRaw(iter, swapi, access.getRaw(iter, swapj));
+                        access.setRaw(iter, swapj, tmp);
+                        break;
+                    }
+                    default:
+                        throw RInternalError.shouldNotReachHere();
                 }
             }
         }
         // don't need to set new dimensions; it is a square matrix
         putNewDimNames(vector, vector);
-        return vector;
     }
 
-    private int[] getDimensions(RAbstractVector vector) {
-        assert vector.isMatrix();
-        if (getDimNode == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            getDimNode = insert(GetDimAttributeNode.create());
+    @Specialization(guards = {"isSquare(x)", "!isRExpression(x)", "xReuse.supports(x)"})
+    protected RAbstractVector transposeSquare(RAbstractVector x,
+                    @Cached("createNonShared(x)") VectorReuse xReuse) {
+        RAbstractVector result = xReuse.getResult(x);
+        VectorAccess resultAccess = xReuse.access(result);
+        try (RandomIterator resultIter = resultAccess.randomAccess(result)) {
+            transposeSquareMatrixInPlace(result, resultIter, resultAccess);
         }
-        return getDimNode.getDimensions(vector);
-    }
-
-    protected boolean isSquare(RAbstractVector vector) {
-        if (vector.isMatrix()) {
-            int[] dims = getDimensions(vector);
-            assert dims.length >= 2;
-            return dims[0] == dims[1];
+        return result;
+    }
+
+    @Specialization(replaces = "transposeSquare", guards = {"isSquare(x)", "!isRExpression(x)"})
+    protected RAbstractVector transposeSquareGeneric(RAbstractVector x,
+                    @Cached("createNonSharedGeneric()") VectorReuse xReuse) {
+        return transposeSquare(x, xReuse);
+    }
+
+    @Specialization(guards = {"isMatrix(x)", "!isSquare(x)", "!isRExpression(x)", "xAccess.supports(x)"})
+    protected RAbstractVector transpose(RAbstractVector x,
+                    @Cached("create()") VectorFactory factory,
+                    @Cached("x.access()") VectorAccess xAccess,
+                    @Cached("createNew(xAccess.getType())") VectorAccess resultAccess) {
+        try (RandomIterator xIter = xAccess.randomAccess(x)) {
+            RAbstractVector result = factory.createVector(xAccess.getType(), xAccess.getLength(xIter), false);
+            try (RandomIterator resultIter = resultAccess.randomAccess(result)) {
+                int length = lengthProfile.profile(xAccess.getLength(xIter));
+                assert isMatrix(x);
+                int[] dims = getDimNode.getDimensions(x);
+                int firstDim = dims[0];
+                int secondDim = dims[1];
+                RBaseNode.reportWork(this, length);
+
+                int j = 0;
+                loopProfile.profileCounted(length);
+                for (int i = 0; loopProfile.inject(i < length); i++, j += firstDim) {
+                    if (j > (length - 1)) {
+                        j -= (length - 1);
+                    }
+                    resultAccess.setFromSameType(resultIter, i, xAccess, xIter, j);
+                }
+                // copy attributes
+                copyRegAttributes.execute(x, result);
+                // set new dimensions
+                putNewDimensions(x, result, new int[]{secondDim, firstDim});
+            }
+            result.setComplete(x.isComplete());
+            return result;
         }
-        return false;
-    }
-
-    @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractIntVector x,
-                    @Cached("create()") VectorReadAccess.Int readAccess,
-                    @Cached("create()") SetDataAt.Int setter) {
-        RIntVector reused = (RIntVector) reuseNonShared.execute(x).materialize();
-        Object reusedStore = readAccess.getDataStore(reused);
-        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
-    }
-
-    @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractLogicalVector x,
-                    @Cached("create()") VectorReadAccess.Logical readAccess,
-                    @Cached("create()") SetDataAt.Logical setter) {
-        RLogicalVector reused = (RLogicalVector) reuseNonShared.execute(x).materialize();
-        Object reusedStore = readAccess.getDataStore(reused);
-        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
-    }
-
-    @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractDoubleVector x,
-                    @Cached("create()") VectorReadAccess.Double readAccess,
-                    @Cached("create()") SetDataAt.Double setter) {
-        RDoubleVector reused = (RDoubleVector) reuseNonShared.execute(x).materialize();
-        Object reusedStore = readAccess.getDataStore(reused);
-        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
-    }
-
-    @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractComplexVector x,
-                    @Cached("create()") VectorReadAccess.Complex readAccess,
-                    @Cached("create()") SetDataAt.Complex setter) {
-        RComplexVector reused = (RComplexVector) reuseNonShared.execute(x).materialize();
-        Object reusedStore = readAccess.getDataStore(reused);
-        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
-    }
-
-    @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractStringVector x,
-                    @Cached("create()") VectorReadAccess.String readAccess,
-                    @Cached("create()") SetDataAt.String setter) {
-        RStringVector reused = (RStringVector) reuseNonShared.execute(x).materialize();
-        Object reusedStore = readAccess.getDataStore(reused);
-        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
-    }
-
-    @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractListVector x) {
-        RList reused = (RList) reuseNonShared.execute(x).materialize();
-        Object[] store = reused.getDataWithoutCopying();
-        return transposeSquareMatrixInPlace(reused, store, null, null, (i, j) -> {
-            Object tmp = store[i];
-            store[i] = store[j];
-            store[j] = tmp;
-        });
-    }
-
-    @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractRawVector x,
-                    @Cached("create()") VectorReadAccess.Raw readAccess,
-                    @Cached("create()") SetDataAt.Raw setter) {
-        RRawVector reused = (RRawVector) reuseNonShared.execute(x).materialize();
-        Object reusedStore = readAccess.getDataStore(reused);
-        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
-    }
-
-    @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"})
-    protected RVector<?> transpose(RAbstractIntVector x) {
-        return transposeInternal(x, l -> new int[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createIntVector);
-    }
-
-    @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"})
-    protected RVector<?> transpose(RAbstractLogicalVector x) {
-        return transposeInternal(x, l -> new byte[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createLogicalVector);
-    }
-
-    @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"})
-    protected RVector<?> transpose(RAbstractDoubleVector x) {
-        return transposeInternal(x, l -> new double[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createDoubleVector);
-    }
-
-    @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"})
-    protected RVector<?> transpose(RAbstractComplexVector x) {
-        return transposeInternal(x, l -> new double[l * 2], (a, v, i, j) -> {
-            RComplex d = v.getDataAt(j);
-            a[i * 2] = d.getRealPart();
-            a[i * 2 + 1] = d.getImaginaryPart();
-        }, RDataFactory::createComplexVector);
-    }
-
-    @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"})
-    protected RVector<?> transpose(RAbstractStringVector x) {
-        return transposeInternal(x, l -> new String[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createStringVector);
-    }
-
-    @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"})
-    protected RVector<?> transpose(RAbstractListVector x) {
-        return transposeInternal(x, l -> new Object[l], (a, v, i, j) -> a[i] = v.getDataAt(j), (a, c) -> RDataFactory.createList(a));
     }
 
-    @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"})
-    protected RVector<?> transpose(RAbstractRawVector x) {
-        return transposeInternal(x, l -> new byte[l], (a, v, i, j) -> a[i] = v.getRawDataAt(j), (a, c) -> RDataFactory.createRawVector(a));
+    @Specialization(replaces = "transpose", guards = {"isMatrix(x)", "!isSquare(x)", "!isRExpression(x)"})
+    protected RAbstractVector transposeGeneric(RAbstractVector x,
+                    @Cached("create()") VectorFactory factory) {
+        return transpose(x, factory, x.slowPathAccess(), VectorAccess.createSlowPathNew(x.getRType()));
     }
 
-    @Specialization(guards = "!x.isMatrix()")
-    protected RVector<?> transpose(RAbstractVector x) {
+    @Specialization(guards = {"!isMatrix(x)", "!isRExpression(x)"})
+    protected RVector<?> transposeNonMatrix(RAbstractVector x) {
         RVector<?> reused = reuseNonShared.execute(x);
         putNewDimensions(reused, reused, new int[]{1, x.getLength()});
         return reused;
 
     }
 
-    private void putNewDimensions(RAbstractVector source, RVector<?> dest, int[] newDim) {
+    private void putNewDimensions(RAbstractVector source, RAbstractVector dest, int[] newDim) {
         putDimensions.execute(initAttributes.execute(dest), RDataFactory.createIntVector(newDim, RDataFactory.COMPLETE_VECTOR));
         putNewDimNames(source, dest);
     }
 
-    private void putNewDimNames(RAbstractVector source, RVector<?> dest) {
+    private void putNewDimNames(RAbstractVector source, RAbstractVector dest) {
         // set new dim names
         RList dimNames = getDimNamesNode.getDimNames(source);
         if (dimNames != null) {
@@ -292,8 +226,7 @@ public abstract class Transpose extends RBuiltinNode.Arg1 {
             assert dimNames.getLength() == 2;
             RStringVector axisNames = getAxisNamesNode.getNames(dimNames);
             RStringVector transAxisNames = axisNames == null ? null : RDataFactory.createStringVector(new String[]{axisNames.getDataAt(1), axisNames.getDataAt(0)}, true);
-            RList newDimNames = RDataFactory.createList(new Object[]{dimNames.getDataAt(1),
-                            dimNames.getDataAt(0)}, transAxisNames);
+            RList newDimNames = RDataFactory.createList(new Object[]{dimNames.getDataAt(1), dimNames.getDataAt(0)}, transAxisNames);
             putDimNames.execute(dest.getAttributes(), newDimNames);
         }
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
index 5efb1486a32c28a3cedb2e7530ad7eefd352298b..b53035ae7c895902257bc7f7c7ac685858b4ab35 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
@@ -62,9 +62,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "attributes<-", kind = PRIMITIVE, parameterNames = {"obj", "value"}, behavior = PURE)
 public abstract class UpdateAttributes extends RBuiltinNode.Arg2 {
-    private final ConditionProfile numAttributesProfile = ConditionProfile.createBinaryProfile();
-    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
     @Child private UpdateNames updateNames;
     @Child private UpdateDimNames updateDimNames;
     @Child private CastIntegerNode castInteger;
@@ -128,16 +127,17 @@ public abstract class UpdateAttributes extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RAbstractContainer updateAttributes(RAbstractContainer container, RList list,
-                    @Cached("create()") GetNonSharedNode nonShared) {
-        Object listNamesObject = getNamesNode.getNames(list);
-        if (listNamesObject == null || listNamesObject == RNull.instance) {
-            throw error(RError.Message.ATTRIBUTES_NAMED);
-        }
-        RStringVector listNames = (RStringVector) listNamesObject;
+                    @Cached("create()") GetNonSharedNode nonShared,
+                    @Cached("createBinaryProfile()") ConditionProfile emptyListProfile) {
         RAbstractContainer result = ((RAbstractContainer) nonShared.execute(container)).materialize();
-        if (numAttributesProfile.profile(list.getLength() == 0)) {
+        if (emptyListProfile.profile(list.getLength() == 0)) {
             result.resetAllAttributes(true);
         } else {
+            Object listNamesObject = getNamesNode.getNames(list);
+            if (listNamesObject == null || listNamesObject == RNull.instance) {
+                throw error(RError.Message.ATTRIBUTES_NAMED);
+            }
+            RStringVector listNames = (RStringVector) listNamesObject;
             result.resetAllAttributes(false);
             // error checking is a little weird - seems easier to separate it than weave it into the
             // update loop
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java
index 48f97b147f36682ec368ac5e61fe3914693c4765..9d9aeef9d87eeb09cd5963d5bab80650d8c80fd4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java
@@ -32,6 +32,7 @@ import com.oracle.truffle.r.nodes.builtin.base.MatrixNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
 import com.oracle.truffle.r.nodes.unary.FirstIntNode;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.REmpty;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -64,6 +65,9 @@ public abstract class MatrixFastPath extends RFastPathNode {
         int row = rowMissing ? 1 : firstRow.executeInt(castRow.doCast(nrow));
         int col = colMissing ? 1 : firstCol.executeInt(castCol.doCast(ncol));
         Object dim = dimMissingProfile.profile(dimnames == RMissing.instance) ? RNull.instance : dimnames;
+        if (row == RRuntime.INT_NA || col == RRuntime.INT_NA) {
+            return null;
+        }
         return matrix.execute(classProfile.profile(data), row, col, false, dim, rowMissing, colMissing);
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
index fa7bd093468a50b2f7af32a0ba00d1f728d75522..97bdda9d9a8aa0ef9ce10ea25e39e47dfed0f6b1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
@@ -324,43 +324,43 @@ public class CallAndExternalFunctions {
                 case "qnorm":
                     return StatsFunctionsNodes.Function3_2Node.create(new Qnorm());
                 case "rnorm":
-                    return RandFunction2Node.createDouble(new Rnorm());
+                    return RandFunction2Node.createDouble(Rnorm::new);
                 case "runif":
-                    return RandFunction2Node.createDouble(new Runif());
+                    return RandFunction2Node.createDouble(Runif::new);
                 case "rbeta":
-                    return RandFunction2Node.createDouble(new RBeta());
+                    return RandFunction2Node.createDouble(RBeta::new);
                 case "rgamma":
-                    return RandFunction2Node.createDouble(new RGamma());
+                    return RandFunction2Node.createDouble(RGamma::new);
                 case "rcauchy":
-                    return RandFunction2Node.createDouble(new RCauchy());
+                    return RandFunction2Node.createDouble(RCauchy::new);
                 case "rf":
-                    return RandFunction2Node.createDouble(new Rf());
+                    return RandFunction2Node.createDouble(Rf::new);
                 case "rlogis":
-                    return RandFunction2Node.createDouble(new RLogis());
+                    return RandFunction2Node.createDouble(RLogis::new);
                 case "rweibull":
-                    return RandFunction2Node.createDouble(new RWeibull());
+                    return RandFunction2Node.createDouble(RWeibull::new);
                 case "rnchisq":
-                    return RandFunction2Node.createDouble(new RNchisq());
+                    return RandFunction2Node.createDouble(RNchisq::new);
                 case "rnbinom_mu":
-                    return RandFunction2Node.createDouble(new RNBinomMu());
+                    return RandFunction2Node.createDouble(RNBinomMu::new);
                 case "rwilcox":
-                    return RandFunction2Node.createInt(new RWilcox());
+                    return RandFunction2Node.createInt(RWilcox::new);
                 case "rchisq":
-                    return RandFunction1Node.createDouble(new RChisq());
+                    return RandFunction1Node.createDouble(RChisq::new);
                 case "rexp":
-                    return RandFunction1Node.createDouble(new RExp());
+                    return RandFunction1Node.createDouble(RExp::new);
                 case "rgeom":
-                    return RandFunction1Node.createInt(new RGeom());
+                    return RandFunction1Node.createInt(RGeom::new);
                 case "rpois":
-                    return RandFunction1Node.createInt(new RPois());
+                    return RandFunction1Node.createInt(RPois::new);
                 case "rnbinom":
-                    return RandFunction2Node.createInt(new RNBinomFunc());
+                    return RandFunction2Node.createInt(RNBinomFunc::new);
                 case "rt":
-                    return RandFunction1Node.createDouble(new Rt());
+                    return RandFunction1Node.createDouble(Rt::new);
                 case "rsignrank":
-                    return RandFunction1Node.createInt(new RSignrank());
+                    return RandFunction1Node.createInt(RSignrank::new);
                 case "rhyper":
-                    return RandFunction3Node.createInt(new RHyper());
+                    return RandFunction3Node.createInt(RHyper::new);
                 case "phyper":
                     return StatsFunctionsNodes.Function4_2Node.create(new PHyper());
                 case "dhyper":
@@ -400,7 +400,7 @@ public class CallAndExternalFunctions {
                 case "dweibull":
                     return StatsFunctionsNodes.Function3_1Node.create(new DWeibull());
                 case "rbinom":
-                    return RandFunction2Node.createInt(new Rbinom());
+                    return RandFunction2Node.createInt(Rbinom::new);
                 case "pbinom":
                     return StatsFunctionsNodes.Function3_2Node.create(new Pbinom());
                 case "pbeta":
@@ -458,7 +458,7 @@ public class CallAndExternalFunctions {
                 case "dt":
                     return StatsFunctionsNodes.Function2_1Node.create(new Dt());
                 case "rlnorm":
-                    return RandFunction2Node.createDouble(new LogNormal.RLNorm());
+                    return RandFunction2Node.createDouble(LogNormal.RLNorm::new);
                 case "dlnorm":
                     return StatsFunctionsNodes.Function3_1Node.create(new DLNorm());
                 case "qlnorm":
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AnyVectorToStringVectorWriter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AnyVectorToStringVectorWriter.java
index 5282e1d86e05f9d9fda1a0aec8f1c9a7bba188e0..c3c58869de499c385be2b8630a20ac6d3407cec4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AnyVectorToStringVectorWriter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AnyVectorToStringVectorWriter.java
@@ -71,14 +71,14 @@ public class AnyVectorToStringVectorWriter extends Writer implements PrettyWrite
     }
 
     @Override
-    public void beginElement(@SuppressWarnings("hiding") RAbstractVector vector, int index, FormatMetrics fm) {
+    public void beginElement(int index, FormatMetrics fm) {
         if (levelCounter == 1) {
             sb = new StringBuilder();
         }
     }
 
     @Override
-    public void endElement(@SuppressWarnings("hiding") RAbstractVector vector, int index, FormatMetrics fm) {
+    public void endElement(int index, FormatMetrics fm) {
         if (levelCounter == 1) {
             String s = sb.toString().trim();
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
index 9acd7e244cc288467929467e5bbe82e73deb2c77..99957bfd751f46e4ab8d04a00db0119cc4f86153 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
@@ -23,6 +23,8 @@ import com.oracle.truffle.r.nodes.builtin.base.printer.DoubleVectorPrinter.Scien
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 
 //Transcribed from GnuR, src/main/printutils.c
 
@@ -52,13 +54,13 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe
 
         @Override
         protected FormatMetrics formatVector(int offs, int len) {
-            return formatComplexVector(vector, offs, len, 0, printCtx.parameters());
+            return formatComplexVector(iterator, access, offs, len, 0, printCtx.parameters());
         }
 
         @Override
         protected void printElement(int i, FormatMetrics fm) throws IOException {
             ComplexVectorMetrics cfm = (ComplexVectorMetrics) fm;
-            String v = encodeComplex(vector.getDataAt(i), cfm, '.', printCtx.parameters());
+            String v = encodeComplex(access.getComplex(iterator, i), cfm, '.', printCtx.parameters());
             out.print(v);
         }
 
@@ -74,69 +76,47 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe
     }
 
     @TruffleBoundary
-    static ComplexVectorMetrics formatComplexVector(RAbstractComplexVector x, int offs, int n, int nsmall, PrintParameters pp) {
-        return formatComplexVector(x, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth());
+    static ComplexVectorMetrics formatComplexVector(RandomIterator iter, VectorAccess access, int offs, int n, int nsmall, PrintParameters pp) {
+        return formatComplexVector(iter, access, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth());
     }
 
     @TruffleBoundary
-    static ComplexVectorMetrics formatComplexVector(RAbstractComplexVector x, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) {
-
-        int wr;
-        int dr;
-        int er;
-        int wi;
-        int di;
-        int ei;
+    static ComplexVectorMetrics formatComplexVector(RandomIterator iter, VectorAccess access, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) {
 
         /* format.info() or x[1..l] for both Re & Im */
-        int left;
-        int right;
-        int sleft;
         int rt;
         int mnl;
         int mxl;
         int mxsl;
         int mxns;
-        int wF;
-        int iwF;
         int irt;
         int imnl;
         int imxl;
         int imxsl;
         int imxns;
-        int neg;
-        boolean naflag;
-        boolean rnanflag;
-        boolean rposinf;
-        boolean rneginf;
-        boolean inanflag;
-        boolean iposinf;
-        RComplex tmp;
         boolean allReZero = true;
         boolean allImZero = true;
-
-        naflag = false;
-        rnanflag = false;
-        rposinf = false;
-        rneginf = false;
-        inanflag = false;
-        iposinf = false;
-        neg = 0;
-
+        boolean naflag = false;
+        boolean rnanflag = false;
+        boolean rposinf = false;
+        boolean rneginf = false;
+        boolean inanflag = false;
+        boolean iposinf = false;
+
+        int neg = 0;
         rt = mxl = mxsl = mxns = RRuntime.INT_MIN_VALUE;
         irt = imxl = imxsl = imxns = RRuntime.INT_MIN_VALUE;
         imnl = mnl = RRuntime.INT_MAX_VALUE;
 
         for (int i = 0; i < n; i++) {
             /* Now round */
-            RComplex xi = x.getDataAt(offs + i);
+            RComplex xi = access.getComplex(iter, offs + i);
             if (RRuntime.isNA(xi.getRealPart()) || RRuntime.isNA(xi.getImaginaryPart())) {
                 naflag = true;
             } else {
                 /* real part */
 
-                tmp = zprecr(xi, digits);
-
+                RComplex tmp = zprecr(xi, digits);
                 if (!RRuntime.isFinite(tmp.getRealPart())) {
                     if (RRuntime.isNAorNaN(tmp.getRealPart())) {
                         rnanflag = true;
@@ -151,12 +131,12 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe
                     }
                     ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getRealPart(), digits);
 
-                    left = sd.kpower + 1;
+                    int left = sd.kpower + 1;
                     if (sd.roundingwidens) {
                         left--;
                     }
-                    sleft = sd.sgn + ((left <= 0) ? 1 : left); /* >= 1 */
-                    right = sd.nsig - left; /* #{digits} right of '.' ( > 0 often) */
+                    int sleft = sd.sgn + ((left <= 0) ? 1 : left); /* >= 1 */
+                    int right = sd.nsig - left; /* #{digits} right of '.' ( > 0 often) */
                     if (sd.sgn != 0) {
                         neg = 1; /* if any < 0, need extra space for sign */
                     }
@@ -194,12 +174,12 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe
                     }
                     ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getImaginaryPart(), digits);
 
-                    left = sd.kpower + 1;
+                    int left = sd.kpower + 1;
                     if (sd.roundingwidens) {
                         left--;
                     }
-                    sleft = (left <= 0) ? 1 : left;
-                    right = sd.nsig - left;
+                    int sleft = (left <= 0) ? 1 : left;
+                    int right = sd.nsig - left;
 
                     if (right > irt) {
                         irt = right;
@@ -229,6 +209,11 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe
         if (digits == 0) {
             rt = 0;
         }
+        int wr;
+        int dr;
+        int er;
+        int wi;
+        int wF;
         if (mxl != RRuntime.INT_MIN_VALUE) {
             if (mxl < 0) {
                 mxsl = 1 + neg;
@@ -253,6 +238,9 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe
         if (digits == 0) {
             irt = 0;
         }
+        int di;
+        int ei;
+        int iwF;
         if (imxl != RRuntime.INT_MIN_VALUE) {
             if (imxl < 0) {
                 imxsl = 1;
@@ -400,8 +388,11 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe
 
     @TruffleBoundary
     public static String encodeComplex(RComplex x, int digits, int sciPen, String naString) {
-        ComplexVectorMetrics cvm = formatComplexVector(x, 0, 1, 0, digits, sciPen, naString.length());
-        return encodeComplex(x, cvm, '.', digits, naString);
+        VectorAccess access = x.slowPathAccess();
+        try (RandomIterator iter = access.randomAccess(x)) {
+            ComplexVectorMetrics cvm = formatComplexVector(iter, access, 0, 1, 0, digits, sciPen, naString.length());
+            return encodeComplex(x, cvm, '.', digits, naString);
+        }
     }
 
     @TruffleBoundary
@@ -465,13 +456,19 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe
     }
 
     public static String[] format(RAbstractComplexVector value, boolean trim, int nsmall, int width, char decimalMark, PrintParameters pp) {
-        ComplexVectorMetrics dfm = formatComplexVector(value, 0, value.getLength(), nsmall, pp);
-        ComplexVectorMetrics adjusted = new ComplexVectorMetrics(Math.max(trim ? 1 : dfm.wr, width), dfm.dr, dfm.er, Math.max(trim ? 1 : dfm.wi, width), dfm.di, dfm.ei);
-
-        String[] result = new String[value.getLength()];
-        for (int i = 0; i < value.getLength(); i++) {
-            result[i] = encodeComplex(value.getDataAt(i), adjusted, decimalMark, pp);
+        VectorAccess access = value.slowPathAccess();
+        try (RandomIterator iter = access.randomAccess(value)) {
+            int length = access.getLength(iter);
+            ComplexVectorMetrics dfm = formatComplexVector(iter, access, 0, length, nsmall, pp);
+            int wr = Math.max(trim ? 1 : dfm.wr, width);
+            int wi = Math.max(trim ? 1 : dfm.wi, width);
+            ComplexVectorMetrics adjusted = new ComplexVectorMetrics(wr, dfm.dr, dfm.er, wi, dfm.di, dfm.ei);
+
+            String[] result = new String[length];
+            for (int i = 0; i < length; i++) {
+                result[i] = encodeComplex(access.getComplex(iter, i), adjusted, decimalMark, pp);
+            }
+            return result;
         }
-        return result;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
index 1c3df1c59f40dc33de4b909f935aa54be4febb28..afec29e85a7f87ca11f4ff92b22ba11dae5d90c5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
@@ -15,8 +15,10 @@ import java.io.IOException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDouble;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 
 //Transcribed from GnuR, src/main/format.c
 
@@ -41,13 +43,13 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
 
         @Override
         protected DoubleVectorMetrics formatVector(int offs, int len) {
-            return formatDoubleVector(vector, offs, len, 0, printCtx.parameters());
+            return formatDoubleVector(iterator, access, offs, len, 0, printCtx.parameters());
         }
 
         @Override
         protected void printElement(int i, FormatMetrics fm) throws IOException {
             DoubleVectorMetrics dfm = (DoubleVectorMetrics) fm;
-            String v = encodeReal(vector.getDataAt(i), dfm.maxWidth, dfm.d, dfm.e, '.', printCtx.parameters());
+            String v = encodeReal(access.getDouble(iterator, i), dfm.maxWidth, dfm.d, dfm.e, '.', printCtx.parameters());
             out.print(v);
         }
 
@@ -68,12 +70,12 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
     }
 
     @TruffleBoundary
-    static DoubleVectorMetrics formatDoubleVector(RAbstractDoubleVector x, int offs, int n, int nsmall, PrintParameters pp) {
-        return formatDoubleVector(x, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth());
+    static DoubleVectorMetrics formatDoubleVector(RandomIterator iter, VectorAccess access, int offs, int n, int nsmall, PrintParameters pp) {
+        return formatDoubleVector(iter, access, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth());
     }
 
     @TruffleBoundary
-    public static DoubleVectorMetrics formatDoubleVector(RAbstractDoubleVector x, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) {
+    public static DoubleVectorMetrics formatDoubleVector(RandomIterator iter, VectorAccess access, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) {
         int left;
         int right;
         int sleft;
@@ -107,7 +109,7 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
         mnl = RRuntime.INT_MAX_VALUE;
 
         for (int i = 0; i < n; i++) {
-            double xi = x.getDataAt(i + offs);
+            double xi = access.getDouble(iter, offs + i);
             if (!RRuntime.isFinite(xi)) {
                 if (RRuntime.isNA(xi)) {
                     naflag = true;
@@ -368,8 +370,12 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
 
     @TruffleBoundary
     public static String encodeReal(double x, int digits, char cdec, int sciPen, String naString) {
-        DoubleVectorMetrics dm = formatDoubleVector(RDataFactory.createDoubleVectorFromScalar(x), 0, 1, 0, digits, sciPen, naString.length());
-        return encodeReal(x, dm.maxWidth, dm.d, dm.e, cdec, naString);
+        RDouble value = RDouble.valueOf(x);
+        VectorAccess access = value.slowPathAccess();
+        try (RandomIterator iter = access.randomAccess(value)) {
+            DoubleVectorMetrics dm = formatDoubleVector(iter, access, 0, 1, 0, digits, sciPen, naString.length());
+            return encodeReal(x, dm.maxWidth, dm.d, dm.e, cdec, naString);
+        }
     }
 
     @TruffleBoundary
@@ -563,13 +569,17 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
     }
 
     public static String[] format(RAbstractDoubleVector value, boolean trim, int nsmall, int width, char decimalMark, PrintParameters pp) {
-        DoubleVectorMetrics dfm = formatDoubleVector(value, 0, value.getLength(), nsmall, pp);
-        int w = Math.max(trim ? 1 : dfm.maxWidth, width);
-
-        String[] result = new String[value.getLength()];
-        for (int i = 0; i < value.getLength(); i++) {
-            result[i] = encodeReal(value.getDataAt(i), w, dfm.d, dfm.e, decimalMark, pp);
+        VectorAccess access = value.slowPathAccess();
+        try (RandomIterator iter = access.randomAccess(value)) {
+            int length = access.getLength(iter);
+            DoubleVectorMetrics dfm = formatDoubleVector(iter, access, 0, length, nsmall, pp);
+            int w = Math.max(trim ? 1 : dfm.maxWidth, width);
+
+            String[] result = new String[length];
+            for (int i = 0; i < length; i++) {
+                result[i] = encodeReal(access.getDouble(iter, i), w, dfm.d, dfm.e, decimalMark, pp);
+            }
+            return result;
         }
-        return result;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java
index f9d0ea7c4f89cb0cf9b1470a644d0615fee0eed6..6c7d6c4ae77dc7f4a932c91cec375c664c1083a8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java
@@ -17,6 +17,8 @@ import java.io.IOException;
 
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 
 //Transcribed from GnuR, src/main/printutils.c, src/main/format.c
 
@@ -46,12 +48,12 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector
 
         @Override
         protected FormatMetrics formatVector(int offs, int len) {
-            return new FormatMetrics(formatIntVectorInternal(vector, offs, len, printCtx.parameters().getNaWidth()));
+            return new FormatMetrics(formatIntVectorInternal(iterator, access, offs, len, printCtx.parameters().getNaWidth()));
         }
 
         @Override
         protected void printElement(int i, FormatMetrics fm) throws IOException {
-            String v = encodeInteger(vector.getDataAt(i), fm.maxWidth, printCtx.parameters());
+            String v = encodeInteger(access.getInt(iterator, i), fm.maxWidth, printCtx.parameters());
             out.print(v);
         }
 
@@ -66,7 +68,7 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector
         }
     }
 
-    static int formatIntVectorInternal(RAbstractIntVector x, int offs, int n, int naWidth) {
+    static int formatIntVectorInternal(RandomIterator iter, VectorAccess access, int offs, int n, int naWidth) {
         int xmin = RRuntime.INT_MAX_VALUE;
         int xmax = RRuntime.INT_MIN_VALUE;
         boolean naflag = false;
@@ -74,7 +76,7 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector
         int fieldwidth;
 
         for (int i = 0; i < n; i++) {
-            int xi = x.getDataAt(offs + i);
+            int xi = access.getInt(iter, offs + i);
             if (xi == RRuntime.INT_NA) {
                 naflag = true;
             } else {
@@ -164,18 +166,22 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector
     }
 
     public static String[] format(RAbstractIntVector value, boolean trim, int width, PrintParameters pp) {
-        int w;
-        if (trim) {
-            w = 1;
-        } else {
-            w = formatIntVectorInternal(value, 0, value.getLength(), pp.getNaWidth());
-        }
-        w = Math.max(w, width);
+        VectorAccess access = value.slowPathAccess();
+        try (RandomIterator iter = access.randomAccess(value)) {
+            int w;
+            int length = access.getLength(iter);
+            if (trim) {
+                w = 1;
+            } else {
+                w = formatIntVectorInternal(iter, access, 0, length, pp.getNaWidth());
+            }
+            w = Math.max(w, width);
 
-        String[] result = new String[value.getLength()];
-        for (int i = 0; i < value.getLength(); i++) {
-            result[i] = encodeInteger(value.getDataAt(i), w, pp);
+            String[] result = new String[length];
+            for (int i = 0; i < length; i++) {
+                result[i] = encodeInteger(access.getInt(iter, i), w, pp);
+            }
+            return result;
         }
-        return result;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
index 7c84d1caf7a79c2145c6ad528bd222ee4e6ed597..65694c0578f9cc5c94f3c3b15bddb268ab7e8056 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
@@ -24,7 +24,6 @@ import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributable;
-import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -36,6 +35,8 @@ 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.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 
 //Transcribed from GnuR, src/main/print.c
 
@@ -77,8 +78,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
             } else if (tmp instanceof RAbstractLogicalVector) {
                 RAbstractLogicalVector lv = (RAbstractLogicalVector) tmp;
                 if (lv.getLength() == 1) {
-                    int width = LogicalVectorPrinter.formatLogicalVectorInternal(lv, 0, 1, pp.getNaWidth());
-                    pbuf = LogicalVectorPrinter.encodeLogical(lv.getDataAt(0), width, pp);
+                    pbuf = LogicalVectorPrinter.format(lv, false, 0, pp)[0];
                 } else {
                     pbuf = "Logical," + lv.getLength();
                 }
@@ -89,8 +89,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
                     pbuf = "factor," + iv.getLength();
                 } else {
                     if (iv.getLength() == 1) {
-                        int width = IntegerVectorPrinter.formatIntVectorInternal(iv, 0, 1, pp.getNaWidth());
-                        pbuf = IntegerVectorPrinter.encodeInteger(iv.getDataAt(0), width, pp);
+                        pbuf = IntegerVectorPrinter.format(iv, false, 0, pp)[0];
                     } else {
                         pbuf = "Integer," + iv.getLength();
                     }
@@ -98,31 +97,26 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
             } else if (tmp instanceof RAbstractDoubleVector) {
                 RAbstractDoubleVector dv = (RAbstractDoubleVector) tmp;
                 if (dv.getLength() == 1) {
-                    DoubleVectorMetrics fm = DoubleVectorPrinter.formatDoubleVector(dv, 0, 1, 0, pp);
-                    pbuf = DoubleVectorPrinter.encodeReal(dv.getDataAt(0), fm, pp);
+                    pbuf = DoubleVectorPrinter.format(dv, false, 0, 0, '.', pp)[0];
                 } else {
                     pbuf = "Numeric," + dv.getLength();
                 }
             } else if (tmp instanceof RAbstractComplexVector) {
                 RAbstractComplexVector cv = (RAbstractComplexVector) tmp;
                 if (cv.getLength() == 1) {
-                    RComplex x = cv.getDataAt(0);
-                    if (RRuntime.isNA(x.getRealPart()) || RRuntime.isNA(x.getImaginaryPart())) {
-                        /* formatReal(NA) --> w=R_print.na_width, d=0, e=0 */
-                        pbuf = DoubleVectorPrinter.encodeReal(RRuntime.DOUBLE_NA, pp.getNaWidth(), 0, 0, '.', pp);
-                    } else {
-                        ComplexVectorMetrics cvm = ComplexVectorPrinter.formatComplexVector(x, 0, 1, 0, pp);
-                        pbuf = ComplexVectorPrinter.encodeComplex(x, cvm, '.', pp);
-                    }
+                    pbuf = ComplexVectorPrinter.format(cv, false, 0, 0, '.', pp)[0];
                 } else {
                     pbuf = "Complex," + cv.getLength();
                 }
             } else if (tmp instanceof RAbstractStringVector) {
                 RAbstractStringVector sv = (RAbstractStringVector) tmp;
                 if (sv.getLength() == 1) {
-                    String ctmp = RRuntime.escapeString(sv.getDataAt(0), true, true);
-                    int len = ctmp.length();
-                    if (len < 100) {
+                    String ctmp;
+                    VectorAccess access = sv.slowPathAccess();
+                    try (RandomIterator iter = access.randomAccess(sv)) {
+                        ctmp = RRuntime.escapeString(access.getString(iter, 0), true, true);
+                    }
+                    if (ctmp.length() < 100) {
                         pbuf = ctmp;
                     } else {
                         pbuf = Utils.trimSize(101, ctmp) + "\" [truncated]";
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java
index 3421a15d5b01f989d577a8e5b274bea67a117002..7bb3d8274d49d4b4eebab8c3471a899445392726 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java
@@ -15,6 +15,8 @@ import java.io.IOException;
 
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 
 //Transcribed from GnuR, src/main/printutils.c, src/main/format.c
 
@@ -44,12 +46,12 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe
 
         @Override
         protected FormatMetrics formatVector(int offs, int len) {
-            return new FormatMetrics(formatLogicalVectorInternal(vector, offs, len, printCtx.parameters().getNaWidth()));
+            return new FormatMetrics(formatLogicalVectorInternal(iterator, access, offs, len, printCtx.parameters().getNaWidth()));
         }
 
         @Override
         protected void printElement(int i, FormatMetrics fm) throws IOException {
-            out.print(encodeLogical(vector.getDataAt(i), fm.maxWidth, printCtx.parameters()));
+            out.print(encodeLogical(access.getLogical(iterator, i), fm.maxWidth, printCtx.parameters()));
         }
 
         @Override
@@ -63,10 +65,10 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe
         }
     }
 
-    static int formatLogicalVectorInternal(RAbstractLogicalVector x, int offs, int n, int naWidth) {
+    static int formatLogicalVectorInternal(RandomIterator iter, VectorAccess access, int offs, int n, int naWidth) {
         int fieldwidth = 1;
         for (int i = 0; i < n; i++) {
-            byte xi = x.getDataAt(offs + i);
+            byte xi = access.getLogical(iter, offs + i);
             if (xi == RRuntime.LOGICAL_NA) {
                 if (fieldwidth < naWidth) {
                     fieldwidth = naWidth;
@@ -105,18 +107,22 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe
     }
 
     public static String[] format(RAbstractLogicalVector value, boolean trim, int width, PrintParameters pp) {
-        int w;
-        if (trim) {
-            w = 1;
-        } else {
-            w = formatLogicalVectorInternal(value, 0, value.getLength(), pp.getNaWidth());
-        }
-        w = Math.max(w, width);
+        VectorAccess access = value.slowPathAccess();
+        try (RandomIterator iter = access.randomAccess(value)) {
+            int length = access.getLength(iter);
+            int w;
+            if (trim) {
+                w = 1;
+            } else {
+                w = formatLogicalVectorInternal(iter, access, 0, length, pp.getNaWidth());
+            }
+            w = Math.max(w, width);
 
-        String[] result = new String[value.getLength()];
-        for (int i = 0; i < value.getLength(); i++) {
-            result[i] = encodeLogical(value.getDataAt(i), w, pp);
+            String[] result = new String[value.getLength()];
+            for (int i = 0; i < length; i++) {
+                result[i] = encodeLogical(access.getLogical(iter, i), w, pp);
+            }
+            return result;
         }
-        return result;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyPrintWriter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyPrintWriter.java
index 675bb97080f397e81113ed17aa37d1a63bad2182..138cbe4e58af0de7b3ab12f7b71c657e752da9e6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyPrintWriter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyPrintWriter.java
@@ -26,7 +26,6 @@ import java.io.PrintWriter;
 import java.io.Writer;
 
 import com.oracle.truffle.r.runtime.data.RAttributeStorage;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public class PrettyPrintWriter extends PrintWriter implements PrettyWriter {
 
@@ -81,16 +80,16 @@ public class PrettyPrintWriter extends PrintWriter implements PrettyWriter {
     }
 
     @Override
-    public void beginElement(RAbstractVector vector, int index, FormatMetrics fm) {
+    public void beginElement(int index, FormatMetrics fm) {
         if (out instanceof PrettyWriter) {
-            ((PrettyWriter) out).beginElement(vector, index, fm);
+            ((PrettyWriter) out).beginElement(index, fm);
         }
     }
 
     @Override
-    public void endElement(RAbstractVector vector, int index, FormatMetrics fm) {
+    public void endElement(int index, FormatMetrics fm) {
         if (out instanceof PrettyWriter) {
-            ((PrettyWriter) out).endElement(vector, index, fm);
+            ((PrettyWriter) out).endElement(index, fm);
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyWriter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyWriter.java
index 9813e5cc9f439bee7ebc325a254a6a202dc9568e..b54c046686781bb656aa878817e2d9ed1efb2ff5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyWriter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,6 @@
 package com.oracle.truffle.r.nodes.builtin.base.printer;
 
 import com.oracle.truffle.r.runtime.data.RAttributeStorage;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public interface PrettyWriter {
 
@@ -39,9 +38,9 @@ public interface PrettyWriter {
 
     void endAttributes(RAttributeStorage value);
 
-    void beginElement(RAbstractVector vector, int index, FormatMetrics fm);
+    void beginElement(int index, FormatMetrics fm);
 
-    void endElement(RAbstractVector vector, int index, FormatMetrics fm);
+    void endElement(int index, FormatMetrics fm);
 
     Object getPrintReport();
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RawVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RawVectorPrinter.java
index bf648a7aa9f0280a5bbfa9ab0e4b0981ed74ea3d..f3ffdebdd96170f6dcf74d4e6507b02f4e850a41 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RawVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RawVectorPrinter.java
@@ -60,7 +60,7 @@ final class RawVectorPrinter extends VectorPrinter<RAbstractRawVector> {
         @Override
         @TruffleBoundary
         protected void printElement(int i, FormatMetrics fm) throws IOException {
-            String rs = RRuntime.rawToHexString(vector.getRawDataAt(i));
+            String rs = RRuntime.rawToHexString(access.getRaw(iterator, i));
             if (fm.maxWidth > 2) {
                 StringBuilder str = new StringBuilder(fm.maxWidth);
                 for (int j = 2; j < fm.maxWidth; j++) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrettyWriter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrettyWriter.java
index de109409424251285af7b61c24615bf440702913..0e188fffc786d79c7f77ef0240e3799293aeaa02 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrettyWriter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrettyWriter.java
@@ -25,7 +25,6 @@ package com.oracle.truffle.r.nodes.builtin.base.printer;
 import java.io.StringWriter;
 
 import com.oracle.truffle.r.runtime.data.RAttributeStorage;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public class StringPrettyWriter extends StringWriter implements PrettyWriter {
 
@@ -54,11 +53,11 @@ public class StringPrettyWriter extends StringWriter implements PrettyWriter {
     }
 
     @Override
-    public void beginElement(RAbstractVector vector, int index, FormatMetrics fm) {
+    public void beginElement(int index, FormatMetrics fm) {
     }
 
     @Override
-    public void endElement(RAbstractVector vector, int index, FormatMetrics fm) {
+    public void endElement(int index, FormatMetrics fm) {
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java
index 5ba2ea9ebc1e0f52b2601b313cda108089ada5a4..13937fca383ca7404f733dde9edde436038b5e35 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java
@@ -18,6 +18,8 @@ import java.util.Arrays;
 
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 
 //Transcribed from GnuR, src/main/format.c
 
@@ -42,19 +44,19 @@ final class StringVectorPrinter extends VectorPrinter<RAbstractStringVector> {
 
         @Override
         protected FormatMetrics formatVector(int offs, int len) {
-            int w = formatString(vector, offs, len, quote, printCtx.parameters());
+            int w = formatString(iterator, access, offs, len, quote, printCtx.parameters());
             return new FormatMetrics(w);
         }
 
         @Override
         protected void printElement(int i, FormatMetrics fm) throws IOException {
-            String s = vector.getDataAt(i);
+            String s = access.getString(iterator, i);
             StringVectorPrinter.printString(s, fm.maxWidth, printCtx);
         }
 
         @Override
         protected void printCell(int i, FormatMetrics fm) throws IOException {
-            String s = vector.getDataAt(i);
+            String s = access.getString(iterator, i);
             String outS = StringVectorPrinter.encode(s, fm.maxWidth, printCtx.parameters());
             int g = printCtx.parameters().getGap();
             String fmt = "%" + asBlankArg(g) + "s%s";
@@ -95,7 +97,7 @@ final class StringVectorPrinter extends VectorPrinter<RAbstractStringVector> {
         }
     }
 
-    static int formatString(RAbstractStringVector x, int offs, int n, boolean quote, PrintParameters pp) {
+    static int formatString(RandomIterator iter, VectorAccess access, int offs, int n, boolean quote, PrintParameters pp) {
         int xmax = 0;
         int l;
 
@@ -103,7 +105,7 @@ final class StringVectorPrinter extends VectorPrinter<RAbstractStringVector> {
         int fieldwidth;
 
         for (int i = 0; i < n; i++) {
-            String s = x.getDataAt(offs + i);
+            String s = access.getString(iter, offs + i);
             String xi = RRuntime.escapeString(s, false, quote);
 
             if (xi == RRuntime.STRING_NA) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
index e2a12e3ae18c0977f6db8c47300dac10950c6080..4a97ef3b3c4ec5e5cbd0ce13ce951147906e4848 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
@@ -24,6 +24,8 @@ import com.oracle.truffle.r.runtime.data.RList;
 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.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 
 //Transcribed from GnuR, src/main/print.c, src/main/printarray.c, src/main/printvector.c
 
@@ -35,7 +37,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
     }
 
     public void printVector(T vector, int indx, PrintContext printCtx) throws IOException {
-        createJob(vector, indx, printCtx).print();
+        createJob(vector, indx, printCtx).print(vector);
     }
 
     protected abstract VectorPrintJob createJob(T vector, int indx, PrintContext printCtx);
@@ -53,7 +55,8 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
 
     protected abstract class VectorPrintJob {
 
-        protected final T vector;
+        protected VectorAccess access;
+        protected RandomIterator iterator;
         protected final int n;
         protected final int nPr;
         protected final int indx;
@@ -69,13 +72,13 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
         protected final boolean supressIndexLabels;
 
         protected VectorPrintJob(T vector, int indx, PrintContext printCtx) {
-            this.vector = vector;
             this.indx = indx;
             this.quote = printCtx.parameters().getQuote();
 
             MatrixDimNames mdn = null;
 
             Object dimAttr = getDims(vector);
+            int length = vector.getLength();
             if (dimAttr instanceof RAbstractIntVector) {
                 dims = (RAbstractIntVector) dimAttr;
                 if (dims.getLength() == 1) {
@@ -89,12 +92,12 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
                             title = null;
                         }
 
-                        jobMode = vector.getLength() == 0 ? JobMode.namedEmpty : JobMode.named;
+                        jobMode = length == 0 ? JobMode.namedEmpty : JobMode.named;
                         names = Utils.castTo(RRuntime.convertScalarVectors(t.getDataAt(0)));
                     } else {
                         title = null;
                         names = null;
-                        jobMode = vector.getLength() == 0 ? JobMode.empty : JobMode.nonEmpty;
+                        jobMode = length == 0 ? JobMode.empty : JobMode.nonEmpty;
                     }
                 } else if (dims.getLength() == 2) {
                     mdn = new MatrixDimNames(vector);
@@ -111,14 +114,14 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
                 dims = null;
                 Object namesAttr = Utils.castTo(getNames(vector));
                 if (namesAttr != null) {
-                    if (vector.getLength() > 0) {
+                    if (length > 0) {
                         names = Utils.castTo(RRuntime.convertScalarVectors(namesAttr));
                         jobMode = JobMode.named;
                     } else {
                         names = null;
                         jobMode = JobMode.namedEmpty;
                     }
-                } else if (vector.getLength() > 0) {
+                } else if (length > 0) {
                     jobMode = JobMode.nonEmpty;
                     names = null;
                 } else {
@@ -134,32 +137,36 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
                 this.printCtx.parameters().setRight(true);
             }
             this.out = this.printCtx.output();
-            this.n = vector.getLength();
+            this.n = length;
             int max = printCtx.parameters().getMax();
             this.nPr = (n <= max + 1) ? n : max;
             this.labwidth = indexWidth(n) + 2;
             this.matrixDimNames = mdn;
         }
 
-        public void print() throws IOException {
-            switch (jobMode) {
-                case empty:
-                    printEmptyVector();
-                    break;
-                case nonEmpty:
-                    printNonEmptyVector();
-                    break;
-                case named:
-                    printNamedVector();
-                    break;
-                case namedEmpty:
-                    printNamedEmptyVector();
-                    break;
-                case matrix:
-                    printMatrix();
-                    break;
-                case array:
-                    printArray();
+        public final void print(T vector) throws IOException {
+            access = vector.access();
+            try (RandomIterator iter = access.randomAccess(vector)) {
+                this.iterator = iter;
+                switch (jobMode) {
+                    case empty:
+                        printEmptyVector();
+                        break;
+                    case nonEmpty:
+                        printNonEmptyVector();
+                        break;
+                    case named:
+                        printNamedVector();
+                        break;
+                    case namedEmpty:
+                        printNamedEmptyVector();
+                        break;
+                    case matrix:
+                        printMatrix();
+                        break;
+                    case array:
+                        printArray();
+                }
             }
         }
 
@@ -209,7 +216,10 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
 
             PrintParameters pp = printCtx.parameters();
 
-            wn = StringVectorPrinter.formatString(names, 0, n, false, pp);
+            VectorAccess namesAccess = names.slowPathAccess();
+            try (RandomIterator namesIter = namesAccess.randomAccess(names)) {
+                wn = StringVectorPrinter.formatString(namesIter, namesAccess, 0, n, false, pp);
+            }
             if (fm.maxWidth < wn) {
                 fm.maxWidth = wn;
             }
@@ -302,7 +312,10 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
             int lbloff = 0;
 
             if (rl != null) {
-                rlabw = StringVectorPrinter.formatString(rl, 0, r, false, pp);
+                VectorAccess rlAccess = rl.slowPathAccess();
+                try (RandomIterator rlIter = rlAccess.randomAccess(rl)) {
+                    rlabw = StringVectorPrinter.formatString(rlIter, rlAccess, 0, r, false, pp);
+                }
             } else {
                 rlabw = indexWidth(r + 1) + 3;
             }
@@ -609,9 +622,9 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
         protected abstract void printElement(int i, FormatMetrics fm) throws IOException;
 
         private void printElementAndNotify(int i, FormatMetrics fm) throws IOException {
-            out.beginElement(vector, i, fm);
+            out.beginElement(i, fm);
             printElement(i, fm);
-            out.endElement(vector, i, fm);
+            out.endElement(i, fm);
         }
 
         /**
@@ -625,9 +638,9 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
         protected abstract void printCell(int i, FormatMetrics fm) throws IOException;
 
         private void printCellAndNotify(int i, FormatMetrics fm) throws IOException {
-            out.beginElement(vector, i, fm);
+            out.beginElement(i, fm);
             printCell(i, fm);
-            out.endElement(vector, i, fm);
+            out.endElement(i, fm);
         }
 
         protected int matrixIndividualCellColumnWidthCorrection() {
@@ -713,7 +726,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
     }
 
     @TruffleBoundary
-    private static Object getNames(RAbstractVector vector) {
-        return vector.getAttr(RRuntime.NAMES_ATTR_KEY);
+    private static Object getNames(RAbstractVector x) {
+        return x.getAttr(RRuntime.NAMES_ATTR_KEY);
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java
index 1b211974b3c9f8ab72cb4d8711e76a132876cfe3..9f6f6652e1d19533b225ea5e3afe6c2943211587 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java
@@ -258,15 +258,14 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> {
     public RSyntaxNode constant(SourceSection source, Object value) {
         if (value instanceof String && !RRuntime.isNA((String) value)) {
             return ConstantNode.create(source, Utils.intern((String) value));
-        } else {
-            if (value instanceof RShareable) {
-                RShareable shareable = (RShareable) value;
-                if (!shareable.isSharedPermanent()) {
-                    return ConstantNode.create(source, shareable.makeSharedPermanent());
-                }
+        }
+        if (value instanceof RShareable) {
+            RShareable shareable = (RShareable) value;
+            if (!shareable.isSharedPermanent()) {
+                return ConstantNode.create(source, shareable.makeSharedPermanent());
             }
-            return ConstantNode.create(source, value);
         }
+        return ConstantNode.create(source, value);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
index 903947939fed214361eb750ec927e7f480a2c503..4ab4126616010c6acaae4d804942752ec14601e6 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
@@ -39,10 +39,8 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNa
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
-import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.nodes.profile.AlwaysOnBranchProfile;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
-import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -52,8 +50,6 @@ import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RPromise;
-import com.oracle.truffle.r.runtime.data.RS4Object;
 import com.oracle.truffle.r.runtime.data.RString;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
@@ -61,7 +57,6 @@ import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 final class CachedExtractVectorNode extends CachedVectorNode {
@@ -69,7 +64,7 @@ final class CachedExtractVectorNode extends CachedVectorNode {
     private static final boolean DEFAULT_EXACT = true;
     private static final boolean DEFAULT_DROP_DIMENSION = true;
 
-    private final Class<? extends RTypedValue> targetClass;
+    private final Class<? extends RAbstractContainer> targetClass;
     private final Class<? extends RTypedValue> exactClass;
     private final Class<? extends RTypedValue> dropDimensionsClass;
     private final boolean exact;
@@ -90,10 +85,7 @@ final class CachedExtractVectorNode extends CachedVectorNode {
 
     @Child private ExtractDimNamesNode extractDimNames;
 
-    @Child private ExtractS4ObjectNode extractS4ObjectNode;
-
     private final ConditionProfile resultHasDimensions = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile promiseInEnvironment = ConditionProfile.createBinaryProfile();
 
     /**
      * Profile if any metadata was applied at any point in time. This is useful extract primitive
@@ -101,8 +93,9 @@ final class CachedExtractVectorNode extends CachedVectorNode {
      */
     private final AlwaysOnBranchProfile metadataApplied = AlwaysOnBranchProfile.create();
 
-    CachedExtractVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, RTypedValue exact, RTypedValue dropDimensions, boolean recursive) {
+    CachedExtractVectorNode(ElementAccessMode mode, RAbstractContainer vector, Object[] positions, RTypedValue exact, RTypedValue dropDimensions, boolean recursive) {
         super(mode, vector, positions, recursive);
+        assert vectorType != RType.Null && vectorType != RType.Environment;
         this.targetClass = vector.getClass();
         this.exactClass = exact.getClass();
         this.dropDimensionsClass = dropDimensions.getClass();
@@ -112,9 +105,7 @@ final class CachedExtractVectorNode extends CachedVectorNode {
         this.exact = logicalAsBoolean(exact, DEFAULT_EXACT);
         this.dropDimensions = logicalAsBoolean(dropDimensions, DEFAULT_DROP_DIMENSION);
         this.positionsCheckNode = new PositionsCheckNode(mode, vectorType, convertedPositions, this.exact, false, recursive);
-        if (error == null && vectorType != RType.Null && vectorType != RType.Environment && vectorType != RType.S4Object) {
-            this.writeVectorNode = WriteIndexedVectorNode.create(vectorType, convertedPositions.length, true, false, false, false);
-        }
+        this.writeVectorNode = WriteIndexedVectorNode.create(vectorType, convertedPositions.length, true, false, false);
     }
 
     public boolean isSupported(Object target, Object[] positions, Object exactValue, Object dropDimensionsValue) {
@@ -130,36 +121,10 @@ final class CachedExtractVectorNode extends CachedVectorNode {
     private final ConditionProfile extractedLengthGTZeroProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile oneDimensionProfile = ConditionProfile.createBinaryProfile();
 
-    public Object apply(Object originalVector, Object[] originalPositions, PositionProfile[] originalProfiles, Object originalExact, Object originalDropDimensions) {
-        if (error != null) {
-            CompilerDirectives.transferToInterpreter();
-            error.run();
-        }
+    public Object apply(RAbstractContainer originalVector, Object[] originalPositions, PositionProfile[] originalProfiles, Object originalExact, Object originalDropDimensions) {
         final Object[] positions = filterPositions(originalPositions);
-
         assert isSupported(originalVector, positions, originalExact, originalDropDimensions);
-
-        final RTypedValue castVector = targetClass.cast(originalVector);
-        final RAbstractContainer vector;
-        switch (vectorType) {
-            case Null:
-                return RNull.instance;
-            case Environment:
-                /*
-                 * TODO (chumer) the environment case cannot be applied to the default extract
-                 * method as it does not implement RAbstractContainer. This should be harmonized
-                 * later.
-                 */
-                return doEnvironment((REnvironment) castVector, positions);
-            case S4Object:
-                return doS4Object((RS4Object) castVector, positions);
-            case Integer:
-                vector = (RAbstractContainer) castVector;
-                break;
-            default:
-                vector = (RAbstractContainer) castVector;
-                break;
-        }
+        RAbstractContainer vector = targetClass.cast(originalVector);
 
         int vectorLength = vectorLengthProfile.profile(vector.getLength());
 
@@ -178,11 +143,8 @@ final class CachedExtractVectorNode extends CachedVectorNode {
         }
 
         int extractedVectorLength = positionsCheckNode.getSelectedPositionsCount(positionProfiles);
-        final RVector<?> extractedVector;
+        RVector<?> extractedVector;
         switch (vectorType) {
-            case Expression:
-                extractedVector = RType.Expression.create(extractedVectorLength, false);
-                break;
             case Language:
             case PairList:
                 extractedVector = RType.List.create(extractedVectorLength, false);
@@ -194,9 +156,7 @@ final class CachedExtractVectorNode extends CachedVectorNode {
 
         if (mode.isSubset()) {
             if (extractedLengthGTZeroProfile.profile(extractedVectorLength > 0)) {
-                writeVectorNode.enableValueNACheck(vector);
-                writeVectorNode.apply(extractedVector, extractedVectorLength, positions, vector, vectorLength, dimensions);
-                extractedVector.setComplete(writeVectorNode.neverSeenNAInValue());
+                writeVectorNode.execute(extractedVector, positions, vector, dimensions);
                 RBaseNode.reportWork(this, extractedVectorLength);
             }
             if (oneDimensionProfile.profile(numberOfDimensions == 1)) {
@@ -216,15 +176,13 @@ final class CachedExtractVectorNode extends CachedVectorNode {
             }
 
             switch (vectorType) {
-                case Expression:
-                    return extractedVector;
                 case Language:
                     return materializeLanguage(extractedVector);
                 default:
                     return trySubsetPrimitive(extractedVector);
             }
         } else {
-            writeVectorNode.apply(extractedVector, extractedVectorLength, positions, vector, vectorLength, dimensions);
+            writeVectorNode.execute(extractedVector, positions, vector, dimensions);
             RBaseNode.reportWork(this, 1);
             assert extractedVectorLength == 1;
             return extractedVector.getDataAtAsObject(0);
@@ -242,7 +200,7 @@ final class CachedExtractVectorNode extends CachedVectorNode {
     }
 
     private Object trySubsetPrimitive(RAbstractVector extractedVector) {
-        if (!metadataApplied.isVisited() && positionsCheckNode.getCachedSelectedPositionsCount() == 1 && !isList()) {
+        if (!metadataApplied.isVisited() && positionsCheckNode.getCachedSelectedPositionsCount() == 1 && vectorType != RType.List && vectorType != RType.Expression) {
             /*
              * If the selected count was always 1 and no metadata was ever set we can just extract
              * the primitive value from the vector. This branch has to fold to a constant because we
@@ -256,31 +214,6 @@ final class CachedExtractVectorNode extends CachedVectorNode {
         return extractedVector;
     }
 
-    @TruffleBoundary
-    private Object doEnvironment(REnvironment env, Object[] positions) {
-        if (mode.isSubset()) {
-            throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName());
-        }
-
-        String positionString = tryCastSingleString(positionsCheckNode, positions);
-        if (positionString != null) {
-            Object obj = env.get(positionString);
-            if (promiseInEnvironment.profile(obj instanceof RPromise)) {
-                obj = PromiseHelperNode.evaluateSlowPath((RPromise) obj);
-            }
-            return obj == null ? RNull.instance : obj;
-        }
-        throw error(RError.Message.WRONG_ARGS_SUBSET_ENV);
-    }
-
-    private Object doS4Object(RS4Object object, Object[] positions) {
-        if (extractS4ObjectNode == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            extractS4ObjectNode = insert(new ExtractS4ObjectNode(mode, exact, dropDimensions));
-        }
-        return extractS4ObjectNode.execute(object, positions);
-    }
-
     private boolean isMissingSingleDimension() {
         return numberOfDimensions == 1 && positionsCheckNode.isMissing();
     }
@@ -298,10 +231,6 @@ final class CachedExtractVectorNode extends CachedVectorNode {
         return extractDimNames.extract(dimensionIndex, vector, pos, profile);
     }
 
-    private boolean isList() {
-        return vectorType == RType.List;
-    }
-
     private final ConditionProfile dimNamesNull = ConditionProfile.createBinaryProfile();
     private final ValueProfile foundDimNamesProfile = ValueProfile.createClassProfile();
     private final ConditionProfile selectPositionsProfile = ConditionProfile.createBinaryProfile();
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
index 40e456bf6c06a3da980ffc7cf9054e56d682aaef..43e9de314e70a6237d6060d7e6b55e63ba6e5abf 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
@@ -34,7 +34,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeInfo;
-import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
@@ -49,15 +48,11 @@ import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RPairList;
-import com.oracle.truffle.r.runtime.data.RS4Object;
+import com.oracle.truffle.r.runtime.data.RScalarList;
 import com.oracle.truffle.r.runtime.data.RScalarVector;
 import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -66,27 +61,22 @@ import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.env.REnvironment;
-import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 final class CachedReplaceVectorNode extends CachedVectorNode {
 
     private static final Object DELETE_MARKER = new Object();
 
-    private final Class<?> vectorClass;
+    private final Class<? extends RAbstractVector> vectorClass;
     private final Class<?> valueClass;
 
     private final VectorLengthProfile targetLengthProfile = VectorLengthProfile.create();
     private final VectorLengthProfile valueLengthProfile = VectorLengthProfile.create();
     private final BranchProfile warningBranch = BranchProfile.create();
-    private final ConditionProfile valueIsNA = ConditionProfile.createBinaryProfile();
     private final BranchProfile resizeProfile = BranchProfile.create();
-    private final ConditionProfile rlanguageAttributesProfile = ConditionProfile.createBinaryProfile();
 
     private final ConditionProfile valueLengthOneProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile emptyReplacementProfile = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile completeVectorProfile = ConditionProfile.createBinaryProfile();
 
     private final ValueProfile vectorTypeProfile = ValueProfile.createClassProfile();
 
@@ -103,9 +93,13 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
     @Child private DeleteElementsNode deleteElementsNode;
     @Child private SetNamesAttributeNode setNamesNode;
 
-    CachedReplaceVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, Class<?> valueClass, RType valueType, boolean updatePositionNames, boolean recursive,
-                    boolean ignoreRecursive, boolean isValueGt1) {
+    // if this is non-null, the node needs to throw the error whenever it is executed
+    @CompilationFinal protected Runnable error;
+
+    CachedReplaceVectorNode(ElementAccessMode mode, RAbstractVector vector, Object[] positions, Class<?> valueClass, RType valueType, boolean updatePositionNames, boolean recursive,
+                    boolean isValueGt1) {
         super(mode, vector, positions, recursive);
+        assert vectorType.isVector();
 
         if (numberOfDimensions == 1 && positions[0] instanceof String || positions[0] instanceof RAbstractStringVector) {
             this.updatePositionNames = updatePositionNames;
@@ -117,17 +111,48 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
         this.valueClass = valueClass;
         this.valueType = valueType;
         this.isValueGt1 = isValueGt1;
-        this.castType = resolveCastVectorType();
-        verifyCastType(this.castType);
-        this.castVectorNode = createCastVectorNode();
+
+        // determine the target cast type
+        if (vectorType == RType.List && mode.isSubscript()) {
+            if (valueType.isNull() && numberOfDimensions > 1) {
+                this.castType = null;
+            } else {
+                this.castType = vectorType;
+            }
+        } else if (valueType.isVector()) {
+            if (vectorType.isAtomic() && valueType.isAtomic() && (vectorType == RType.Raw ^ valueType == RType.Raw)) {
+                // mixing with raw with other atomic types is not allowed
+                this.castType = null;
+            } else {
+                this.castType = RType.maxPrecedence(valueType, vectorType);
+            }
+        } else if (valueType.isNull()) {
+            if (mode.isSubscript() && numberOfDimensions > 1) {
+                this.castType = null;
+            } else {
+                this.castType = vectorType;
+            }
+        } else {
+            this.castType = null;
+        }
+
+        if (castType == null) {
+            Message message = (mode.isSubset() || vectorType != RType.List) ? RError.Message.SUBASSIGN_TYPE_FIX : RError.Message.SUBSCRIPT_TYPES;
+            error = () -> {
+                throw error(message, valueType.getName(), vectorType.getName(), false);
+            };
+        }
+
+        if (castType != vectorType && castType != null) {
+            // All casts except list casts preserve dimension names.
+            this.castVectorNode = castType == RType.List ? CastListNodeGen.create(true, false, true) : CastTypeNode.createCast(castType, true, true, true, false);
+        }
         this.deleteElementsNode = isDeleteElements() ? new DeleteElementsNode() : null;
 
         Object[] convertedPositions = filterPositions(positions);
         this.positionsCheckNode = new PositionsCheckNode(mode, vectorType, convertedPositions, true, true, recursive);
-        if (vectorType == RType.S4Object) {
-            replaceS4ObjectNode = new ReplaceS4ObjectNode(mode, ignoreRecursive);
-        } else if (castType != null && !castType.isNull()) {
-            this.writeVectorNode = WriteIndexedVectorNode.create(castType, convertedPositions.length, false, true, mode.isSubscript() && !isDeleteElements(), true);
+        if (castType != null && !castType.isNull()) {
+            this.writeVectorNode = WriteIndexedVectorNode.create(castType, convertedPositions.length, false, true, true);
         }
     }
 
@@ -135,50 +160,41 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
         return (values instanceof RAbstractContainer) && ((RAbstractContainer) values).getLength() > 1;
     }
 
-    public boolean isSupported(Object target, Object[] positions, Object values) {
+    public boolean isSupported(RAbstractVector target, Object[] positions, Object values) {
         if (vectorClass == target.getClass() && values.getClass() == valueClass) {
             return positionsCheckNode.isSupported(positions) && isValueLengthGreaterThanOne(values) == isValueGt1;
         }
         return false;
     }
 
-    public Object apply(Object originalVector, Object[] originalPositions, Object originalValues) {
+    public Object apply(RAbstractVector originalVector, Object[] originalPositions, Object originalValues) {
         if (error != null) {
             CompilerDirectives.transferToInterpreter();
             error.run();
         }
-        final Object[] positions = filterPositions(originalPositions);
+        Object[] positions = filterPositions(originalPositions);
         assert isSupported(originalVector, positions, originalValues);
 
-        Object castVector = vectorClass.cast(originalVector);
+        RAbstractVector vector = vectorClass.cast(originalVector);
         Object castValue = valueClass.cast(originalValues);
 
-        if (vectorType == RType.Environment) {
-            return doEnvironment((REnvironment) castVector, positions, castValue);
-        } else if (vectorType == RType.S4Object) {
-            return doS4Object((RS4Object) castVector, positions, castValue);
-        }
-
-        Object value;
+        RAbstractContainer value;
         if (valueType == RType.Null) {
-            if (vectorType == RType.Null) {
-                // we cast Null to Logical, but in the end it will fold and return Null
-                value = RType.Logical.getEmpty();
-            } else if (castType == RType.List) {
+            if (castType == RType.List) {
                 value = RDataFactory.createList(new Object[]{DELETE_MARKER});
             } else {
                 value = castType.getEmpty();
             }
         } else {
-            value = castValue;
+            if ((castType == RType.List || castType == RType.Expression) && mode.isSubscript() && !isDeleteElements() && !(castValue instanceof RScalarVector)) {
+                // wrap into a list when
+                value = RScalarList.valueOf(castValue);
+            } else {
+                value = (RAbstractContainer) castValue;
+            }
         }
 
-        int appliedValueLength;
-        if (value instanceof RAbstractContainer) {
-            appliedValueLength = valueLengthProfile.profile(((RAbstractContainer) value).getLength());
-        } else {
-            appliedValueLength = 1;
-        }
+        int appliedValueLength = valueLengthProfile.profile(value.getLength());
 
         int valueLength;
         if (this.numberOfDimensions > 1 && isDeleteElements()) {
@@ -187,39 +203,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
             valueLength = appliedValueLength;
         }
 
-        if (vectorType == RType.Null) {
-            if (valueLength == 0) {
-                return RNull.instance;
-            }
-        }
-
-        /*
-         * Unfortunately special behavior for some RTypes are necessary. We should aim for getting
-         * rid of them as much as possible in the future. N.B.: because of this 'unwrapping' any
-         * return should call wrapResult(vector, repType) to do the reverse where necessary.
-         */
-        RAbstractVector vector;
-        RLanguage.RepType repType = RLanguage.RepType.UNKNOWN;
-        switch (vectorType) {
-            case Null:
-                vector = castType.getEmpty();
-                break;
-            case PairList:
-                vector = ((RPairList) castVector).toRList();
-                break;
-            case Language:
-                repType = RContext.getRRuntimeASTAccess().getRepType((RLanguage) castVector);
-                vector = RContext.getRRuntimeASTAccess().asList((RLanguage) castVector);
-                DynamicObject attrs = ((RLanguage) castVector).getAttributes();
-                if (rlanguageAttributesProfile.profile(attrs != null && !attrs.isEmpty())) {
-                    vector.initAttributes(RAttributesLayout.copy(attrs));
-                }
-                break;
-            default:
-                vector = (RAbstractVector) castVector;
-                break;
-        }
-
         int vectorLength = targetLengthProfile.profile(vector.getLength());
         int[] vectorDimensions;
         if (numberOfDimensions == 1) {
@@ -238,29 +221,30 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
 
         int replacementLength = positionsCheckNode.getSelectedPositionsCount(positionProfiles);
         if (emptyReplacementProfile.profile(replacementLength == 0)) {
-            /* Nothing to modify */
-            if (vectorType == RType.Language || vectorType == RType.Expression) {
-                return originalVector;
-            } else {
-                return vector.materialize();
-            }
+            // Nothing to modify
+            return vector;
         }
 
         if (valueLengthOneProfile.profile(valueLength != 1)) {
             verifyValueLength(positionProfiles, valueLength);
         }
-
-        if (!isList() && value instanceof RAbstractVector) {
-            value = ((RAbstractVector) value).castSafe(castType, valueIsNA, false);
+        if (vector instanceof RShareable) {
+            RShareable shareable = (RShareable) vector;
+            // TODO find out if we need to copy always in the recursive case
+            if (recursive || sharedConditionProfile.execute(shareable.isShared()) || valueEqualsVectorProfile.profile(vector == value)) {
+                shareable = (RShareable) vector.copy();
+                vector = (RAbstractVector) shareable;
+                assert shareable.isTemporary();
+            }
         }
-
-        vector = share(vector, value);
+        vector = sharedClassProfile.profile(vector);
+        CompilerAsserts.partialEvaluationConstant(vector.getClass());
 
         int maxOutOfBounds = positionsCheckNode.getMaxOutOfBounds(positionProfiles);
         if (maxOutOfBounds > vectorLength) {
             resizeProfile.enter();
             if (isDeleteElements() && mode.isSubscript()) {
-                return wrapResult(vector, repType);
+                return vector;
             }
             vector = resizeVector(vector, maxOutOfBounds);
         } else {
@@ -297,17 +281,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
             }
         }
 
-        if (value instanceof RAbstractContainer) {
-            writeVectorNode.enableValueNACheck((RAbstractContainer) value);
-        }
-
-        writeVectorNode.apply(vector, vectorLength, positions, value, appliedValueLength, vectorDimensions);
-        boolean complete = vector.isComplete();
-        if (completeVectorProfile.profile(complete)) {
-            if (!writeVectorNode.neverSeenNAInValue()) {
-                vector.setComplete(false);
-            }
-        }
+        writeVectorNode.execute(vector, positions, value, vectorDimensions);
 
         RBaseNode.reportWork(this, replacementLength);
 
@@ -320,48 +294,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
             updateVectorWithPositionNames(vector, positions);
         }
 
-        return wrapResult(vector, repType);
-    }
-
-    private Object wrapResult(RAbstractVector vector, RLanguage.RepType repType) {
-        switch (vectorType) {
-            case Language:
-                return RContext.getRRuntimeASTAccess().createLanguageFromList((RList) vector, repType);
-            default:
-                return vector;
-        }
-    }
-
-    private void verifyCastType(RType compatibleType) {
-        if (error == null && compatibleType == null && (vectorType.isNull() || vectorType.isVector())) {
-            Message message;
-            if (mode.isSubset()) {
-                message = RError.Message.SUBASSIGN_TYPE_FIX;
-            } else {
-                if (vectorType == RType.List) {
-                    message = RError.Message.SUBSCRIPT_TYPES;
-                } else {
-                    message = RError.Message.SUBASSIGN_TYPE_FIX;
-                }
-            }
-            error = () -> {
-                throw error(message, valueType.getName(), vectorType.getName(), false);
-            };
-        }
-    }
-
-    private CastNode createCastVectorNode() {
-        if (castType == vectorType || castType == null || castType == RType.Null) {
-            return null;
-        }
-        /*
-         * All casts except list casts preserve dimension names.
-         */
-        if (castType == RType.List) {
-            return CastListNodeGen.create(true, false, true);
-        } else {
-            return CastTypeNode.createCast(castType, true, true, true, false);
-        }
+        return vector;
     }
 
     private boolean isDeleteElements() {
@@ -372,54 +305,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
         return castType == RType.List;
     }
 
-    private RType resolveCastVectorType() {
-        final RType vector;
-        // convert type for list like values
-        switch (this.vectorType) {
-            case Language:
-            case Expression:
-            case PairList:
-                vector = RType.List;
-                break;
-            case Environment:
-                vector = RType.List;
-                break;
-            default:
-                vector = this.vectorType;
-                break;
-        }
-
-        RType value = this.valueType;
-
-        if (vector == RType.List && mode.isSubscript()) {
-            if (value.isNull() && numberOfDimensions > 1) {
-                return null;
-            } else {
-                return vector;
-            }
-        } else if (vector.isVector() && value.isVector()) {
-            if (vector != value) {
-                if (vector == RType.List || value == RType.List) {
-                    return RType.List;
-                }
-                if (vector == RType.Raw || value == RType.Raw) {
-                    return null;
-                }
-            }
-            return RType.maxPrecedence(value, vector);
-        } else if (vector.isNull() || value.isNull()) {
-            if (!value.isNull()) {
-                return (mode == ElementAccessMode.FIELD_SUBSCRIPT || (mode == ElementAccessMode.SUBSCRIPT && isValueGt1)) ? RType.List : value;
-            }
-            if (mode.isSubscript() && numberOfDimensions > 1) {
-                return null;
-            }
-            return vector;
-        } else {
-            return null;
-        }
-    }
-
     private void verifyValueLength(PositionProfile[] positionProfiles, int valueLength) {
         if (mode.isSubscript()) {
             if (!isList()) {
@@ -469,34 +354,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
         }
     }
 
-    private Object doEnvironment(REnvironment env, Object[] positions, Object originalValues) {
-        if (mode.isSubset()) {
-            throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName());
-        }
-
-        String positionString = tryCastSingleString(positionsCheckNode, positions);
-        if (positionString == null) {
-            throw error(RError.Message.WRONG_ARGS_SUBSET_ENV);
-        }
-
-        try {
-            Object value = originalValues;
-            if (value instanceof RScalarVector) {
-                value = ((RScalarVector) value).getDataAtAsObject(0);
-            }
-            env.put(positionString, value);
-        } catch (PutException ex) {
-            throw error(ex);
-        }
-        return env;
-    }
-
-    @Child private ReplaceS4ObjectNode replaceS4ObjectNode;
-
-    private Object doS4Object(RS4Object obj, Object[] positions, Object originalValues) {
-        return replaceS4ObjectNode.execute(obj, positions, originalValues);
-    }
-
     @NodeInfo(cost = NONE)
     public abstract static class ValueProfileNode extends Node {
 
@@ -520,28 +377,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
 
     private final ConditionProfile valueEqualsVectorProfile = ConditionProfile.createBinaryProfile();
 
-    /*
-     * TODO (chumer) share code between {@link #share(RAbstractVector)} and {@link
-     * #copyValueOnAssignment(RAbstractContainer)}
-     */
-    private RAbstractVector share(RAbstractVector vector, Object value) {
-        RAbstractVector returnVector = vector;
-        if (returnVector instanceof RShareable) {
-            RShareable shareable = (RShareable) returnVector;
-            // TODO find out if we need to copy always in the recursive case
-            if (recursive || sharedConditionProfile.execute(shareable.isShared()) || valueEqualsVectorProfile.profile(vector == value)) {
-                shareable = (RShareable) returnVector.copy();
-                returnVector = (RAbstractVector) shareable;
-                assert shareable.isTemporary();
-            }
-        }
-        returnVector = sharedClassProfile.profile(returnVector);
-
-        CompilerAsserts.partialEvaluationConstant(returnVector.getClass());
-
-        return returnVector;
-    }
-
     // TODO (chumer) this is way to complicated at the moment
     // not yet worth compiling. we should introduce some nodes for this
     @TruffleBoundary
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java
index 595c1452ef73f1fe6d3acff813ca57342c6b85fa..d9346356426458ac2c92f71dc664a4a5c7780476 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java
@@ -22,9 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.access.vector;
 
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
-import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RMissing;
@@ -56,9 +54,6 @@ abstract class CachedVectorNode extends RBaseNode {
     protected final int numberOfDimensions;
     private final int filteredPositionsLength;
 
-    // if this is non-null, the node needs to throw the error whenever it is executed
-    @CompilationFinal protected Runnable error;
-
     @Child private GetDimAttributeNode getDimNode = GetDimAttributeNode.create();
 
     CachedVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, boolean recursive) {
@@ -71,11 +66,6 @@ abstract class CachedVectorNode extends RBaseNode {
         } else {
             this.numberOfDimensions = filteredPositionsLength;
         }
-        if (!isSubsetable(vectorType)) {
-            error = () -> {
-                throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, vectorType.getName());
-            };
-        }
     }
 
     private static int initializeFilteredPositionsCount(Object[] positions) {
@@ -136,23 +126,6 @@ abstract class CachedVectorNode extends RBaseNode {
         }
     }
 
-    private static boolean isSubsetable(RType type) {
-        if (type.isVector()) {
-            return true;
-        }
-        switch (type) {
-            case Null:
-            case Language:
-            case PairList:
-            case Environment:
-            case Expression:
-            case S4Object:
-                return true;
-            default:
-                return false;
-        }
-    }
-
     protected final int[] loadVectorDimensions(RAbstractContainer vector) {
         // N.B. (stepan) this method used to be instance method and have special handling for
         // RDataFrame, which was removed and any test case, which would require this special
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractS4ObjectNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractS4ObjectNode.java
deleted file mode 100644
index 70df3131589553daab5ed53561f33f4a2fb20d76..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractS4ObjectNode.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.access.vector;
-
-import static com.oracle.truffle.r.runtime.RError.Message.OP_NOT_DEFINED_FOR_S4_CLASS;
-
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.nodes.objects.GetS4DataSlot;
-import com.oracle.truffle.r.nodes.objects.GetS4DataSlotNodeGen;
-import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RS4Object;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-
-public class ExtractS4ObjectNode extends Node {
-    @Child private GetS4DataSlot getS4DataSlotNode = GetS4DataSlotNodeGen.create(RType.Environment);
-    @Child private ExtractVectorNode extract;
-    private final boolean exact;
-    private final boolean dropDimensions;
-
-    public ExtractS4ObjectNode(ElementAccessMode accessMode, boolean exact, boolean dropDimensions) {
-        this.extract = ExtractVectorNode.create(accessMode, true);
-        this.exact = exact;
-        this.dropDimensions = dropDimensions;
-    }
-
-    public Object execute(RS4Object obj, Object[] positions) {
-        RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj);
-        if (dataSlot == RNull.instance) {
-            throw RError.error(RError.SHOW_CALLER, OP_NOT_DEFINED_FOR_S4_CLASS, "$");
-        }
-        return extract.execute(dataSlot, positions, createLogical(exact), createLogical(dropDimensions));
-    }
-
-    private static RAbstractLogicalVector createLogical(boolean b) {
-        return RDataFactory.createLogicalVectorFromScalar(b);
-    }
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java
index c3c7bcbd3519ee7244320a1c1d471a046e007950..54338db024c2be03c583839f28bf8b77641bb133 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java
@@ -23,8 +23,10 @@
 package com.oracle.truffle.r.nodes.access.vector;
 
 import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.interop.ForeignAccess;
@@ -34,20 +36,31 @@ import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.interop.java.JavaInterop;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNodeGen.ExtractSingleNameNodeGen;
 import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
+import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode;
+import com.oracle.truffle.r.nodes.objects.GetS4DataSlot;
 import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.FirstStringNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RMissing;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RS4Object;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
+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.RAbstractListVector;
 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.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
+import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.interop.Foreign2R;
 import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
 import com.oracle.truffle.r.runtime.interop.ForeignArray2R.ForeignArrayData;
@@ -58,7 +71,7 @@ public abstract class ExtractVectorNode extends RBaseNode {
 
     protected static final int CACHE_LIMIT = 5;
 
-    private final ElementAccessMode mode;
+    protected final ElementAccessMode mode;
     private final boolean recursive;
     private final boolean ignoreRecursive;
 
@@ -124,23 +137,92 @@ public abstract class ExtractVectorNode extends RBaseNode {
     }
 
     @Specialization(limit = "CACHE_LIMIT", guards = {"!isForeignObject(vector)", "cached != null", "cached.isSupported(vector, positions, exact, dropDimensions)"})
-    protected Object doExtractDefaultCached(Object vector, Object[] positions, Object exact, Object dropDimensions,  //
+    protected Object doExtractDefaultCached(RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions,  //
                     @Cached("createDefaultCache(getThis(), vector, positions, exact, dropDimensions)") CachedExtractVectorNode cached) {
         assert !isRecursiveSubscript(vector, positions);
         return cached.apply(vector, positions, null, exact, dropDimensions);
     }
 
-    protected static CachedExtractVectorNode createDefaultCache(ExtractVectorNode node, Object vector, Object[] positions, Object exact, Object dropDimensions) {
-        return new CachedExtractVectorNode(node.getMode(), (RTypedValue) vector, positions, (RTypedValue) exact, (RTypedValue) dropDimensions, node.recursive);
+    protected static CachedExtractVectorNode createDefaultCache(ExtractVectorNode node, RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions) {
+        assert !(vector instanceof REnvironment);
+        return new CachedExtractVectorNode(node.getMode(), vector, positions, (RTypedValue) exact, (RTypedValue) dropDimensions, node.recursive);
     }
 
-    @Specialization(replaces = "doExtractDefaultCached", guards = "!isForeignObject(vector)")
+    @Specialization(replaces = "doExtractDefaultCached", guards = {"!isForeignObject(vector)"})
     @TruffleBoundary
-    protected Object doExtractDefaultGeneric(Object vector, Object[] positions, Object exact, Object dropDimensions,  //
+    protected Object doExtractDefaultGeneric(RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions,  //
                     @Cached("new(createDefaultCache(getThis(), vector, positions, exact, dropDimensions))") GenericVectorExtractNode generic) {
         return generic.get(this, vector, positions, exact, dropDimensions).apply(vector, positions, null, exact, dropDimensions);
     }
 
+    @Specialization
+    protected Object doExtractEnvironment(REnvironment env, Object[] positions, @SuppressWarnings("unused") Object exact, @SuppressWarnings("unused") Object dropDimensions,
+                    @Cached("createExtractName()") ExtractSingleName extractName,
+                    @Cached("new()") PromiseCheckHelperNode promiseHelper) {
+        if (mode.isSubset()) {
+            throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName());
+        }
+        String name = positions.length == 1 ? extractName.execute(positions[0]) : null;
+        if (name != null) {
+            Object obj = env.get(name);
+            return obj == null ? RNull.instance : promiseHelper.checkEvaluate(null, obj);
+        }
+        throw error(RError.Message.WRONG_ARGS_SUBSET_ENV);
+    }
+
+    @Specialization
+    protected Object doExtractS4Object(RS4Object obj, Object[] positions, Object exact, Object dropDimensions,
+                    @Cached("createEnvironment()") GetS4DataSlot getS4DataSlotNode,
+                    @Cached("create(mode, True)") ExtractVectorNode recursiveExtract) {
+        RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj);
+        if (dataSlot == RNull.instance) {
+            throw RError.error(RError.SHOW_CALLER, RError.Message.OP_NOT_DEFINED_FOR_S4_CLASS, "$");
+        }
+        return recursiveExtract.execute(dataSlot, positions, exact, dropDimensions);
+    }
+
+    abstract static class ExtractSingleName extends Node {
+
+        public abstract String execute(Object value);
+
+        public static ExtractSingleName createExtractName() {
+            return ExtractSingleNameNodeGen.create();
+        }
+
+        @Specialization
+        protected static String extract(String value) {
+            return value;
+        }
+
+        @Specialization(guards = "access.supports(value)")
+        protected static String extractCached(RAbstractStringVector value,
+                        @Cached("value.access()") VectorAccess access) {
+            try (RandomIterator iter = access.randomAccess(value)) {
+                if (access.getLength(iter) == 1) {
+                    return access.getString(iter, 0);
+                }
+            }
+            return null;
+        }
+
+        @Specialization(replaces = "extractCached")
+        @TruffleBoundary
+        protected static String extractGeneric(RAbstractStringVector value) {
+            return extractCached(value, value.slowPathAccess());
+        }
+
+        @Fallback
+        protected static String extractFallback(@SuppressWarnings("unused") Object value) {
+            return null;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    @Specialization
+    protected Object doExtractRNull(RNull vector, Object[] positions, Object exact, Object dropDimensions) {
+        return RNull.instance;
+    }
+
     // TODO hack until Truffle-DSL supports this.
     protected ExtractVectorNode getThis() {
         return this;
@@ -154,7 +236,7 @@ public abstract class ExtractVectorNode extends RBaseNode {
             this.cached = insert(cachedOperation);
         }
 
-        public CachedExtractVectorNode get(ExtractVectorNode node, Object vector, Object[] positions, Object exact, Object dropDimensions) {
+        public CachedExtractVectorNode get(ExtractVectorNode node, RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions) {
             CompilerAsserts.neverPartOfCompilation();
             if (!cached.isSupported(vector, positions, exact, dropDimensions)) {
                 cached = cached.replace(createDefaultCache(node, vector, positions, exact, dropDimensions));
@@ -251,4 +333,11 @@ public abstract class ExtractVectorNode extends RBaseNode {
     private static TruffleObject toJavaClass(TruffleObject obj) {
         return JavaInterop.toJavaClass(obj);
     }
+
+    @SuppressWarnings("unused")
+    @Fallback
+    protected Object access(Object object, Object[] positions, Object exact, Object dropDimensions) {
+        CompilerDirectives.transferToInterpreter();
+        throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, Predef.typeName().apply(object));
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceS4ObjectNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceS4ObjectNode.java
deleted file mode 100644
index afc04f304e9af843de7d835e03a384c1e7808832..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceS4ObjectNode.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.access.vector;
-
-import static com.oracle.truffle.r.runtime.RError.Message.NO_METHOD_ASSIGNING_SUBSET_S4;
-
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.nodes.objects.GetS4DataSlot;
-import com.oracle.truffle.r.nodes.objects.GetS4DataSlotNodeGen;
-import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RS4Object;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
-
-public class ReplaceS4ObjectNode extends Node {
-    @Child private GetS4DataSlot getS4DataSlotNode = GetS4DataSlotNodeGen.create(RType.Environment);
-    @Child private ReplaceVectorNode replaceVectorNode;
-
-    public ReplaceS4ObjectNode(ElementAccessMode mode, boolean ignoreRecursive) {
-        replaceVectorNode = ReplaceVectorNode.create(mode, ignoreRecursive);
-    }
-
-    public Object execute(RS4Object obj, Object[] positions, Object values) {
-        RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj);
-        if (dataSlot == RNull.instance) {
-            throw RError.error(RError.SHOW_CALLER, NO_METHOD_ASSIGNING_SUBSET_S4);
-        }
-        // No need to update the data slot, the value is env and they have reference semantics.
-        replaceVectorNode.execute(dataSlot, positions, values);
-        return obj;
-    }
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java
index f295281ded9fb2cd67094d7e21c4367b724dcc31..9d78ec148542ba97349f5f5ee30a1ae1b22b24a3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java
@@ -23,31 +23,49 @@
 package com.oracle.truffle.r.nodes.access.vector;
 
 import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.InteropException;
 import com.oracle.truffle.api.interop.KeyInfo;
-import com.oracle.truffle.api.interop.Message;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.interop.java.JavaInterop;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.object.DynamicObject;
+import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode.ExtractSingleName;
 import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
+import com.oracle.truffle.r.nodes.objects.GetS4DataSlot;
 import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.FirstStringNode;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RAttributesLayout;
+import com.oracle.truffle.r.runtime.data.RLanguage;
+import com.oracle.truffle.r.runtime.data.RLanguage.RepType;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RPairList;
+import com.oracle.truffle.r.runtime.data.RS4Object;
+import com.oracle.truffle.r.runtime.data.RScalarVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
+import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector;
 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.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
 import com.oracle.truffle.r.runtime.interop.R2Foreign;
-import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
@@ -58,9 +76,9 @@ public abstract class ReplaceVectorNode extends RBaseNode {
 
     protected static final int CACHE_LIMIT = 5;
 
-    private final ElementAccessMode mode;
+    protected final ElementAccessMode mode;
     private final boolean recursive;
-    private final boolean ignoreRecursive;
+    protected final boolean ignoreRecursive;
 
     @Child private BoxPrimitiveNode boxVector = BoxPrimitiveNode.create();
     @Child private BoxPrimitiveNode boxValue = BoxPrimitiveNode.create();
@@ -81,23 +99,177 @@ public abstract class ReplaceVectorNode extends RBaseNode {
         return ReplaceVectorNodeGen.create(mode, false, ignoreRecursive);
     }
 
-    static ReplaceVectorNode createRecursive(ElementAccessMode mode) {
+    protected static ReplaceVectorNode createRecursive(ElementAccessMode mode) {
         return ReplaceVectorNodeGen.create(mode, true, false);
     }
 
-    protected Node createForeignWrite(Object[] positions) {
-        if (positions.length != 1) {
-            throw error(RError.Message.GENERIC, "Invalid number positions for foreign access.");
+    private boolean isRecursiveSubscript(Object vector, Object[] positions) {
+        return !recursive && !ignoreRecursive && mode.isSubscript() && vector instanceof RAbstractListVector && positions.length == 1;
+    }
+
+    protected RecursiveReplaceSubscriptNode createRecursiveCache(Object vector, Object[] positions) {
+        if (isRecursiveSubscript(vector, positions)) {
+            return RecursiveReplaceSubscriptNode.create((RAbstractListVector) vector, positions[0]);
         }
-        return Message.WRITE.createNode();
+        return null;
     }
 
-    protected FirstStringNode createFirstString() {
-        return FirstStringNode.createWithError(RError.Message.GENERIC, "Cannot corce position to character for foreign access.");
+    @Specialization(limit = "CACHE_LIMIT", guards = {"!isForeignObject(vector)", "cached != null", "cached.isSupported(vector, positions)"})
+    protected Object doRecursive(RAbstractListVector vector, Object[] positions, Object value,  //
+                    @Cached("createRecursiveCache(vector, positions)") RecursiveReplaceSubscriptNode cached) {
+        return cached.apply(vector, positions, value);
+    }
+
+    protected CachedReplaceVectorNode createDefaultCached(RAbstractVector vector, Object[] positions, Object value) {
+        if (vector instanceof RAbstractListVector && isRecursiveSubscript(vector, positions)) {
+            return null;
+        }
+        return new CachedReplaceVectorNode(mode, vector, positions, value.getClass(), RRuntime.isForeignObject(value) ? RType.TruffleObject : ((RTypedValue) value).getRType(), true,
+                        recursive, CachedReplaceVectorNode.isValueLengthGreaterThanOne(value));
+    }
+
+    @Specialization(limit = "CACHE_LIMIT", guards = {"!isForeignObject(vector)", "cached != null", "cached.isSupported(vector, positions, value)"})
+    protected Object doReplaceCached(RAbstractVector vector, Object[] positions, Object value,  //
+                    @Cached("createDefaultCached(vector, positions, value)") CachedReplaceVectorNode cached) {
+        assert !isRecursiveSubscript(vector, positions);
+        return cached.apply(vector, positions, value);
+    }
+
+    @Specialization
+    @TruffleBoundary
+    protected Object doReplaceEnvironment(REnvironment env, Object[] positions, Object value,
+                    @Cached("createExtractName()") ExtractSingleName extractName) {
+        if (mode.isSubset()) {
+            throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName());
+        }
+        String name = positions.length == 1 ? extractName.execute(positions[0]) : null;
+        if (name != null) {
+            try {
+                env.put(name, value instanceof RScalarVector ? ((RScalarVector) value).getDataAtAsObject(0) : value);
+            } catch (PutException ex) {
+                throw error(ex);
+            }
+        }
+        return env;
+    }
+
+    @Specialization
+    @TruffleBoundary
+    protected Object doReplaceS4Object(RS4Object obj, Object[] positions, Object value,
+                    @Cached("createEnvironment()") GetS4DataSlot getS4DataSlotNode,
+                    @Cached("create(mode, ignoreRecursive)") ReplaceVectorNode recursiveReplace) {
+        RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj);
+        if (dataSlot == RNull.instance) {
+            throw RError.error(RError.SHOW_CALLER, RError.Message.NO_METHOD_ASSIGNING_SUBSET_S4);
+        }
+        // No need to update the data slot, the value is env and they have reference semantics.
+        recursiveReplace.execute(dataSlot, positions, value);
+        return obj;
+    }
+
+    protected ReplaceVectorNode createForContainerTypes() {
+        return ReplaceVectorNodeGen.create(mode, false, false);
+    }
+
+    @Specialization
+    protected Object doReplacementNull(@SuppressWarnings("unused") RNull vector, Object[] positions, Object value,
+                    @Cached("createForContainerTypes()") ReplaceVectorNode replace) {
+        /*
+         * Replacing inside a variable containing NULL is quite inconsistent, we try to emulate the
+         * behavior as good as possible.
+         */
+        if (value == RNull.instance) {
+            return RNull.instance;
+        }
+        RType type;
+        switch (mode) {
+            case FIELD_SUBSCRIPT:
+                type = RType.List;
+                break;
+            case SUBSCRIPT:
+                if (value instanceof RAbstractAtomicVector && ((RAbstractAtomicVector) value).getLength() == 1) {
+                    type = ((RAbstractAtomicVector) value).getRType();
+                } else {
+                    type = RType.List;
+                }
+                break;
+            case SUBSET:
+                if (value instanceof RAbstractAtomicVector) {
+                    if (((RAbstractAtomicVector) value).getLength() == 0) {
+                        return RNull.instance;
+                    } else {
+                        type = ((RAbstractAtomicVector) value).getRType();
+                    }
+                } else {
+                    type = RType.List;
+                }
+                break;
+            default:
+                throw RInternalError.shouldNotReachHere();
+        }
+        return replace.execute(type.getEmpty(), positions, value);
+    }
+
+    @Specialization
+    @TruffleBoundary
+    protected Object doReplacementLanguage(RLanguage vector, Object[] positions, Object value,
+                    @Cached("createForContainerTypes()") ReplaceVectorNode replace) {
+        RepType repType = RContext.getRRuntimeASTAccess().getRepType(vector);
+        RList result = RContext.getRRuntimeASTAccess().asList(vector);
+        DynamicObject attrs = vector.getAttributes();
+        if (attrs != null && !attrs.isEmpty()) {
+            result.initAttributes(RAttributesLayout.copy(attrs));
+        }
+        result = (RList) replace.execute(result, positions, value);
+        return RContext.getRRuntimeASTAccess().createLanguageFromList(result, repType);
+    }
+
+    @Specialization
+    @TruffleBoundary
+    protected Object doReplacementPairList(RPairList vector, Object[] positions, Object value,
+                    @Cached("createForContainerTypes()") ReplaceVectorNode replace) {
+        return replace.execute(vector.toRList(), positions, value);
+    }
+
+    protected static GenericVectorReplaceNode createGeneric() {
+        return new GenericVectorReplaceNode();
+    }
+
+    @Specialization(replaces = "doReplaceCached", guards = "!isForeignObject(vector)")
+    @TruffleBoundary
+    protected Object doReplaceDefaultGeneric(RAbstractVector vector, Object[] positions, Object value,  //
+                    @Cached("createGeneric()") GenericVectorReplaceNode generic) {
+        if (vector instanceof RAbstractListVector && isRecursiveSubscript(vector, positions)) {
+            return generic.getRecursive(this, vector, positions).apply(vector, positions, value);
+        } else {
+            return generic.get(this, vector, positions, value).apply(vector, positions, value);
+        }
+    }
+
+    protected static final class GenericVectorReplaceNode extends TruffleBoundaryNode {
+
+        @Child private RecursiveReplaceSubscriptNode cachedRecursive;
+        @Child private CachedReplaceVectorNode cached;
+
+        private RecursiveReplaceSubscriptNode getRecursive(ReplaceVectorNode node, Object vector, Object[] positions) {
+            CompilerAsserts.neverPartOfCompilation();
+            if (cachedRecursive == null || !cachedRecursive.isSupported(vector, positions)) {
+                cachedRecursive = insert(node.createRecursiveCache(vector, positions));
+            }
+            return cachedRecursive;
+        }
+
+        private CachedReplaceVectorNode get(ReplaceVectorNode node, RAbstractVector vector, Object[] positions, Object value) {
+            CompilerAsserts.neverPartOfCompilation();
+            if (cached == null || !cached.isSupported(vector, positions, value)) {
+                cached = insert(node.createDefaultCached(vector, positions, value));
+            }
+            return cached;
+        }
     }
 
-    protected R2Foreign createR2Foreign() {
-        return R2ForeignNodeGen.create();
+    protected FirstStringNode createFirstString() {
+        return FirstStringNode.createWithError(RError.Message.GENERIC, "Cannot corce position to character for foreign access.");
     }
 
     @Specialization(guards = {"isForeignObject(object)", "positions.length == cachedLength"})
@@ -109,7 +281,7 @@ public abstract class ReplaceVectorNode extends RBaseNode {
                     @SuppressWarnings("unused") @Cached("positions.length") int cachedLength,
                     @Cached("create()") CastStringNode castNode,
                     @Cached("createFirstString()") FirstStringNode firstString,
-                    @Cached("createR2Foreign()") R2Foreign r2Foreign) {
+                    @Cached("create()") R2Foreign r2Foreign) {
         Object writtenValue = value;
         try {
             TruffleObject result = object;
@@ -163,65 +335,10 @@ public abstract class ReplaceVectorNode extends RBaseNode {
         return JavaInterop.toJavaClass(obj);
     }
 
-    @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(vector, positions)"})
-    protected Object doRecursive(RAbstractListVector vector, Object[] positions, Object value,  //
-                    @Cached("createRecursiveCache(vector, positions)") RecursiveReplaceSubscriptNode cached) {
-        return cached.apply(vector, positions, value);
-    }
-
-    protected RecursiveReplaceSubscriptNode createRecursiveCache(Object vector, Object[] positions) {
-        if (isRecursiveSubscript(vector, positions)) {
-            return RecursiveReplaceSubscriptNode.create((RAbstractListVector) vector, positions[0]);
-        }
-        return null;
-    }
-
-    private boolean isRecursiveSubscript(Object vector, Object[] positions) {
-        return !recursive && !ignoreRecursive && mode.isSubscript() && vector instanceof RAbstractListVector && positions.length == 1;
-    }
-
-    @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(vector, positions, value)"})
-    protected Object doReplaceCached(Object vector, Object[] positions, Object value,  //
-                    @Cached("createDefaultCached(getThis(), vector, positions, value)") CachedReplaceVectorNode cached) {
-        assert !isRecursiveSubscript(vector, positions);
-        return cached.apply(vector, positions, value);
-    }
-
-    protected static CachedReplaceVectorNode createDefaultCached(ReplaceVectorNode node, Object vector, Object[] positions, Object value) {
-        return new CachedReplaceVectorNode(node.mode, (RTypedValue) vector, positions, value.getClass(), RRuntime.isForeignObject(value) ? RType.TruffleObject : ((RTypedValue) value).getRType(), true,
-                        node.recursive, node.ignoreRecursive, CachedReplaceVectorNode.isValueLengthGreaterThanOne(value));
-    }
-
-    public ElementAccessMode getMode() {
-        return mode;
-    }
-
-    @Specialization(replaces = "doReplaceCached")
-    @TruffleBoundary
-    protected Object doReplaceDefaultGeneric(Object vector, Object[] positions, Object value,  //
-                    @Cached("new(createDefaultCached(getThis(), vector, positions, value))") GenericVectorReplaceNode generic) {
-        return generic.get(this, vector, positions, value).apply(vector, positions, value);
-    }
-
-    // TODO hack until Truffle-DSL supports this.
-    protected ReplaceVectorNode getThis() {
-        return this;
-    }
-
-    protected static final class GenericVectorReplaceNode extends TruffleBoundaryNode {
-
-        @Child private CachedReplaceVectorNode cached;
-
-        public GenericVectorReplaceNode(CachedReplaceVectorNode cachedOperation) {
-            this.cached = insert(cachedOperation);
-        }
-
-        private CachedReplaceVectorNode get(ReplaceVectorNode node, Object vector, Object[] positions, Object value) {
-            CompilerAsserts.neverPartOfCompilation();
-            if (!cached.isSupported(vector, positions, value)) {
-                cached = cached.replace(createDefaultCached(node, vector, positions, value));
-            }
-            return cached;
-        }
+    @SuppressWarnings("unused")
+    @Fallback
+    protected Object access(Object object, Object[] positions, Object value) {
+        CompilerDirectives.transferToInterpreter();
+        throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, Predef.typeName().apply(object));
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java
index aecab8b403bb429c8b83a54b1f5f561f191b12bd..28666c2bfe310626240eaa6f4f3086ec88b1b0ab 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.access.vector;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
@@ -35,33 +36,84 @@ import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
 import com.oracle.truffle.r.nodes.profile.AlwaysOnBranchProfile;
 import com.oracle.truffle.r.nodes.profile.IntValueProfile;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
-import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
-import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RIntSequence;
 import com.oracle.truffle.r.runtime.data.RMissing;
-import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RScalarVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 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.RAbstractListBaseVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
+abstract class WriteIndexedVectorNode extends Node {
+
+    private final RType vectorType;
+    private final int totalDimensions;
+    private final int dimensionIndex;
+    private final boolean positionAppliesToRight;
+    private final boolean skipNA;
+    private final boolean isReplace;
+
+    private final ConditionProfile completeVectorProfile = ConditionProfile.createBinaryProfile();
+
+    protected WriteIndexedVectorNode(RType vectorType, int totalDimensions, int dimensionIndex, boolean positionAppliesToRight, boolean skipNA, boolean isReplace) {
+        this.vectorType = vectorType;
+        this.totalDimensions = totalDimensions;
+        this.dimensionIndex = dimensionIndex;
+        this.positionAppliesToRight = positionAppliesToRight;
+        this.skipNA = skipNA;
+        this.isReplace = isReplace;
+    }
+
+    public static WriteIndexedVectorNode create(RType vectorType, int totalDimensions, boolean positionAppliesToValue, boolean skipNA, boolean isReplace) {
+        return WriteIndexedVectorNodeGen.create(vectorType, totalDimensions, totalDimensions - 1, positionAppliesToValue, skipNA, isReplace);
+    }
+
+    protected abstract void execute(RAbstractVector left, Object[] positions, RAbstractContainer right, int[] positionTargetDimensions);
+
+    protected WriteIndexedVectorAccessNode createWrite() {
+        return WriteIndexedVectorAccessNodeGen.create(vectorType, totalDimensions, dimensionIndex, positionAppliesToRight, skipNA, isReplace);
+    }
+
+    @Specialization(guards = {"leftAccess.supports(left)", "rightAccess.supports(right)"})
+    protected void write(RAbstractVector left, Object[] positions, RAbstractContainer right, int[] positionTargetDimensions,
+                    @Cached("left.access()") VectorAccess leftAccess,
+                    @Cached("right.access()") VectorAccess rightAccess,
+                    @Cached("createWrite()") WriteIndexedVectorAccessNode write) {
+        try (RandomIterator leftIter = leftAccess.randomAccess(left); RandomIterator rightIter = rightAccess.randomAccess(right)) {
+            write.apply(leftIter, leftAccess, positions, rightIter, rightAccess, right, positionTargetDimensions);
+
+            if (completeVectorProfile.profile(left.isComplete())) {
+                if (!(leftAccess.na.neverSeenNA() && rightAccess.na.neverSeenNA())) {
+                    left.setComplete(false);
+                }
+            }
+        }
+    }
+
+    @Specialization(replaces = "write")
+    @TruffleBoundary
+    protected void writeGeneric(RAbstractVector left, Object[] positions, RAbstractContainer right, int[] positionTargetDimensions,
+                    @Cached("createWrite()") WriteIndexedVectorAccessNode write) {
+        VectorAccess leftAccess = left.slowPathAccess();
+        VectorAccess rightAccess = right.slowPathAccess();
+        try (RandomIterator leftIter = leftAccess.randomAccess(left); RandomIterator rightIter = rightAccess.randomAccess(right)) {
+            write.apply(leftIter, leftAccess, positions, rightIter, rightAccess, right, positionTargetDimensions);
+        }
+    }
+}
+
 /**
  * Primitive indexed N-dimensional vector write node. It can be used for vector replaces and
  * extracts. The only difference is that replace indexes the left vector and extract indexes the
  * right vector. The index direction is indicated with the boolean flag
  * {@link #positionsApplyToRight}.
  */
-abstract class WriteIndexedVectorNode extends Node {
+abstract class WriteIndexedVectorAccessNode extends Node {
 
     private final int dimensionIndex;
     private final int totalDimensions;
@@ -84,57 +136,39 @@ abstract class WriteIndexedVectorNode extends Node {
     private final NACheck positionNACheck = NACheck.create();
     private final ConditionProfile resetIndexProfile = ConditionProfile.createBinaryProfile();
 
-    @Child private WriteIndexedScalarNode<RAbstractVector, Object> scalarNode;
-    @Child private WriteIndexedVectorNode innerVectorNode;
+    @Child private WriteIndexedVectorAccessNode innerVectorNode;
+
+    @Child private UpdateShareableChildValueNode updateStateOfListElement;
+    @Child private ShareObjectNode shareObjectNode;
 
-    @SuppressWarnings("unchecked")
-    protected WriteIndexedVectorNode(RType vectorType, int totalDimensions, int dimensionIndex, boolean positionAppliesToRight, boolean skipNA, boolean setListElementAsObject, boolean isReplace) {
-        this.scalarNode = (WriteIndexedScalarNode<RAbstractVector, Object>) createIndexedAction(vectorType, setListElementAsObject, isReplace);
+    private final boolean isReplace;
+    private final RType vectorType;
+
+    protected WriteIndexedVectorAccessNode(RType vectorType, int totalDimensions, int dimensionIndex, boolean positionAppliesToRight, boolean skipNA, boolean isReplace) {
+        this.vectorType = vectorType;
         this.dimensionIndex = dimensionIndex;
         this.totalDimensions = totalDimensions;
         this.positionsApplyToRight = positionAppliesToRight;
         this.skipNA = skipNA;
+        this.isReplace = isReplace;
         if (dimensionIndex > 0) {
-            innerVectorNode = WriteIndexedVectorNodeGen.create(vectorType, totalDimensions, dimensionIndex - 1, positionAppliesToRight, skipNA, setListElementAsObject, isReplace);
-        }
-    }
-
-    public static WriteIndexedVectorNode create(RType vectorType, int totalDimensions, boolean positionAppliesToValue, boolean skipNA, boolean setListElementAsObject, boolean isReplace) {
-        return WriteIndexedVectorNodeGen.create(vectorType, totalDimensions, totalDimensions - 1, positionAppliesToValue, skipNA, setListElementAsObject, isReplace);
-    }
-
-    public NACheck getValueNACheck() {
-        return scalarNode.valueNACheck;
-    }
-
-    public void enableValueNACheck(RAbstractContainer vector) {
-        getValueNACheck().enable(vector);
-        if (innerVectorNode != null) {
-            innerVectorNode.enableValueNACheck(vector);
+            innerVectorNode = WriteIndexedVectorAccessNodeGen.create(vectorType, totalDimensions, dimensionIndex - 1, positionAppliesToRight, skipNA, isReplace);
         }
-    }
-
-    public boolean neverSeenNAInValue() {
-        if (getValueNACheck().neverSeenNA()) {
-            if (innerVectorNode == null || innerVectorNode.neverSeenNAInValue()) {
-                return true;
+        if (vectorType == RType.List || vectorType == RType.Expression) {
+            if (!isReplace) {
+                updateStateOfListElement = UpdateShareableChildValueNode.create();
+            } else {
+                shareObjectNode = ShareObjectNode.create();
             }
         }
-        return false;
     }
 
-    public final void apply(RAbstractVector left, int leftLength,
-                    Object[] positions, Object right, int rightLength, int[] positionTargetDimensions) {
-        assert left.getLength() == leftLength;
+    public void apply(RandomIterator leftIter, VectorAccess leftAccess, Object[] positions, RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right,
+                    int[] positionTargetDimensions) {
         assert totalDimensions == positions.length : "totalDimensions must be constant per vector write node";
 
-        Object leftStore = left.getInternalStore();
-        Object rightStore = null;
-        if (right instanceof RAbstractContainer) {
-            RAbstractContainer rightContainer = (RAbstractContainer) right;
-            assert rightContainer.getLength() == rightLength;
-            rightStore = rightContainer.getInternalStore();
-        }
+        int leftLength = leftAccess.getLength(leftIter);
+        int rightLength = rightAccess.getLength(rightIter);
 
         int initialPositionOffset;
         if (positionsApplyToRight) {
@@ -151,17 +185,17 @@ abstract class WriteIndexedVectorNode extends Node {
             firstTargetDimension = dimensionValueProfile.profile(positionTargetDimensions[dimensionIndex]);
         }
 
-        applyImpl(left, leftStore, 0, leftLength, positionTargetDimensions, firstTargetDimension,
+        applyImpl(leftIter, leftAccess, 0, leftLength, positionTargetDimensions, firstTargetDimension,
                         positions, initialPositionOffset,
-                        right, rightStore, 0, rightLength, false);
+                        rightIter, rightAccess, right, 0, rightLength, false);
     }
 
     private final ConditionProfile positionMatchesTargetDimensionsProfile = ConditionProfile.createBinaryProfile();
 
     private int applyImpl(//
-                    RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, int targetDimension,
+                    RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, int targetDimension,
                     Object[] positions, int positionOffset,
-                    Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA) {
+                    RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA) {
 
         Object position = positionClassProfile.profile(positions[dimensionIndex]);
 
@@ -172,9 +206,9 @@ abstract class WriteIndexedVectorNode extends Node {
         } else {
             newPositionOffset = positionOffsetProfile.profile(positionOffset / targetDimension);
         }
-        return execute(left, leftStore, leftBase, leftLength, targetDimensions, targetDimension,
+        return execute(leftIter, leftAccess, leftBase, leftLength, targetDimensions, targetDimension,
                         positions, position, newPositionOffset, positionLength,
-                        right, rightStore, rightBase, rightLength, parentNA);
+                        rightIter, rightAccess, right, rightBase, rightLength, parentNA);
     }
 
     private int getPositionLength(Object position) {
@@ -185,30 +219,30 @@ abstract class WriteIndexedVectorNode extends Node {
         }
     }
 
-    protected abstract int execute(RAbstractVector left, Object leftStore, int storeBase, int storeLength, Object targetDimensions, int targetDimension,
+    protected abstract int execute(RandomIterator leftIter, VectorAccess leftAccess, int storeBase, int storeLength, Object targetDimensions, int targetDimension,
                     Object[] positions, Object position, int positionOffset, int positionLength,
-                    Object right, Object rightStore, int valueBase, int valueLength, boolean parentNA);
+                    RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int valueBase, int valueLength, boolean parentNA);
 
     @Specialization
-    protected int doMissing(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, int targetDimension,
+    protected int doMissing(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, int targetDimension,
                     Object[] positions, @SuppressWarnings("unused") RMissing position, int positionOffset, @SuppressWarnings("unused") int positionLength,
-                    RAbstractContainer right, Object rightStore, int rightBase, int rightLength, boolean parentNA,
+                    RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA,
                     @Cached("createCountingProfile()") LoopConditionProfile profile) {
         int rightIndex = rightBase;
         profile.profileCounted(targetDimension);
         for (int positionValue = 0; profile.inject(positionValue < targetDimension); positionValue += 1) {
             rightIndex = applyInner(//
-                            left, leftStore, leftBase, leftLength, targetDimensions,
+                            leftIter, leftAccess, leftBase, leftLength, targetDimensions,
                             positions, positionOffset, positionValue,
-                            right, rightStore, rightLength, rightIndex, parentNA);
+                            rightIter, rightAccess, right, rightLength, rightIndex, parentNA);
         }
         return rightIndex;
     }
 
     @Specialization
-    protected int doLogicalPosition(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, int targetDimension,
+    protected int doLogicalPosition(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, int targetDimension,
                     Object[] positions, RAbstractLogicalVector position, int positionOffset, int positionLength,
-                    Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA,
+                    RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA,
                     @Cached("create()") BranchProfile wasTrue,
                     @Cached("create()") AlwaysOnBranchProfile outOfBounds,
                     @Cached("createCountingProfile()") LoopConditionProfile profile,
@@ -235,9 +269,9 @@ abstract class WriteIndexedVectorNode extends Node {
                         isNA = true;
                     }
                     rightIndex = applyInner(//
-                                    left, leftStore, leftBase, leftLength, targetDimensions,
+                                    leftIter, leftAccess, leftBase, leftLength, targetDimensions,
                                     positions, positionOffset, i,
-                                    right, rightStore, rightLength, rightIndex, isNA || parentNA);
+                                    rightIter, rightAccess, right, rightLength, rightIndex, isNA || parentNA);
                 }
                 positionIndex = Utils.incMod(positionIndex, positionLength, incModProfile);
             }
@@ -251,9 +285,9 @@ abstract class WriteIndexedVectorNode extends Node {
      * @throws SlowPathException
      */
     @Specialization(rewriteOn = SlowPathException.class)
-    protected int doIntegerSequencePosition(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension,
+    protected int doIntegerSequencePosition(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension,
                     Object[] positions, RIntSequence position, int positionOffset, int positionLength,
-                    Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA,
+                    RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA,
                     @Cached("create()") IntValueProfile startProfile,
                     @Cached("create()") IntValueProfile strideProfile,
                     @Cached("createBinaryProfile()") ConditionProfile conditionProfile,
@@ -272,27 +306,22 @@ abstract class WriteIndexedVectorNode extends Node {
         profile.profileCounted(positionLength);
         for (int positionValue = start; profile.inject(ascending ? positionValue < end : positionValue > end); positionValue += stride) {
             rightIndex = applyInner(//
-                            left, leftStore, leftBase, leftLength, targetDimensions,
+                            leftIter, leftAccess, leftBase, leftLength, targetDimensions,
                             positions, positionOffset, positionValue,
-                            right, rightStore, rightLength, rightIndex, parentNA);
+                            rightIter, rightAccess, right, rightLength, rightIndex, parentNA);
         }
         return rightIndex;
     }
 
     /**
      * Integer vectors iterate over the number of positions because we assume that the number of
-     * positions in an integer vector is significantly lower than the number of elements in the
-     * store. This might not be always true and could benefit from more investigation.
-     */
-    /**
-     * Integer vectors iterate over the number of positions because we assume that the number of
-     * positions in an integer vector is significantly lower than the number of elements in the
-     * store. This might not be always true and could benefit from more investigation.
+     * positions in an integer vector is significantly lower than the number of elements. This might
+     * not be always true and could benefit from more investigation.
      */
     @Specialization(replaces = "doIntegerSequencePosition")
-    protected int doIntegerPosition(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension,
+    protected int doIntegerPosition(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension,
                     Object[] positions, RAbstractIntVector position, int positionOffset, int positionLength,
-                    Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA,
+                    RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA,
                     @Cached("createCountingProfile()") LoopConditionProfile lengthProfile) {
         positionNACheck.enable(position);
         int rightIndex = rightBase;
@@ -307,17 +336,17 @@ abstract class WriteIndexedVectorNode extends Node {
                 }
             }
             rightIndex = applyInner(//
-                            left, leftStore, leftBase, leftLength, targetDimensions,
+                            leftIter, leftAccess, leftBase, leftLength, targetDimensions,
                             positions, positionOffset, positionValue - 1,
-                            right, rightStore, rightLength, rightIndex, isNA || parentNA);
+                            rightIter, rightAccess, right, rightLength, rightIndex, isNA || parentNA);
         }
         return rightIndex;
     }
 
     private int applyInner(//
-                    RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions,
+                    RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions,
                     Object[] positions, int positionOffset, int positionValue,
-                    Object right, Object rightStore, int rightLength, int actionIndex, boolean isNA) {
+                    RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightLength, int actionIndex, boolean isNA) {
         int newTargetIndex = leftBase + positionValue * positionOffset;
         if (dimensionIndex == 0) {
             // for-loops leaf for innermost dimension
@@ -334,9 +363,15 @@ abstract class WriteIndexedVectorNode extends Node {
             }
 
             if (isNA) {
-                scalarNode.applyNA(left, leftStore, actionLeftIndex);
+                leftAccess.setNA(leftIter, actionLeftIndex);
+                leftAccess.na.seenNA();
             } else {
-                scalarNode.apply(left, leftStore, actionLeftIndex, right, rightStore, actionRightIndex);
+                if (vectorType == RType.List || vectorType == RType.Expression) {
+                    setListElement(leftIter, leftAccess, rightIter, rightAccess, right, actionLeftIndex, actionRightIndex);
+                } else {
+                    leftAccess.setFromSameType(leftIter, actionLeftIndex, rightAccess, rightIter, actionRightIndex);
+                }
+                rightAccess.isNA(rightIter, actionRightIndex);
             }
 
             if (resetIndexProfile.profile((actionIndex + 1) == (positionsApplyToRight ? leftLength : rightLength))) {
@@ -347,189 +382,24 @@ abstract class WriteIndexedVectorNode extends Node {
             // generate another for-loop for other dimensions
             int nextTargetDimension = innerVectorNode.dimensionValueProfile.profile(((int[]) targetDimensions)[innerVectorNode.dimensionIndex]);
             return innerVectorNode.applyImpl(//
-                            left, leftStore, newTargetIndex, leftLength, targetDimensions, nextTargetDimension,
+                            leftIter, leftAccess, newTargetIndex, leftLength, targetDimensions, nextTargetDimension,
                             positions, positionOffset,
-                            right, rightStore, actionIndex, rightLength, isNA);
-        }
-    }
-
-    private static WriteIndexedScalarNode<? extends RAbstractVector, ? extends Object> createIndexedAction(RType type, boolean setListElementAsObject, boolean isReplace) {
-        switch (type) {
-            case Logical:
-                return new WriteLogicalAction();
-            case Integer:
-                return new WriteIntegerAction();
-            case Double:
-                return new WriteDoubleAction();
-            case Complex:
-                return new WriteComplexAction();
-            case Character:
-                return new WriteCharacterAction();
-            case Raw:
-                return new WriteRawAction();
-            case Language:
-            case Expression:
-            case PairList:
-            case List:
-                return new WriteListAction(setListElementAsObject, isReplace);
-            default:
-                throw RInternalError.shouldNotReachHere("WriteIndexedScalarNode for " + type);
-        }
-    }
-
-    private abstract static class WriteIndexedScalarNode<A extends RAbstractVector, V extends Object> extends Node {
-
-        final NACheck valueNACheck = NACheck.create();
-
-        abstract void apply(A leftAccess, Object leftStore, int leftIndex, V rightAccess, Object rightStore, int rightIndex);
-
-        abstract void applyNA(A leftAccess, Object leftStore, int leftIndex);
-
-    }
-
-    private static final class WriteLogicalAction extends WriteIndexedScalarNode<RAbstractLogicalVector, RAbstractLogicalVector> {
-
-        @Override
-        void apply(RAbstractLogicalVector leftAccess, Object leftStore, int leftIndex, RAbstractLogicalVector rightAccess, Object rightStore, int rightIndex) {
-            byte value = rightAccess.getDataAt(rightStore, rightIndex);
-            leftAccess.setDataAt(leftStore, leftIndex, value);
-            valueNACheck.check(value);
-        }
-
-        @Override
-        void applyNA(RAbstractLogicalVector leftAccess, Object leftStore, int leftIndex) {
-            leftAccess.setDataAt(leftStore, leftIndex, RRuntime.LOGICAL_NA);
-            valueNACheck.seenNA();
-        }
-    }
-
-    private static final class WriteIntegerAction extends WriteIndexedScalarNode<RAbstractIntVector, RAbstractIntVector> {
-
-        @Override
-        void apply(RAbstractIntVector leftAccess, Object leftStore, int leftIndex, RAbstractIntVector rightAccess, Object rightStore, int rightIndex) {
-            int value = rightAccess.getDataAt(rightStore, rightIndex);
-            leftAccess.setDataAt(leftStore, leftIndex, value);
-            valueNACheck.check(value);
-        }
-
-        @Override
-        void applyNA(RAbstractIntVector leftAccess, Object leftStore, int leftIndex) {
-            leftAccess.setDataAt(leftStore, leftIndex, RRuntime.INT_NA);
-            valueNACheck.seenNA();
-        }
-    }
-
-    private static final class WriteDoubleAction extends WriteIndexedScalarNode<RAbstractDoubleVector, RAbstractDoubleVector> {
-
-        @Override
-        void apply(RAbstractDoubleVector leftAccess, Object leftStore, int leftIndex, RAbstractDoubleVector rightAccess, Object rightStore, int rightIndex) {
-            double value = rightAccess.getDataAt(rightStore, rightIndex);
-            leftAccess.setDataAt(leftStore, leftIndex, value);
-            valueNACheck.check(value);
-        }
-
-        @Override
-        void applyNA(RAbstractDoubleVector leftAccess, Object leftStore, int leftIndex) {
-            leftAccess.setDataAt(leftStore, leftIndex, RRuntime.DOUBLE_NA);
-            valueNACheck.seenNA();
-        }
-    }
-
-    private static final class WriteComplexAction extends WriteIndexedScalarNode<RAbstractComplexVector, RAbstractComplexVector> {
-
-        @Override
-        void apply(RAbstractComplexVector leftAccess, Object leftStore, int leftIndex, RAbstractComplexVector rightAccess, Object rightStore, int rightIndex) {
-            RComplex value = rightAccess.getDataAt(rightStore, rightIndex);
-            leftAccess.setDataAt(leftStore, leftIndex, value);
-            valueNACheck.check(value);
-        }
-
-        @Override
-        void applyNA(RAbstractComplexVector leftAccess, Object leftStore, int leftIndex) {
-            leftAccess.setDataAt(leftStore, leftIndex, RComplex.createNA());
-            valueNACheck.seenNA();
+                            rightIter, rightAccess, right, actionIndex, rightLength, isNA);
         }
     }
 
-    private static final class WriteCharacterAction extends WriteIndexedScalarNode<RAbstractStringVector, RAbstractStringVector> {
-
-        @Override
-        void apply(RAbstractStringVector leftAccess, Object leftStore, int leftIndex, RAbstractStringVector rightAccess, Object rightStore, int rightIndex) {
-            String value = rightAccess.getDataAt(rightStore, rightIndex);
-            leftAccess.setDataAt(leftStore, leftIndex, value);
-            valueNACheck.check(value);
-        }
-
-        @Override
-        void applyNA(RAbstractStringVector leftAccess, Object leftStore, int leftIndex) {
-            leftAccess.setDataAt(leftStore, leftIndex, RRuntime.STRING_NA);
-            valueNACheck.seenNA();
-        }
-    }
-
-    private static final class WriteRawAction extends WriteIndexedScalarNode<RAbstractRawVector, RAbstractRawVector> {
-
-        @Override
-        void apply(RAbstractRawVector leftAccess, Object leftStore, int leftIndex, RAbstractRawVector rightAccess, Object rightStore, int rightIndex) {
-            byte value = rightAccess.getRawDataAt(rightStore, rightIndex);
-            leftAccess.setRawDataAt(leftStore, leftIndex, value);
-            valueNACheck.check(value);
-        }
-
-        @Override
-        void applyNA(RAbstractRawVector leftAccess, Object leftStore, int leftIndex) {
-            // nothing to do
-        }
-    }
-
-    private static final class WriteListAction extends WriteIndexedScalarNode<RAbstractListBaseVector, Object> {
-
-        private final boolean setListElementAsObject;
-        private final boolean isReplace;
-        @Child private UpdateShareableChildValueNode updateStateOfListElement;
-        @Child private ShareObjectNode shareObjectNode;
-
-        WriteListAction(boolean setListElementAsObject, boolean isReplace) {
-            this.setListElementAsObject = setListElementAsObject;
-            this.isReplace = isReplace;
-            if (!isReplace) {
-                updateStateOfListElement = UpdateShareableChildValueNode.create();
-            } else {
-                shareObjectNode = ShareObjectNode.create();
+    private void setListElement(RandomIterator leftIter, VectorAccess leftAccess, RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int leftIndex, int rightIndex) {
+        Object rightValue = rightAccess.getListElement(rightIter, rightIndex);
+        if (isReplace) {
+            // we are replacing within the same list
+            if (leftAccess.getListElement(leftIter, leftIndex) != rightValue) {
+                shareObjectNode.execute(rightValue);
             }
+        } else {
+            // we are writing into a list data that are being read from possibly another list
+            updateStateOfListElement.execute(right, rightValue);
         }
 
-        @Override
-        void apply(RAbstractListBaseVector leftAccess, Object leftStore, int leftIndex, Object rightAccess, Object rightStore, int rightIndex) {
-            Object rightValue;
-            if (setListElementAsObject) {
-                rightValue = rightAccess;
-                // unbox scalar vectors
-                if (rightValue instanceof RScalarVector) {
-                    rightValue = ((RScalarVector) rightValue).getDataAtAsObject(rightStore, 0);
-                }
-            } else {
-                rightValue = ((RAbstractContainer) rightAccess).getDataAtAsObject(rightStore, rightIndex);
-            }
-
-            if (isReplace) {
-                // we are replacing within the same list
-                if (leftAccess.getDataAtAsObject(leftStore, leftIndex) != rightValue) {
-                    shareObjectNode.execute(rightValue);
-                }
-            } else {
-                // we are writing into a list data that are being read from possibly another list
-                updateStateOfListElement.execute(rightAccess, rightValue);
-            }
-
-            leftAccess.setDataAt(leftStore, leftIndex, rightValue);
-            valueNACheck.checkListElement(rightValue);
-        }
-
-        @Override
-        void applyNA(RAbstractListBaseVector leftAccess, Object leftStore, int leftIndex) {
-            leftAccess.setDataAt(leftStore, leftIndex, RNull.instance);
-            valueNACheck.seenNA();
-        }
+        leftAccess.setListElement(leftIter, leftIndex, rightValue);
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
index 6af290e8b548d3f283e78459085726d2507c3bb6..96d5b62296049ad4bc60fde9876f0c20d9535a03 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
@@ -87,29 +87,27 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 {
     }
 
     @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(left, right)"})
-    protected Object doNumericVectorCached(Object left, Object right,
+    protected Object doNumericVectorCached(RAbstractVector left, RAbstractVector right,
                     @Cached("createFastCached(left, right)") BinaryMapNode cached) {
         return cached.apply(left, right);
     }
 
     @Specialization(replaces = "doNumericVectorCached", guards = {"isNumericVector(left)", "isNumericVector(right)"})
     @TruffleBoundary
-    protected Object doNumericVectorGeneric(Object left, Object right,
+    protected Object doNumericVectorGeneric(RAbstractVector left, RAbstractVector right,
                     @Cached("binary.createOperation()") BinaryArithmetic arithmetic,
-                    @Cached("new(createCached(arithmetic, left, right))") GenericNumericVectorNode generic) {
-        RAbstractVector leftVector = (RAbstractVector) left;
-        RAbstractVector rightVector = (RAbstractVector) right;
-        return generic.get(arithmetic, leftVector, rightVector).apply(leftVector, rightVector);
+                    @Cached("createGeneric()") GenericNumericVectorNode generic) {
+        return generic.get(arithmetic, left, right).apply(left, right);
     }
 
-    protected BinaryMapNode createFastCached(Object left, Object right) {
+    protected BinaryMapNode createFastCached(RAbstractVector left, RAbstractVector right) {
         if (isNumericVector(left) && isNumericVector(right)) {
-            return createCached(binary.createOperation(), left, right);
+            return createCached(binary.createOperation(), left, right, false);
         }
         return null;
     }
 
-    protected static boolean isNumericVector(Object value) {
+    protected static boolean isNumericVector(RAbstractVector value) {
         return value instanceof RAbstractIntVector || value instanceof RAbstractDoubleVector || value instanceof RAbstractComplexVector || value instanceof RAbstractLogicalVector;
     }
 
@@ -133,19 +131,19 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 {
     }
 
     @Specialization(guards = {"isNumericVector(right)"})
-    protected Object doLeftNull(@SuppressWarnings("unused") RNull left, Object right,
+    protected Object doLeftNull(@SuppressWarnings("unused") RNull left, RAbstractVector right,
                     @Cached("createClassProfile()") ValueProfile classProfile) {
-        RType rType = ((RAbstractVector) classProfile.profile(right)).getRType();
-        if (rType == RType.Complex) {
+        RType type = classProfile.profile(right).getRType();
+        if (type == RType.Complex) {
             return RDataFactory.createEmptyComplexVector();
         } else {
-            if (rType == RType.Integer || rType == RType.Logical) {
+            if (type == RType.Integer || type == RType.Logical) {
                 if (operation instanceof BinaryArithmetic.Div || operation instanceof BinaryArithmetic.Pow) {
                     return RType.Double.getEmpty();
                 } else {
                     return RType.Integer.getEmpty();
                 }
-            } else if (rType == RType.Double) {
+            } else if (type == RType.Double) {
                 return RType.Double.getEmpty();
             } else {
                 throw error(Message.NON_NUMERIC_BINARY);
@@ -154,7 +152,7 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 {
     }
 
     @Specialization(guards = {"isNumericVector(left)"})
-    protected Object doRightNull(Object left, RNull right,
+    protected Object doRightNull(RAbstractVector left, RNull right,
                     @Cached("createClassProfile()") ValueProfile classProfile) {
         return doLeftNull(right, left, classProfile);
     }
@@ -164,7 +162,7 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 {
         throw error(Message.NON_NUMERIC_BINARY);
     }
 
-    protected static BinaryMapNode createCached(BinaryArithmetic innerArithmetic, Object left, Object right) {
+    protected static BinaryMapNode createCached(BinaryArithmetic innerArithmetic, Object left, Object right, boolean isGeneric) {
         RAbstractVector leftVector = (RAbstractVector) left;
         RAbstractVector rightVector = (RAbstractVector) right;
 
@@ -174,22 +172,22 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 {
             resultType = RType.Double;
         }
 
-        return BinaryMapNode.create(new BinaryMapArithmeticFunctionNode(innerArithmetic), leftVector, rightVector, argumentType, resultType, true);
+        return BinaryMapNode.create(new BinaryMapArithmeticFunctionNode(innerArithmetic), leftVector, rightVector, argumentType, resultType, true, isGeneric);
+    }
+
+    protected static GenericNumericVectorNode createGeneric() {
+        return new GenericNumericVectorNode();
     }
 
     protected static final class GenericNumericVectorNode extends TruffleBoundaryNode {
 
         @Child private BinaryMapNode cached;
 
-        public GenericNumericVectorNode(BinaryMapNode cachedOperation) {
-            this.cached = insert(cachedOperation);
-        }
-
         public BinaryMapNode get(BinaryArithmetic arithmetic, RAbstractVector left, RAbstractVector right) {
             CompilerAsserts.neverPartOfCompilation();
             BinaryMapNode map = cached;
-            if (!map.isSupported(left, right)) {
-                cached = map = map.replace(createCached(arithmetic, left, right));
+            if (map == null || !map.isSupported(left, right)) {
+                cached = map = insert(createCached(arithmetic, left, right, true));
             }
             return map;
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
index bae281a74708b2017a5659fe5a48430fa37bf444..b367673e3376d89d14d59cd085f5ee232c0b4cbd 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
@@ -104,24 +104,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode.Arg2 {
     }
 
     @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(left, right)"})
-    protected Object doNumericVectorCached(Object left, Object right,
+    protected Object doNumericVectorCached(RAbstractVector left, RAbstractVector right,
                     @Cached("createFastCached(left, right)") BinaryMapNode cached) {
         return cached.apply(left, right);
     }
 
     @Specialization(replaces = "doNumericVectorCached", guards = "isSupported(left, right)")
     @TruffleBoundary
-    protected Object doNumericVectorGeneric(Object left, Object right,
+    protected Object doNumericVectorGeneric(RAbstractVector left, RAbstractVector right,
                     @Cached("factory.createOperation()") BooleanOperation operation,
-                    @Cached("new(createCached(operation, left, right))") GenericNumericVectorNode generic) {
-        RAbstractVector leftVector = (RAbstractVector) left;
-        RAbstractVector rightVector = (RAbstractVector) right;
-        return generic.get(operation, leftVector, rightVector).apply(leftVector, rightVector);
+                    @Cached("createGeneric()") GenericNumericVectorNode generic) {
+        return generic.get(operation, left, right).apply(left, right);
     }
 
     protected BinaryMapNode createFastCached(Object left, Object right) {
         if (isSupported(left, right)) {
-            return createCached(factory.createOperation(), left, right);
+            return createCached(factory.createOperation(), left, right, false);
         }
         return null;
     }
@@ -243,7 +241,7 @@ public abstract class BinaryBooleanNode extends RBuiltinNode.Arg2 {
         throw error(Message.OPERATIONS_NUMERIC_LOGICAL_COMPLEX);
     }
 
-    protected static BinaryMapNode createCached(BooleanOperation operation, Object left, Object right) {
+    protected static BinaryMapNode createCached(BooleanOperation operation, Object left, Object right, boolean isGeneric) {
         RAbstractVector leftVector = (RAbstractVector) left;
         RAbstractVector rightVector = (RAbstractVector) right;
 
@@ -255,23 +253,24 @@ public abstract class BinaryBooleanNode extends RBuiltinNode.Arg2 {
             resultType = RType.Logical;
         }
 
-        return BinaryMapNode.create(new BinaryMapBooleanFunctionNode(operation), leftVector, rightVector, argumentType, resultType, false);
+        return BinaryMapNode.create(new BinaryMapBooleanFunctionNode(operation), leftVector, rightVector, argumentType, resultType, false, isGeneric);
+    }
+
+    protected static GenericNumericVectorNode createGeneric() {
+        return new GenericNumericVectorNode();
     }
 
     protected static final class GenericNumericVectorNode extends TruffleBoundaryNode {
 
         @Child private BinaryMapNode cached;
 
-        public GenericNumericVectorNode(BinaryMapNode cachedOperation) {
-            this.cached = insert(cachedOperation);
-        }
-
         private BinaryMapNode get(BooleanOperation arithmetic, RAbstractVector left, RAbstractVector right) {
             CompilerAsserts.neverPartOfCompilation();
-            if (!cached.isSupported(left, right)) {
-                cached = cached.replace(createCached(arithmetic, left, right));
+            BinaryMapNode map = cached;
+            if (map == null || !map.isSupported(left, right)) {
+                cached = map = insert(createCached(arithmetic, left, right, true));
             }
-            return cached;
+            return map;
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
index e0c252dfd5387ebc560c2f338682add035352804..037b7b409d29b3cb39e93ba4cd6dba9da5156f9f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
@@ -299,48 +299,49 @@ public final class PipelineToCastNode {
 
         @Override
         public ArgumentFilter<?, ?> visit(RTypeFilter<?> filter, ArgumentFilter<?, ?> previous) {
-            if (filter.getType() == RType.Integer) {
-                return new ArgumentFilter<Object, Object>() {
-                    private final ConditionProfile profile = ConditionProfile.createBinaryProfile();
-
-                    @Override
-                    public boolean test(Object x) {
-                        return profile.profile(x instanceof Integer) || x instanceof RAbstractIntVector;
-                    }
-                };
-            } else if (filter.getType() == RType.Double) {
-                return new ArgumentFilter<Object, Object>() {
-                    private final ConditionProfile profile = ConditionProfile.createBinaryProfile();
-
-                    @Override
-                    public boolean test(Object x) {
-                        return profile.profile(x instanceof Double) || x instanceof RAbstractDoubleVector;
-                    }
-                };
-            } else if (filter.getType() == RType.Logical) {
-                return new ArgumentFilter<Object, Object>() {
-                    private final ConditionProfile profile = ConditionProfile.createBinaryProfile();
-
-                    @Override
-                    public boolean test(Object x) {
-                        return profile.profile(x instanceof Byte) || x instanceof RAbstractLogicalVector;
-                    }
-                };
-            } else if (filter.getType() == RType.Complex) {
-                return x -> x instanceof RAbstractComplexVector;
-            } else if (filter.getType() == RType.Character) {
-                return new ArgumentFilter<Object, Object>() {
-                    private final ConditionProfile profile = ConditionProfile.createBinaryProfile();
-
-                    @Override
-                    public boolean test(Object x) {
-                        return profile.profile(x instanceof String) || x instanceof RAbstractStringVector;
-                    }
-                };
-            } else if (filter.getType() == RType.Raw) {
-                return x -> x instanceof RAbstractRawVector;
-            } else {
-                throw RInternalError.unimplemented("TODO: more types here");
+            switch (filter.getType()) {
+                case Integer:
+                    return new ArgumentFilter<Object, Object>() {
+                        private final ConditionProfile profile = ConditionProfile.createBinaryProfile();
+
+                        @Override
+                        public boolean test(Object x) {
+                            return profile.profile(x instanceof Integer) || x instanceof RAbstractIntVector;
+                        }
+                    };
+                case Double:
+                    return new ArgumentFilter<Object, Object>() {
+                        private final ConditionProfile profile = ConditionProfile.createBinaryProfile();
+
+                        @Override
+                        public boolean test(Object x) {
+                            return profile.profile(x instanceof Double) || x instanceof RAbstractDoubleVector;
+                        }
+                    };
+                case Logical:
+                    return new ArgumentFilter<Object, Object>() {
+                        private final ConditionProfile profile = ConditionProfile.createBinaryProfile();
+
+                        @Override
+                        public boolean test(Object x) {
+                            return profile.profile(x instanceof Byte) || x instanceof RAbstractLogicalVector;
+                        }
+                    };
+                case Complex:
+                    return x -> x instanceof RAbstractComplexVector;
+                case Character:
+                    return new ArgumentFilter<Object, Object>() {
+                        private final ConditionProfile profile = ConditionProfile.createBinaryProfile();
+
+                        @Override
+                        public boolean test(Object x) {
+                            return profile.profile(x instanceof String) || x instanceof RAbstractStringVector;
+                        }
+                    };
+                case Raw:
+                    return x -> x instanceof RAbstractRawVector;
+                default:
+                    throw RInternalError.unimplemented("type " + filter.getType());
             }
         }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java
index 8498a61289235f2e0c4de993b38c06492030a46f..7a3866e37c07060d7d91c0874338fefd8e6f67b0 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java
@@ -200,11 +200,11 @@ public abstract class ForNode extends AbstractLoopNode implements RSyntaxNode, R
         return createLoopNode(new ForIndexRepeatingNode(this, var.getIdentifier(), RASTUtils.cloneNode(body), indexName, lengthName, rangeName));
     }
 
-    private LoopNode createLoopNode(AbstractRepeatingNode n) {
+    private static LoopNode createLoopNode(AbstractRepeatingNode n) {
         return Truffle.getRuntime().createLoopNode(n);
     }
 
-    private TruffleObject getIterator(TruffleObject obj, Node readNode, Node executeNode) {
+    private static TruffleObject getIterator(TruffleObject obj, Node readNode, Node executeNode) {
         assert ForeignArray2R.isJavaIterable(obj);
         try {
             TruffleObject itFun = (TruffleObject) ForeignAccess.sendRead(readNode, obj, "iterator");
@@ -214,7 +214,7 @@ public abstract class ForNode extends AbstractLoopNode implements RSyntaxNode, R
         }
     }
 
-    private int getKeysLength(TruffleObject keys, Node sizeNode) {
+    private static int getKeysLength(TruffleObject keys, Node sizeNode) {
         try {
             return (int) ForeignAccess.sendGetSize(sizeNode, keys);
         } catch (UnsupportedMessageException ex) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
index 74d41d8ec674bbe75c785baf3bcf2bfe096fffd4..243858790910424768d6deb86ac0510659900f49 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
@@ -58,9 +58,9 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  * Holds {@link RPromise}-related functionality that cannot be implemented in
  * "com.oracle.truffle.r.runtime.data" due to package import restrictions.
  */
-public class PromiseHelperNode extends RBaseNode {
+public final class PromiseHelperNode extends RBaseNode {
 
-    public static class PromiseCheckHelperNode extends RBaseNode {
+    public static final class PromiseCheckHelperNode extends RBaseNode {
 
         @Child private PromiseHelperNode promiseHelper;
 
@@ -81,7 +81,7 @@ public class PromiseHelperNode extends RBaseNode {
         }
     }
 
-    public static class PromiseDeoptimizeFrameNode extends RBaseNode {
+    public static final class PromiseDeoptimizeFrameNode extends RBaseNode {
         private final BranchProfile deoptimizeProfile = BranchProfile.create();
 
         /**
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java
index dd6ba6f6a16f2c99731e4d0a9f662530dc94afbb..2d5361356d9f10c047f8789210694473da303f1d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java
@@ -54,7 +54,7 @@ public abstract class AsS4 extends Node {
             if (complete != 0) {
                 if (getS4DataSlot == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
-                    getS4DataSlot = insert(GetS4DataSlotNodeGen.create(RType.Any));
+                    getS4DataSlot = insert(GetS4DataSlot.create(RType.Any));
 
                 }
                 RTypedValue value = getS4DataSlot.executeObject(obj);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java
index 6d2ca9ae16f77f59d89a0f82797bd97cd367ec40..37827a9f33541330ddb84de42102c0d30d1d285c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java
@@ -13,7 +13,6 @@
 package com.oracle.truffle.r.nodes.objects;
 
 import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
@@ -32,9 +31,7 @@ import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 
 // transcribed from src/main/attrib.c
-public abstract class GetS4DataSlot extends Node {
-
-    public abstract RTypedValue executeObject(RAttributable attObj);
+public final class GetS4DataSlot extends Node {
 
     @Child private GetFixedAttributeNode s3ClassAttrAccess;
     @Child private RemoveFixedAttributeNode s3ClassAttrRemove;
@@ -48,12 +45,19 @@ public abstract class GetS4DataSlot extends Node {
 
     private final RType type;
 
-    protected GetS4DataSlot(RType type) {
+    private GetS4DataSlot(RType type) {
         this.type = type;
     }
 
-    @Specialization
-    protected RTypedValue doNewObject(RAttributable attrObj) {
+    public static GetS4DataSlot create(RType type) {
+        return new GetS4DataSlot(type);
+    }
+
+    public static GetS4DataSlot createEnvironment() {
+        return new GetS4DataSlot(RType.Environment);
+    }
+
+    public RTypedValue executeObject(RAttributable attrObj) {
         RAttributable obj = attrObj;
         Object value = null;
         if (!(obj instanceof RS4Object) || type == RType.S4Object) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
index a77f74f63d9ab98891b5b20991a0594958294612..51200dd1cf40613c23a7d68ef8b432764d1a3eec 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
@@ -22,8 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.primitive;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
@@ -31,7 +31,6 @@ import com.oracle.truffle.r.nodes.attributes.CopyAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.CopyAttributesNodeGen;
 import com.oracle.truffle.r.nodes.attributes.HasFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
-import com.oracle.truffle.r.nodes.primitive.BinaryMapNodeFactory.VectorMapBinaryInternalNodeGen;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -42,110 +41,229 @@ import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.RScalarVector;
 import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-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.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.data.nodes.GetDataStore;
-import com.oracle.truffle.r.runtime.data.nodes.SetDataAt;
-import com.oracle.truffle.r.runtime.data.nodes.VectorIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
-/**
- * Implements a binary map operation that maps two vectors into a single result vector of the
- * maximum size of both vectors. Vectors with smaller length are repeated. The actual implementation
- * is provided using a {@link BinaryMapFunctionNode}.
- *
- * The implementation tries to share input vectors if they are implementing {@link RShareable}.
- */
-public final class BinaryMapNode extends RBaseNode {
+final class BinaryMapScalarNode extends BinaryMapNode {
+
+    @Child private VectorAccess leftAccess;
+    @Child private VectorAccess rightAccess;
+
+    BinaryMapScalarNode(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType) {
+        super(function, left, right, argumentType, resultType);
+        this.leftAccess = left.access();
+        this.rightAccess = right.access();
+    }
+
+    @Override
+    public boolean isSupported(RAbstractVector left, RAbstractVector right) {
+        return leftAccess.supports(left) && rightAccess.supports(right);
+    }
+
+    @Override
+    public Object apply(RAbstractVector originalLeft, RAbstractVector originalRight) {
+        assert isSupported(originalLeft, originalRight);
+        RAbstractVector left = leftClass.cast(originalLeft);
+        RAbstractVector right = rightClass.cast(originalRight);
+        try (RandomIterator leftIter = leftAccess.randomAccess(left); RandomIterator rightIter = rightAccess.randomAccess(right)) {
+
+            assert left != null;
+            assert right != null;
+            function.enable(left, right);
+            assert leftAccess.getLength(leftIter) == 1;
+            assert rightAccess.getLength(rightIter) == 1;
+
+            switch (argumentType) {
+                case Raw:
+                    byte leftValueRaw = leftAccess.getRaw(leftIter, 0);
+                    byte rightValueRaw = rightAccess.getRaw(rightIter, 0);
+                    switch (resultType) {
+                        case Raw:
+                            return RRaw.valueOf(function.applyRaw(leftValueRaw, rightValueRaw));
+                        case Logical:
+                            return function.applyLogical(RRuntime.raw2int(leftValueRaw), RRuntime.raw2int(rightValueRaw));
+                        default:
+                            throw RInternalError.shouldNotReachHere();
+                    }
+                case Logical:
+                    byte leftValueLogical = leftAccess.getLogical(leftIter, 0);
+                    byte rightValueLogical = rightAccess.getLogical(rightIter, 0);
+                    return function.applyLogical(leftValueLogical, rightValueLogical);
+                case Integer:
+                    int leftValueInt = leftAccess.getInt(leftIter, 0);
+                    int rightValueInt = rightAccess.getInt(rightIter, 0);
+                    switch (resultType) {
+                        case Logical:
+                            return function.applyLogical(leftValueInt, rightValueInt);
+                        case Integer:
+                            return function.applyInteger(leftValueInt, rightValueInt);
+                        case Double:
+                            return function.applyDouble(leftValueInt, rightValueInt);
+                        default:
+                            throw RInternalError.shouldNotReachHere();
+                    }
+                case Double:
+                    double leftValueDouble = leftAccess.getDouble(leftIter, 0);
+                    double rightValueDouble = rightAccess.getDouble(rightIter, 0);
+                    switch (resultType) {
+                        case Logical:
+                            return function.applyLogical(leftValueDouble, rightValueDouble);
+                        case Double:
+                            return function.applyDouble(leftValueDouble, rightValueDouble);
+                        default:
+                            throw RInternalError.shouldNotReachHere();
+                    }
+                case Complex:
+                    RComplex leftValueComplex = leftAccess.getComplex(leftIter, 0);
+                    RComplex rightValueComplex = rightAccess.getComplex(rightIter, 0);
+                    switch (resultType) {
+                        case Logical:
+                            return function.applyLogical(leftValueComplex, rightValueComplex);
+                        case Complex:
+                            return function.applyComplex(leftValueComplex, rightValueComplex);
+                        default:
+                            throw RInternalError.shouldNotReachHere();
+                    }
+                case Character:
+                    String leftValueString = leftAccess.getString(leftIter, 0);
+                    String rightValueString = rightAccess.getString(rightIter, 0);
+                    switch (resultType) {
+                        case Logical:
+                            return function.applyLogical(leftValueString, rightValueString);
+                        default:
+                            throw RInternalError.shouldNotReachHere();
+                    }
+                default:
+                    throw RInternalError.shouldNotReachHere();
+            }
+        }
+    }
+}
+
+final class BinaryMapVectorNode extends BinaryMapNode {
 
     @Child private VectorMapBinaryInternalNode vectorNode;
-    @Child private BinaryMapFunctionNode function;
     @Child private CopyAttributesNode copyAttributes;
     @Child private GetDimAttributeNode getLeftDimNode = GetDimAttributeNode.create();
     @Child private GetDimAttributeNode getRightDimNode = GetDimAttributeNode.create();
     @Child private HasFixedAttributeNode hasLeftDimNode = HasFixedAttributeNode.createDim();
     @Child private HasFixedAttributeNode hasRightDimNode = HasFixedAttributeNode.createDim();
 
+    @Child private VectorAccess fastLeftAccess;
+    @Child private VectorAccess fastRightAccess;
+    @Child private VectorAccess resultAccess;
+
     // profiles
-    private final Class<? extends RAbstractVector> leftClass;
-    private final Class<? extends RAbstractVector> rightClass;
-    private final VectorLengthProfile leftLengthProfile = VectorLengthProfile.create();
-    private final VectorLengthProfile rightLengthProfile = VectorLengthProfile.create();
+    private final VectorLengthProfile leftLengthProfile;
+    private final VectorLengthProfile rightLengthProfile;
     private final ConditionProfile dimensionsProfile;
     private final ConditionProfile maxLengthProfile;
-    private final ConditionProfile leftIsNAProfile = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile rightIsNAProfile = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile seenEmpty = ConditionProfile.createBinaryProfile();
+    private final ConditionProfile seenEmpty;
     private final ConditionProfile shareLeft;
     private final ConditionProfile shareRight;
-    private final RType argumentType;
-    private final RType resultType;
+    private final ConditionProfile leftIsNAProfile;
+    private final ConditionProfile rightIsNAProfile;
 
     // compile-time optimization flags
-    private final boolean scalarTypes;
     private final boolean mayContainMetadata;
     private final boolean mayFoldConstantTime;
     private final boolean mayShareLeft;
     private final boolean mayShareRight;
-
-    private BinaryMapNode(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType, boolean copyAttributes) {
-        this.function = function;
-        this.leftClass = left.getClass();
-        this.rightClass = right.getClass();
+    private final boolean isGeneric;
+
+    BinaryMapVectorNode(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType, boolean copyAttributes, boolean isGeneric) {
+        super(function, left, right, argumentType, resultType);
+        this.leftLengthProfile = VectorLengthProfile.create();
+        this.rightLengthProfile = VectorLengthProfile.create();
+        this.seenEmpty = ConditionProfile.createBinaryProfile();
+        this.fastLeftAccess = isGeneric ? null : left.access();
+        this.fastRightAccess = isGeneric ? null : right.access();
         this.vectorNode = VectorMapBinaryInternalNode.create(resultType, argumentType);
-        this.scalarTypes = left instanceof RScalarVector && right instanceof RScalarVector;
         boolean leftVectorImpl = RVector.class.isAssignableFrom(leftClass);
         boolean rightVectorImpl = RVector.class.isAssignableFrom(rightClass);
         this.mayContainMetadata = leftVectorImpl || rightVectorImpl;
         this.mayFoldConstantTime = function.mayFoldConstantTime(leftClass, rightClass);
+        this.leftIsNAProfile = mayFoldConstantTime ? ConditionProfile.createBinaryProfile() : null;
+        this.rightIsNAProfile = mayFoldConstantTime ? ConditionProfile.createBinaryProfile() : null;
         this.mayShareLeft = left.getRType() == resultType && leftVectorImpl;
         this.mayShareRight = right.getRType() == resultType && rightVectorImpl;
-        this.argumentType = argumentType;
-        this.resultType = resultType;
-        this.maxLengthProfile = ConditionProfile.createBinaryProfile();
-
         // lazily create profiles only if needed to avoid unnecessary allocations
         this.shareLeft = mayShareLeft ? ConditionProfile.createBinaryProfile() : null;
         this.shareRight = mayShareRight ? ConditionProfile.createBinaryProfile() : null;
         this.dimensionsProfile = mayContainMetadata ? ConditionProfile.createBinaryProfile() : null;
 
         this.copyAttributes = mayContainMetadata ? CopyAttributesNodeGen.create(copyAttributes) : null;
+        this.maxLengthProfile = ConditionProfile.createBinaryProfile();
+        this.isGeneric = isGeneric;
     }
 
-    public static BinaryMapNode create(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType, boolean copyAttributes) {
-        return new BinaryMapNode(function, left, right, argumentType, resultType, copyAttributes);
-    }
-
-    public boolean isSupported(Object left, Object right) {
-        return left.getClass() == leftClass && right.getClass() == rightClass;
+    @Override
+    public boolean isSupported(RAbstractVector left, RAbstractVector right) {
+        return left.getClass() == leftClass && right.getClass() == rightClass && (isGeneric || fastLeftAccess.supports(left) && fastRightAccess.supports(right));
     }
 
-    public Object apply(Object originalLeft, Object originalRight) {
+    @Override
+    public Object apply(RAbstractVector originalLeft, RAbstractVector originalRight) {
         assert isSupported(originalLeft, originalRight);
         RAbstractVector left = leftClass.cast(originalLeft);
         RAbstractVector right = rightClass.cast(originalRight);
 
-        RAbstractVector leftCast = left.castSafe(argumentType, leftIsNAProfile, false);
-        RAbstractVector rightCast = right.castSafe(argumentType, rightIsNAProfile, false);
+        function.enable(left, right);
 
-        assert leftCast != null;
-        assert rightCast != null;
-
-        function.enable(leftCast, rightCast);
+        if (mayContainMetadata && (dimensionsProfile.profile(hasLeftDimNode.execute(left) && hasRightDimNode.execute(right)))) {
+            if (differentDimensions(left, right)) {
+                throw error(RError.Message.NON_CONFORMABLE_ARRAYS);
+            }
+        }
 
-        if (scalarTypes) {
-            assert left.getLength() == 1;
-            assert right.getLength() == 1;
-            return applyScalar(leftCast, rightCast);
-        } else {
-            int leftLength = leftLengthProfile.profile(left.getLength());
-            int rightLength = rightLengthProfile.profile(right.getLength());
-            return applyVectorized(left, leftCast, leftLength, right, rightCast, rightLength);
+        VectorAccess leftAccess = isGeneric ? left.slowPathAccess() : fastLeftAccess;
+        VectorAccess rightAccess = isGeneric ? right.slowPathAccess() : fastRightAccess;
+        try (SequentialIterator leftIter = leftAccess.access(left);
+                        SequentialIterator rightIter = rightAccess.access(right)) {
+            RAbstractVector target = null;
+            int leftLength = leftLengthProfile.profile(leftAccess.getLength(leftIter));
+            int rightLength = rightLengthProfile.profile(rightAccess.getLength(rightIter));
+            if (seenEmpty.profile(leftLength == 0 || rightLength == 0)) {
+                /*
+                 * It is safe to skip attribute handling here as they are never copied if length is
+                 * 0 of either side. Note that dimension check still needs to be performed.
+                 */
+                return resultType.getEmpty();
+            }
+            if (mayFoldConstantTime) {
+                target = function.tryFoldConstantTime(left.castSafe(argumentType, leftIsNAProfile, false), leftLength, right.castSafe(argumentType, rightIsNAProfile, false), rightLength);
+            }
+            if (target == null) {
+                int maxLength = maxLengthProfile.profile(leftLength >= rightLength) ? leftLength : rightLength;
+
+                assert left.getLength() == leftLength;
+                assert right.getLength() == rightLength;
+                if (mayShareLeft && left.getRType() == resultType && shareLeft.profile(leftLength == maxLength && ((RShareable) left).isTemporary())) {
+                    target = left;
+                    vectorNode.execute(function, leftLength, rightLength, leftAccess, leftIter, leftAccess, leftIter, rightAccess, rightIter);
+                } else if (mayShareRight && right.getRType() == resultType && shareRight.profile(rightLength == maxLength && ((RShareable) right).isTemporary())) {
+                    target = right;
+                    vectorNode.execute(function, leftLength, rightLength, rightAccess, rightIter, leftAccess, leftIter, rightAccess, rightIter);
+                } else {
+                    if (resultAccess == null) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        resultAccess = insert(VectorAccess.createNew(resultType));
+                    }
+                    target = resultType.create(maxLength, false);
+                    try (SequentialIterator resultIter = resultAccess.access(target)) {
+                        vectorNode.execute(function, leftLength, rightLength, resultAccess, resultIter, leftAccess, leftIter, rightAccess, rightIter);
+                    }
+                }
+                RBaseNode.reportWork(this, maxLength);
+                target.setComplete(function.isComplete());
+            }
+            if (mayContainMetadata) {
+                target = copyAttributes.execute(target, left, leftLength, right, rightLength);
+            }
+            return target;
         }
     }
 
@@ -166,353 +284,308 @@ public final class BinaryMapNode extends RBaseNode {
         }
         return false;
     }
+}
+
+abstract class VectorMapBinaryInternalNode extends RBaseNode {
+
+    private abstract static class MapBinaryIndexedAction {
+        public abstract void perform(BinaryMapFunctionNode action, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter);
+    }
+
+    private static final MapBinaryIndexedAction LOGICAL_LOGICAL = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            result.setLogical(resultIter, arithmetic.applyLogical(left.getLogical(leftIter), right.getLogical(rightIter)));
+        }
+    };
+    private static final MapBinaryIndexedAction LOGICAL_INTEGER = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            result.setLogical(resultIter, arithmetic.applyLogical(left.getInt(leftIter), right.getInt(rightIter)));
+        }
+    };
+    private static final MapBinaryIndexedAction LOGICAL_DOUBLE = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            result.setLogical(resultIter, arithmetic.applyLogical(left.getDouble(leftIter), right.getDouble(rightIter)));
+        }
+    };
+    private static final MapBinaryIndexedAction LOGICAL_COMPLEX = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            result.setLogical(resultIter, arithmetic.applyLogical(left.getComplex(leftIter), right.getComplex(rightIter)));
+        }
+    };
+    private static final MapBinaryIndexedAction LOGICAL_CHARACTER = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            result.setLogical(resultIter, arithmetic.applyLogical(left.getString(leftIter), right.getString(rightIter)));
+        }
+    };
+    private static final MapBinaryIndexedAction LOGICAL_RAW = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            result.setLogical(resultIter, arithmetic.applyLogical(RRuntime.raw2int(left.getRaw(leftIter)), RRuntime.raw2int(right.getRaw(rightIter))));
+        }
+    };
+    private static final MapBinaryIndexedAction RAW_RAW = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            result.setRaw(resultIter, arithmetic.applyRaw(left.getRaw(leftIter), right.getRaw(rightIter)));
+        }
+    };
+    private static final MapBinaryIndexedAction INTEGER_INTEGER = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            result.setInt(resultIter, arithmetic.applyInteger(left.getInt(leftIter), right.getInt(rightIter)));
+        }
+    };
+    private static final MapBinaryIndexedAction DOUBLE_INTEGER = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            result.setDouble(resultIter, arithmetic.applyDouble(left.getInt(leftIter), right.getInt(rightIter)));
+        }
+    };
+    private static final MapBinaryIndexedAction DOUBLE = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            result.setDouble(resultIter, arithmetic.applyDouble(left.getDouble(leftIter), right.getDouble(rightIter)));
+        }
+    };
+    private static final MapBinaryIndexedAction COMPLEX = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            RComplex value = arithmetic.applyComplex(left.getComplex(leftIter), right.getComplex(rightIter));
+            result.setComplex(resultIter, value.getRealPart(), value.getImaginaryPart());
+        }
+    };
+    private static final MapBinaryIndexedAction CHARACTER = new MapBinaryIndexedAction() {
+        @Override
+        public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter,
+                        VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+            result.setString(resultIter, arithmetic.applyCharacter(left.getString(leftIter), right.getString(rightIter)));
+        }
+    };
+
+    private final MapBinaryIndexedAction indexedAction;
+
+    protected VectorMapBinaryInternalNode(RType resultType, RType argumentType) {
+        this.indexedAction = createIndexedAction(resultType, argumentType);
+    }
 
-    private Object applyScalar(RAbstractVector left, RAbstractVector right) {
-        switch (argumentType) {
+    public static VectorMapBinaryInternalNode create(RType resultType, RType argumentType) {
+        return VectorMapBinaryInternalNodeGen.create(resultType, argumentType);
+    }
+
+    private static MapBinaryIndexedAction createIndexedAction(RType resultType, RType argumentType) {
+        switch (resultType) {
             case Raw:
-                byte leftValueRaw = ((RAbstractRawVector) left).getRawDataAt(0);
-                byte rightValueRaw = ((RAbstractRawVector) right).getRawDataAt(0);
-                switch (resultType) {
-                    case Raw:
-                        return RRaw.valueOf(function.applyRaw(leftValueRaw, rightValueRaw));
-                    case Logical:
-                        return function.applyLogical(RRuntime.raw2int(leftValueRaw), RRuntime.raw2int(rightValueRaw));
-                    default:
-                        throw RInternalError.shouldNotReachHere();
-                }
+                assert argumentType == RType.Raw;
+                return RAW_RAW;
             case Logical:
-                byte leftValueLogical = ((RAbstractLogicalVector) left).getDataAt(0);
-                byte rightValueLogical = ((RAbstractLogicalVector) right).getDataAt(0);
-                return function.applyLogical(leftValueLogical, rightValueLogical);
-            case Integer:
-                int leftValueInt = ((RAbstractIntVector) left).getDataAt(0);
-                int rightValueInt = ((RAbstractIntVector) right).getDataAt(0);
-                switch (resultType) {
+                switch (argumentType) {
+                    case Raw:
+                        return LOGICAL_RAW;
                     case Logical:
-                        return function.applyLogical(leftValueInt, rightValueInt);
+                        return LOGICAL_LOGICAL;
                     case Integer:
-                        return function.applyInteger(leftValueInt, rightValueInt);
+                        return LOGICAL_INTEGER;
                     case Double:
-                        return function.applyDouble(leftValueInt, rightValueInt);
+                        return LOGICAL_DOUBLE;
+                    case Complex:
+                        return LOGICAL_COMPLEX;
+                    case Character:
+                        return LOGICAL_CHARACTER;
                     default:
                         throw RInternalError.shouldNotReachHere();
                 }
+            case Integer:
+                assert argumentType == RType.Integer;
+                return INTEGER_INTEGER;
             case Double:
-                double leftValueDouble = ((RAbstractDoubleVector) left).getDataAt(0);
-                double rightValueDouble = ((RAbstractDoubleVector) right).getDataAt(0);
-                switch (resultType) {
-                    case Logical:
-                        return function.applyLogical(leftValueDouble, rightValueDouble);
+                switch (argumentType) {
+                    case Integer:
+                        return DOUBLE_INTEGER;
                     case Double:
-                        return function.applyDouble(leftValueDouble, rightValueDouble);
+                        return DOUBLE;
                     default:
                         throw RInternalError.shouldNotReachHere();
                 }
             case Complex:
-                RComplex leftValueComplex = ((RAbstractComplexVector) left).getDataAt(0);
-                RComplex rightValueComplex = ((RAbstractComplexVector) right).getDataAt(0);
-                switch (resultType) {
-                    case Logical:
-                        return function.applyLogical(leftValueComplex, rightValueComplex);
-                    case Complex:
-                        return function.applyComplex(leftValueComplex, rightValueComplex);
-                    default:
-                        throw RInternalError.shouldNotReachHere();
-                }
+                assert argumentType == RType.Complex;
+                return COMPLEX;
             case Character:
-                String leftValueString = ((RAbstractStringVector) left).getDataAt(0);
-                String rightValueString = ((RAbstractStringVector) right).getDataAt(0);
-                switch (resultType) {
-                    case Logical:
-                        return function.applyLogical(leftValueString, rightValueString);
-                    default:
-                        throw RInternalError.shouldNotReachHere();
-                }
+                assert argumentType == RType.Character;
+                return CHARACTER;
             default:
                 throw RInternalError.shouldNotReachHere();
         }
     }
 
-    private Object applyVectorized(RAbstractVector left, RAbstractVector leftCast, int leftLength, RAbstractVector right, RAbstractVector rightCast, int rightLength) {
-        if (mayContainMetadata && (dimensionsProfile.profile(hasLeftDimNode.execute(left) && hasRightDimNode.execute(right)))) {
-            if (differentDimensions(left, right)) {
-                throw error(RError.Message.NON_CONFORMABLE_ARRAYS);
-            }
-        }
-
-        if (seenEmpty.profile(leftLength == 0 || rightLength == 0)) {
-            /*
-             * It is safe to skip attribute handling here as they are never copied if length is 0 of
-             * either side. Note that dimension check still needs to be performed.
-             */
-            return resultType.getEmpty();
-        }
+    public abstract void execute(BinaryMapFunctionNode node, int leftLength, int rightLength, VectorAccess result, SequentialIterator resultIter,
+                    VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter);
 
-        RAbstractVector target = null;
-        if (mayFoldConstantTime) {
-            target = function.tryFoldConstantTime(leftCast, leftLength, rightCast, rightLength);
-        }
-        if (target == null) {
-            int maxLength = maxLengthProfile.profile(leftLength >= rightLength) ? leftLength : rightLength;
-            RVector<?> targetVec = createOrShareVector(leftLength, left, rightLength, right, maxLength);
-            target = targetVec;
-
-            assert left.getLength() == leftLength;
-            assert right.getLength() == rightLength;
-            assert leftCast.getRType() == argumentType;
-            assert rightCast.getRType() == argumentType;
-
-            vectorNode.execute(function, targetVec, leftCast, leftLength, rightCast, rightLength);
-            RBaseNode.reportWork(this, maxLength);
-            target.setComplete(function.isComplete());
+    @Specialization(guards = {"leftLength == 1", "rightLength == 1"})
+    protected void doScalarScalar(BinaryMapFunctionNode node, @SuppressWarnings("unused") int leftLength, @SuppressWarnings("unused") int rightLength, VectorAccess result,
+                    SequentialIterator resultIter, VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) {
+        left.next(leftIter);
+        right.next(rightIter);
+        if (result != right && result != left) {
+            result.next(resultIter);
         }
-        if (mayContainMetadata) {
-            target = copyAttributes.execute(target, left, leftLength, right, rightLength);
-        }
-        return target;
+        indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter);
     }
 
-    private RVector<?> createOrShareVector(int leftLength, RAbstractVector left, int rightLength, RAbstractVector right, int maxLength) {
-        if (mayShareLeft && left.getRType() == resultType && shareLeft.profile(leftLength == maxLength && ((RShareable) left).isTemporary()) && left instanceof RVector<?>) {
-            return (RVector<?>) left;
-        }
-        if (mayShareRight && right.getRType() == resultType && shareRight.profile(rightLength == maxLength && ((RShareable) right).isTemporary()) && right instanceof RVector<?>) {
-            return (RVector<?>) right;
+    @Specialization(replaces = "doScalarScalar", guards = {"leftLength == 1"})
+    protected void doScalarVector(BinaryMapFunctionNode node, @SuppressWarnings("unused") int leftLength, int rightLength, VectorAccess result, SequentialIterator resultIter,
+                    VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter,
+                    @Cached("createCountingProfile()") LoopConditionProfile profile) {
+        profile.profileCounted(rightLength);
+        left.next(leftIter);
+        while (profile.inject(right.next(rightIter))) {
+            if (result != right && result != left) {
+                result.next(resultIter);
+            }
+            indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter);
         }
-        return resultType.create(maxLength, false);
     }
 
-    @ImportStatic(Utils.class)
-    protected abstract static class VectorMapBinaryInternalNode extends RBaseNode {
-
-        private static final MapBinaryIndexedAction<Byte> LOGICAL_LOGICAL = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal);
-        private static final MapBinaryIndexedAction<Integer> LOGICAL_INTEGER = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal);
-        private static final MapBinaryIndexedAction<Double> LOGICAL_DOUBLE = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal);
-        private static final MapBinaryIndexedAction<RComplex> LOGICAL_COMPLEX = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal);
-        private static final MapBinaryIndexedAction<String> LOGICAL_CHARACTER = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal);
-        private static final MapBinaryIndexedAction<Byte> LOGICAL_RAW = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(RRuntime.raw2int(leftVal), RRuntime.raw2int(rightVal));
-        private static final MapBinaryIndexedAction<Byte> RAW_RAW = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyRaw(leftVal, rightVal);
-        private static final MapBinaryIndexedAction<Integer> INTEGER_INTEGER = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyInteger(leftVal, rightVal);
-        private static final MapBinaryIndexedAction<Integer> DOUBLE_INTEGER = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyDouble(leftVal, rightVal);
-        private static final MapBinaryIndexedAction<Double> DOUBLE = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyDouble(leftVal, rightVal);
-        private static final MapBinaryIndexedAction<RComplex> COMPLEX = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyComplex(leftVal, rightVal);
-        private static final MapBinaryIndexedAction<String> CHARACTER = //
-                        (arithmetic, leftVal, rightVal) -> arithmetic.applyCharacter(leftVal, rightVal);
-
-        private final MapBinaryIndexedAction<Object> indexedAction;
-
-        @Child private GetDataStore getTargetDataStore = GetDataStore.create();
-        @Child private SetDataAt targetSetDataAt;
-
-        @SuppressWarnings("unchecked")
-        protected VectorMapBinaryInternalNode(RType resultType, RType argumentType) {
-            this.indexedAction = (MapBinaryIndexedAction<Object>) createIndexedAction(resultType, argumentType);
-            this.targetSetDataAt = Utils.createSetDataAtNode(resultType);
+    @Specialization(replaces = "doScalarScalar", guards = {"rightLength == 1"})
+    protected void doVectorScalar(BinaryMapFunctionNode node, int leftLength, @SuppressWarnings("unused") int rightLength, VectorAccess result, SequentialIterator resultIter,
+                    VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter,
+                    @Cached("createCountingProfile()") LoopConditionProfile profile) {
+        profile.profileCounted(leftLength);
+        right.next(rightIter);
+        while (profile.inject(left.next(leftIter))) {
+            if (result != left && result != right) {
+                result.next(resultIter);
+            }
+            indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter);
         }
+    }
 
-        public static VectorMapBinaryInternalNode create(RType resultType, RType argumentType) {
-            return VectorMapBinaryInternalNodeGen.create(resultType, argumentType);
+    @Specialization(guards = {"leftLength == rightLength"})
+    protected void doSameLength(BinaryMapFunctionNode node, int leftLength, @SuppressWarnings("unused") int rightLength, VectorAccess result, SequentialIterator resultIter,
+                    VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter,
+                    @Cached("createCountingProfile()") LoopConditionProfile profile) {
+        profile.profileCounted(leftLength);
+        while (profile.inject(left.next(leftIter))) {
+            right.next(rightIter);
+            if (result != left && result != right) {
+                result.next(resultIter);
+            }
+            indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter);
         }
+    }
 
-        private static MapBinaryIndexedAction<?> createIndexedAction(RType resultType, RType argumentType) {
-            switch (resultType) {
-                case Raw:
-                    assert argumentType == RType.Raw;
-                    return RAW_RAW;
-                case Logical:
-                    switch (argumentType) {
-                        case Raw:
-                            return LOGICAL_RAW;
-                        case Logical:
-                            return LOGICAL_LOGICAL;
-                        case Integer:
-                            return LOGICAL_INTEGER;
-                        case Double:
-                            return LOGICAL_DOUBLE;
-                        case Complex:
-                            return LOGICAL_COMPLEX;
-                        case Character:
-                            return LOGICAL_CHARACTER;
-                        default:
-                            throw RInternalError.shouldNotReachHere();
+    @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"leftLength >= rightLength"})
+    protected void doMultiplesLeft(BinaryMapFunctionNode node, int leftLength, int rightLength, VectorAccess result, SequentialIterator resultIter,
+                    VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter,
+                    @Cached("createCountingProfile()") LoopConditionProfile leftProfile,
+                    @Cached("createCountingProfile()") LoopConditionProfile rightProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile smallRemainderProfile) {
+        assert result != right;
+        leftProfile.profileCounted(leftLength);
+        rightProfile.profileCounted(rightLength);
+        while (leftProfile.inject(leftIter.getIndex() + 1 < leftLength)) {
+            right.reset(rightIter);
+            if (smallRemainderProfile.profile((leftLength - leftIter.getIndex() - 1) >= rightLength)) {
+                // we need at least rightLength more elements
+                while (rightProfile.inject(right.next(rightIter)) && leftProfile.inject(left.next(leftIter))) {
+                    if (result != left) {
+                        result.next(resultIter);
                     }
-                case Integer:
-                    assert argumentType == RType.Integer;
-                    return INTEGER_INTEGER;
-                case Double:
-                    switch (argumentType) {
-                        case Integer:
-                            return DOUBLE_INTEGER;
-                        case Double:
-                            return DOUBLE;
-                        default:
-                            throw RInternalError.shouldNotReachHere();
+                    indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter);
+                }
+            } else {
+                while (rightProfile.inject(right.next(rightIter)) && leftProfile.inject(left.next(leftIter))) {
+                    if (result != left) {
+                        result.next(resultIter);
                     }
-                case Complex:
-                    assert argumentType == RType.Complex;
-                    return COMPLEX;
-                case Character:
-                    assert argumentType == RType.Character;
-                    return CHARACTER;
-                default:
-                    throw RInternalError.shouldNotReachHere();
-            }
-        }
-
-        public abstract void execute(BinaryMapFunctionNode node, RVector<?> store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength);
-
-        @Specialization(guards = {"leftLength == 1", "rightLength == 1"})
-        @SuppressWarnings("unused")
-        protected void doScalarScalar(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
-                        @Cached("createIterator()") VectorIterator.Generic leftIterator,
-                        @Cached("createIterator()") VectorIterator.Generic rightIterator) {
-            Object itLeft = leftIterator.init(left);
-            Object itRight = rightIterator.init(right);
-            Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight));
-            targetSetDataAt.setDataAtAsObject(result, getTargetDataStore.execute(result), 0, value);
-        }
-
-        @Specialization(replaces = "doScalarScalar", guards = {"leftLength == 1"})
-        @SuppressWarnings("unused")
-        protected void doScalarVector(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
-                        @Cached("createIterator()") VectorIterator.Generic leftIterator,
-                        @Cached("createIterator()") VectorIterator.Generic rightIterator,
-                        @Cached("createCountingProfile()") LoopConditionProfile profile) {
-            profile.profileCounted(rightLength);
-            Object itLeft = leftIterator.init(left);
-            Object itRight = rightIterator.init(right);
-            Object resultStore = getTargetDataStore.execute(result);
-            Object leftValue = leftIterator.next(left, itLeft);
-            for (int i = 0; profile.inject(i < rightLength); ++i) {
-                Object value = indexedAction.perform(node, leftValue, rightIterator.next(right, itRight));
-                targetSetDataAt.setDataAtAsObject(result, resultStore, i, value);
+                    indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter);
+                }
+                RError.warning(this, RError.Message.LENGTH_NOT_MULTI);
             }
         }
+    }
 
-        @Specialization(replaces = "doScalarScalar", guards = {"rightLength == 1"})
-        @SuppressWarnings("unused")
-        protected void doVectorScalar(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
-                        @Cached("createIterator()") VectorIterator.Generic leftIterator,
-                        @Cached("createIterator()") VectorIterator.Generic rightIterator,
-                        @Cached("createCountingProfile()") LoopConditionProfile profile) {
-            profile.profileCounted(leftLength);
-            Object itLeft = leftIterator.init(left);
-            Object itRight = rightIterator.init(right);
-            Object resultStore = getTargetDataStore.execute(result);
-            Object rightValue = rightIterator.next(right, itRight);
-            for (int i = 0; profile.inject(i < leftLength); ++i) {
-                Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightValue);
-                targetSetDataAt.setDataAtAsObject(result, resultStore, i, value);
+    @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"rightLength >= leftLength"})
+    protected void doMultiplesRight(BinaryMapFunctionNode node, int leftLength, int rightLength, VectorAccess result, SequentialIterator resultIter,
+                    VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter,
+                    @Cached("createCountingProfile()") LoopConditionProfile leftProfile,
+                    @Cached("createCountingProfile()") LoopConditionProfile rightProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile smallRemainderProfile) {
+        assert result != left;
+        leftProfile.profileCounted(leftLength);
+        rightProfile.profileCounted(rightLength);
+        while (rightProfile.inject(rightIter.getIndex() + 1 < rightLength)) {
+            left.reset(leftIter);
+            if (smallRemainderProfile.profile((rightLength - rightIter.getIndex() - 1) >= leftLength)) {
+                // we need at least leftLength more elements
+                while (leftProfile.inject(left.next(leftIter)) && rightProfile.inject(right.next(rightIter))) {
+                    if (result != right) {
+                        result.next(resultIter);
+                    }
+                    indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter);
+                }
+            } else {
+                while (leftProfile.inject(left.next(leftIter)) && rightProfile.inject(right.next(rightIter))) {
+                    if (result != right) {
+                        result.next(resultIter);
+                    }
+                    indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter);
+                }
+                RError.warning(this, RError.Message.LENGTH_NOT_MULTI);
             }
         }
+    }
+}
 
-        @Specialization(guards = {"leftLength == rightLength"})
-        @SuppressWarnings("unused")
-        protected void doSameLength(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
-                        @Cached("createIterator()") VectorIterator.Generic leftIterator,
-                        @Cached("createIterator()") VectorIterator.Generic rightIterator,
-                        @Cached("createCountingProfile()") LoopConditionProfile profile) {
-            profile.profileCounted(leftLength);
-            Object itLeft = leftIterator.init(left);
-            Object itRight = rightIterator.init(right);
-            Object resultStore = getTargetDataStore.execute(result);
-            for (int i = 0; profile.inject(i < leftLength); ++i) {
-                Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight));
-                targetSetDataAt.setDataAtAsObject(result, resultStore, i, value);
-            }
-        }
+/**
+ * Implements a binary map operation that maps two vectors into a single result vector of the
+ * maximum size of both vectors. Vectors with smaller length are repeated. The actual implementation
+ * is provided using a {@link BinaryMapFunctionNode}.
+ *
+ * The implementation tries to share input vectors if they are implementing {@link RShareable}.
+ */
+public abstract class BinaryMapNode extends RBaseNode {
 
-        protected static boolean multiplesMinMax(int min, int max) {
-            return max % min == 0;
-        }
+    @Child protected BinaryMapFunctionNode function;
+    protected final Class<? extends RAbstractVector> leftClass;
+    protected final Class<? extends RAbstractVector> rightClass;
+    protected final RType argumentType;
+    protected final RType resultType;
 
-        @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"multiplesMinMax(leftLength, rightLength)"})
-        protected void doMultiplesLeft(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
-                        @Cached("createIteratorWrapAround()") VectorIterator.Generic leftIterator,
-                        @Cached("createIterator()") VectorIterator.Generic rightIterator,
-                        @Cached("createCountingProfile()") LoopConditionProfile leftProfile,
-                        @Cached("createCountingProfile()") LoopConditionProfile rightProfile) {
-            int j = 0;
-            rightProfile.profileCounted(rightLength / leftLength);
-            Object itLeft = leftIterator.init(left);
-            Object itRight = rightIterator.init(right);
-            Object resultStore = getTargetDataStore.execute(result);
-            while (rightProfile.inject(j < rightLength)) {
-                leftProfile.profileCounted(leftLength);
-                for (int k = 0; leftProfile.inject(k < leftLength); k++) {
-                    Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight));
-                    targetSetDataAt.setDataAtAsObject(result, resultStore, j, value);
-                    j++;
-                }
-            }
-        }
+    protected BinaryMapNode(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType) {
+        this.function = function;
+        this.leftClass = left.getClass();
+        this.rightClass = right.getClass();
+        this.argumentType = argumentType;
+        this.resultType = resultType;
+    }
 
-        @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"multiplesMinMax(rightLength, leftLength)"})
-        protected void doMultiplesRight(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
-                        @Cached("createIterator()") VectorIterator.Generic leftIterator,
-                        @Cached("createIteratorWrapAround()") VectorIterator.Generic rightIterator,
-                        @Cached("createCountingProfile()") LoopConditionProfile leftProfile,
-                        @Cached("createCountingProfile()") LoopConditionProfile rightProfile) {
-            int j = 0;
-            leftProfile.profileCounted(leftLength / rightLength);
-            Object itLeft = leftIterator.init(left);
-            Object itRight = rightIterator.init(right);
-            Object resultStore = getTargetDataStore.execute(result);
-            while (leftProfile.inject(j < leftLength)) {
-                rightProfile.profileCounted(rightLength);
-                for (int k = 0; rightProfile.inject(k < rightLength); k++) {
-                    Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight));
-                    targetSetDataAt.setDataAtAsObject(result, resultStore, j, value);
-                    j++;
-                }
-            }
+    public static BinaryMapNode create(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType, boolean copyAttributes, boolean isGeneric) {
+        if (left instanceof RScalarVector && right instanceof RScalarVector) {
+            return new BinaryMapScalarNode(function, left, right, argumentType, resultType);
+        } else {
+            return new BinaryMapVectorNode(function, left, right, argumentType, resultType, copyAttributes, isGeneric);
         }
+    }
 
-        protected static boolean multiples(int leftLength, int rightLength) {
-            int min;
-            int max;
-            if (leftLength >= rightLength) {
-                min = rightLength;
-                max = leftLength;
-            } else {
-                min = leftLength;
-                max = rightLength;
-            }
-            return max % min == 0;
-        }
+    public abstract boolean isSupported(RAbstractVector left, RAbstractVector right);
 
-        @Specialization(guards = {"!multiples(leftLength, rightLength)"})
-        protected void doNoMultiples(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
-                        @Cached("createIteratorWrapAround()") VectorIterator.Generic leftIterator,
-                        @Cached("createIteratorWrapAround()") VectorIterator.Generic rightIterator,
-                        @Cached("createCountingProfile()") LoopConditionProfile profile,
-                        @Cached("createBinaryProfile()") ConditionProfile leftIncModProfile,
-                        @Cached("createBinaryProfile()") ConditionProfile rightIncModProfile) {
-            int max = Math.max(leftLength, rightLength);
-            profile.profileCounted(max);
-            Object itLeft = leftIterator.init(left);
-            Object itRight = rightIterator.init(right);
-            Object resultStore = getTargetDataStore.execute(result);
-            for (int i = 0; profile.inject(i < max); ++i) {
-                Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight));
-                targetSetDataAt.setDataAtAsObject(result, resultStore, i, value);
-            }
-            RError.warning(this, RError.Message.LENGTH_NOT_MULTI);
-        }
+    public abstract Object apply(RAbstractVector originalLeft, RAbstractVector originalRight);
 
-        private interface MapBinaryIndexedAction<V> {
-            Object perform(BinaryMapFunctionNode action, V left, V right);
-        }
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
index aaa72efdec80a239329d21e901f04e54825e7a27..1b997142d4066f3258265d10921a4ce32d70d39f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
@@ -25,7 +25,6 @@ package com.oracle.truffle.r.nodes.primitive;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
@@ -35,7 +34,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAt
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
-import com.oracle.truffle.r.nodes.primitive.UnaryMapNodeFactory.MapUnaryVectorInternalNodeGen;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RType;
@@ -43,121 +41,130 @@ import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RScalarVector;
 import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-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.GetDataStore;
-import com.oracle.truffle.r.runtime.data.nodes.SetDataAt;
-import com.oracle.truffle.r.runtime.data.nodes.VectorIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
-public final class UnaryMapNode extends RBaseNode {
+final class UnaryMapScalarNode extends UnaryMapNode {
+
+    @Child private VectorAccess operandAccess;
+
+    UnaryMapScalarNode(UnaryMapFunctionNode scalarNode, RAbstractVector operand, RType argumentType, RType resultType) {
+        super(scalarNode, operand, argumentType, resultType);
+        this.operandAccess = operand.access();
+    }
+
+    @Override
+    public boolean isSupported(RAbstractVector operand) {
+        return operandAccess.supports(operand);
+    }
+
+    @Override
+    public Object apply(RAbstractVector operand) {
+        assert isSupported(operand);
+
+        function.enable(operand);
+        assert operand.getLength() == 1;
+
+        try (RandomIterator iter = operandAccess.randomAccess(operand)) {
+            switch (argumentType) {
+                case Logical:
+                    return function.applyLogical(operandAccess.getLogical(iter, 0));
+                case Integer:
+                    return function.applyInteger(operandAccess.getInt(iter, 0));
+                case Double:
+                    return function.applyDouble(operandAccess.getDouble(iter, 0));
+                case Complex:
+                    switch (resultType) {
+                        case Double:
+                            return function.applyDouble(operandAccess.getComplex(iter, 0));
+                        case Complex:
+                            return function.applyComplex(operandAccess.getComplex(iter, 0));
+                        default:
+                            throw RInternalError.shouldNotReachHere();
+                    }
+                default:
+                    throw RInternalError.shouldNotReachHere();
+            }
+        }
+    }
+}
+
+final class UnaryMapVectorNode extends UnaryMapNode {
 
-    @Child private UnaryMapFunctionNode scalarNode;
     @Child private MapUnaryVectorInternalNode vectorNode;
     @Child private GetDimAttributeNode getDimNode;
     @Child private SetDimAttributeNode setDimNode;
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
+    @Child private VectorAccess fastOperandAccess;
+    @Child private VectorAccess resultAccess;
 
     // profiles
-    private final Class<? extends RAbstractVector> operandClass;
     private final VectorLengthProfile operandLengthProfile = VectorLengthProfile.create();
-    private final ConditionProfile operandIsNAProfile = ConditionProfile.createBinaryProfile();
     private final BranchProfile hasAttributesProfile;
     private final ConditionProfile shareOperand;
 
     // compile-time optimization flags
-    private final boolean scalarType;
     private final boolean mayContainMetadata;
     private final boolean mayFoldConstantTime;
     private final boolean mayShareOperand;
+    private final boolean isGeneric;
 
-    private UnaryMapNode(UnaryMapFunctionNode scalarNode, RAbstractVector operand, RType argumentType, RType resultType) {
-        this.scalarNode = scalarNode;
+    UnaryMapVectorNode(UnaryMapFunctionNode scalarNode, RAbstractVector operand, RType argumentType, RType resultType, boolean isGeneric) {
+        super(scalarNode, operand, argumentType, resultType);
+        this.fastOperandAccess = isGeneric ? null : operand.access();
         this.vectorNode = MapUnaryVectorInternalNode.create(resultType, argumentType);
-        this.operandClass = operand.getClass();
-        this.scalarType = operand instanceof RScalarVector;
         boolean operandVector = operand instanceof RVector;
         this.mayContainMetadata = operandVector;
-        this.mayFoldConstantTime = scalarNode.mayFoldConstantTime(operandClass);
+        this.mayFoldConstantTime = argumentType == operand.getRType() && scalarNode.mayFoldConstantTime(operandClass);
         this.mayShareOperand = operandVector;
+        this.isGeneric = isGeneric;
 
         // lazily create profiles only if needed to avoid unnecessary allocations
-        this.shareOperand = operandVector ? ConditionProfile.createBinaryProfile() : null;
+        this.shareOperand = mayShareOperand ? ConditionProfile.createBinaryProfile() : null;
         this.hasAttributesProfile = mayContainMetadata ? BranchProfile.create() : null;
-    }
-
-    public static UnaryMapNode create(UnaryMapFunctionNode scalarNode, RAbstractVector operand, RType argumentType, RType resultType) {
-        return new UnaryMapNode(scalarNode, operand, argumentType, resultType);
-    }
 
-    public Class<? extends RAbstractVector> getOperandClass() {
-        return operandClass;
     }
 
-    public RType getArgumentType() {
-        return vectorNode.getArgumentType();
+    @Override
+    public boolean isSupported(RAbstractVector operand) {
+        return operand.getClass() == operandClass && (isGeneric || fastOperandAccess.supports(operand));
     }
 
-    public RType getResultType() {
-        return vectorNode.getResultType();
-    }
-
-    public boolean isSupported(Object operand) {
-        return operand.getClass() == operandClass;
-    }
-
-    public Object apply(Object originalOperand) {
+    @Override
+    public Object apply(RAbstractVector originalOperand) {
         assert isSupported(originalOperand);
         RAbstractVector operand = operandClass.cast(originalOperand);
+        function.enable(operand);
+        int operandLength = operandLengthProfile.profile(operand.getLength());
 
-        RAbstractVector operandCast = operand.castSafe(getArgumentType(), operandIsNAProfile);
-
-        scalarNode.enable(operandCast);
-        if (scalarType) {
-            assert operand.getLength() == 1;
-            return scalarOperation(operandCast);
-        } else {
-            int operandLength = operandLengthProfile.profile(operand.getLength());
-            return vectorOperation(operand, operandCast, operandLength);
-        }
-    }
-
-    private Object scalarOperation(RAbstractVector operand) {
-        switch (getArgumentType()) {
-            case Logical:
-                return scalarNode.applyLogical(((RAbstractLogicalVector) operand).getDataAt(0));
-            case Integer:
-                return scalarNode.applyInteger(((RAbstractIntVector) operand).getDataAt(0));
-            case Double:
-                return scalarNode.applyDouble(((RAbstractDoubleVector) operand).getDataAt(0));
-            case Complex:
-                switch (getResultType()) {
-                    case Double:
-                        return scalarNode.applyDouble(((RAbstractComplexVector) operand).getDataAt(0));
-                    case Complex:
-                        return scalarNode.applyComplex(((RAbstractComplexVector) operand).getDataAt(0));
-                    default:
-                        throw RInternalError.shouldNotReachHere();
-                }
-            default:
-                throw RInternalError.shouldNotReachHere();
-        }
-    }
-
-    private Object vectorOperation(RAbstractVector operand, RAbstractVector operandCast, int operandLength) {
         RAbstractVector target = null;
         if (mayFoldConstantTime) {
-            target = scalarNode.tryFoldConstantTime(operandCast, operandLength);
+            target = function.tryFoldConstantTime(operand, operandLength);
         }
         if (target == null) {
-            RVector<?> targetVec = createOrShareVector(operandLength, operand);
-            target = targetVec;
-            vectorNode.apply(scalarNode, targetVec, operandCast, operandLength);
+            VectorAccess operandAccess = isGeneric ? operand.slowPathAccess() : fastOperandAccess;
+            try (SequentialIterator operandIter = operandAccess.access(operand)) {
+                if (mayShareOperand && operand.getRType() == resultType && shareOperand.profile(((RShareable) operand).isTemporary())) {
+                    target = operand;
+                    vectorNode.execute(function, operandLength, operandAccess, operandIter, operandAccess, operandIter);
+                } else {
+                    if (resultAccess == null) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        target = resultType.create(operandLength, false);
+                        resultAccess = insert(target.access());
+                    } else {
+                        target = resultType.create(operandLength, false);
+                    }
+                    try (SequentialIterator resultIter = resultAccess.access(target)) {
+                        vectorNode.execute(function, operandLength, resultAccess, resultIter, operandAccess, operandIter);
+                    }
+                }
+            }
             RBaseNode.reportWork(this, operandLength);
-            target.setComplete(scalarNode.isComplete());
+            target.setComplete(function.isComplete());
         }
         if (mayContainMetadata) {
             target = handleMetadata(target, operand);
@@ -165,14 +172,6 @@ public final class UnaryMapNode extends RBaseNode {
         return target;
     }
 
-    private RVector<?> createOrShareVector(int operandLength, RAbstractVector operand) {
-        RType resultType = getResultType();
-        if (mayShareOperand && operand.getRType() == resultType && shareOperand.profile(((RShareable) operand).isTemporary()) && operand instanceof RVector<?>) {
-            return (RVector<?>) operand;
-        }
-        return resultType.create(operandLength, false);
-    }
-
     private RAbstractVector handleMetadata(RAbstractVector target, RAbstractVector operand) {
         RAbstractVector result = target;
         if (containsMetadata(operand) && operand != target) {
@@ -213,107 +212,141 @@ public final class UnaryMapNode extends RBaseNode {
         result.copyRegAttributesFrom(attributeSource);
         result.copyNamesFrom(attributeSource);
     }
+}
 
-    @ImportStatic(Utils.class)
-    protected abstract static class MapUnaryVectorInternalNode extends RBaseNode {
-
-        private static final MapIndexedAction<Byte> LOGICAL = (arithmetic, value) -> arithmetic.applyLogical(value);
-        private static final MapIndexedAction<Integer> INTEGER = (arithmetic, value) -> arithmetic.applyInteger(value);
-        private static final MapIndexedAction<Double> DOUBLE = (arithmetic, value) -> arithmetic.applyDouble(value);
-        private static final MapIndexedAction<RComplex> COMPLEX = (arithmetic, value) -> arithmetic.applyComplex(value);
-        private static final MapIndexedAction<RComplex> DOUBLE_COMPLEX = (arithmetic, value) -> arithmetic.applyDouble(value);
-        private static final MapIndexedAction<String> CHARACTER = (arithmetic, value) -> arithmetic.applyCharacter(value);
-
-        private final MapIndexedAction<Object> indexedAction;
-        private final RType argumentType;
-        private final RType resultType;
-
-        @Child private GetDataStore getTargetDataStore = GetDataStore.create();
-        @Child private SetDataAt targetSetDataAt;
-
-        @SuppressWarnings("unchecked")
-        protected MapUnaryVectorInternalNode(RType resultType, RType argumentType) {
-            this.indexedAction = (MapIndexedAction<Object>) createIndexedAction(resultType, argumentType);
-            this.argumentType = argumentType;
-            this.resultType = resultType;
-            this.targetSetDataAt = Utils.createSetDataAtNode(resultType);
-        }
+abstract class MapUnaryVectorInternalNode extends RBaseNode {
 
-        public RType getArgumentType() {
-            return argumentType;
-        }
+    private abstract static class MapIndexedAction {
+        public abstract void perform(UnaryMapFunctionNode action, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter);
+    }
 
-        public RType getResultType() {
-            return resultType;
+    private static final MapIndexedAction LOGICAL = new MapIndexedAction() {
+        @Override
+        public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) {
+            result.setLogical(resultIter, arithmetic.applyLogical(operand.getLogical(operandIter)));
         }
-
-        public static MapUnaryVectorInternalNode create(RType resultType, RType argumentType) {
-            return MapUnaryVectorInternalNodeGen.create(resultType, argumentType);
+    };
+    private static final MapIndexedAction INTEGER = new MapIndexedAction() {
+        @Override
+        public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) {
+            result.setInt(resultIter, arithmetic.applyInteger(operand.getInt(operandIter)));
         }
-
-        private static MapIndexedAction<?> createIndexedAction(RType resultType, RType argumentType) {
-            switch (argumentType) {
-                case Logical:
-                    return LOGICAL;
-                case Integer:
-                    switch (resultType) {
-                        case Integer:
-                            return INTEGER;
-                        case Double:
-                            return DOUBLE;
-                        default:
-                            throw RInternalError.shouldNotReachHere();
-                    }
-                case Double:
-                    return DOUBLE;
-                case Complex:
-                    switch (resultType) {
-                        case Double:
-                            return DOUBLE_COMPLEX;
-                        case Complex:
-                            return COMPLEX;
-                        default:
-                            throw RInternalError.shouldNotReachHere();
-                    }
-                case Character:
-                    return CHARACTER;
-                default:
-                    throw RInternalError.shouldNotReachHere();
-            }
+    };
+    private static final MapIndexedAction DOUBLE = new MapIndexedAction() {
+        @Override
+        public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) {
+            result.setDouble(resultIter, arithmetic.applyDouble(operand.getDouble(operandIter)));
+        }
+    };
+    private static final MapIndexedAction COMPLEX = new MapIndexedAction() {
+        @Override
+        public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) {
+            RComplex value = arithmetic.applyComplex(operand.getComplex(operandIter));
+            result.setComplex(resultIter, value.getRealPart(), value.getImaginaryPart());
+        }
+    };
+    private static final MapIndexedAction DOUBLE_COMPLEX = new MapIndexedAction() {
+        @Override
+        public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) {
+            result.setDouble(resultIter, arithmetic.applyDouble(operand.getComplex(operandIter)));
         }
+    };
+    private static final MapIndexedAction CHARACTER = new MapIndexedAction() {
+        @Override
+        public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) {
+            result.setString(resultIter, arithmetic.applyCharacter(operand.getString(operandIter)));
+        }
+    };
+
+    private final MapIndexedAction indexedAction;
+
+    protected MapUnaryVectorInternalNode(RType resultType, RType argumentType) {
+        this.indexedAction = createIndexedAction(resultType, argumentType);
+    }
+
+    public static MapUnaryVectorInternalNode create(RType resultType, RType argumentType) {
+        return MapUnaryVectorInternalNodeGen.create(resultType, argumentType);
+    }
 
-        private void apply(UnaryMapFunctionNode scalarAction, RVector<?> target, RAbstractVector operand, int operandLength) {
-            assert operand.getLength() == operandLength;
-            assert operand.getRType() == argumentType;
-            executeInternal(scalarAction, target, operand, operandLength);
+    private static MapIndexedAction createIndexedAction(RType resultType, RType argumentType) {
+        switch (argumentType) {
+            case Logical:
+                return LOGICAL;
+            case Integer:
+                switch (resultType) {
+                    case Integer:
+                        return INTEGER;
+                    case Double:
+                        return DOUBLE;
+                    default:
+                        throw RInternalError.shouldNotReachHere();
+                }
+            case Double:
+                return DOUBLE;
+            case Complex:
+                switch (resultType) {
+                    case Double:
+                        return DOUBLE_COMPLEX;
+                    case Complex:
+                        return COMPLEX;
+                    default:
+                        throw RInternalError.shouldNotReachHere();
+                }
+            case Character:
+                return CHARACTER;
+            default:
+                throw RInternalError.shouldNotReachHere();
         }
+    }
 
-        protected abstract void executeInternal(UnaryMapFunctionNode node, Object store, RAbstractVector operand, int operandLength);
+    protected abstract void execute(UnaryMapFunctionNode node, int operandLength, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter);
 
-        @Specialization(guards = {"operandLength == 1"})
-        protected void doScalar(UnaryMapFunctionNode node, RVector<?> target, RAbstractVector operand, int operandLength,
-                        @Cached("createIterator()") VectorIterator.Generic iterator) {
-            Object it = iterator.init(operand);
-            Object targetStore = getTargetDataStore.execute(target);
-            Object value = iterator.next(operand, it);
-            targetSetDataAt.setDataAtAsObject(target, targetStore, 0, indexedAction.perform(node, value));
+    @Specialization(guards = {"operandLength == 1"})
+    protected void doScalar(UnaryMapFunctionNode node, @SuppressWarnings("unused") int operandLength, VectorAccess result, SequentialIterator resultIter, VectorAccess operand,
+                    SequentialIterator operandIter) {
+        operand.next(operandIter);
+        if (result != operand) {
+            result.next(resultIter);
         }
+        indexedAction.perform(node, result, resultIter, operand, operandIter);
+    }
 
-        @Specialization(replaces = "doScalar")
-        protected void doScalarVector(UnaryMapFunctionNode node, RVector<?> target, RAbstractVector operand, int operandLength,
-                        @Cached("createIterator()") VectorIterator.Generic iterator,
-                        @Cached("createCountingProfile()") LoopConditionProfile profile) {
-            Object targetStore = getTargetDataStore.execute(target);
-            Object it = iterator.init(operand);
-            profile.profileCounted(operandLength);
-            for (int i = 0; profile.inject(i < operandLength); ++i) {
-                Object value = indexedAction.perform(node, iterator.next(operand, it));
-                targetSetDataAt.setDataAtAsObject(target, targetStore, i, value);
+    @Specialization(replaces = "doScalar")
+    protected void doScalarVector(UnaryMapFunctionNode node, int operandLength, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter,
+                    @Cached("createCountingProfile()") LoopConditionProfile profile) {
+        profile.profileCounted(operandLength);
+        while (profile.inject(operand.next(operandIter))) {
+            if (result != operand) {
+                result.next(resultIter);
             }
+            indexedAction.perform(node, result, resultIter, operand, operandIter);
         }
+    }
+}
+
+public abstract class UnaryMapNode extends RBaseNode {
 
-        private interface MapIndexedAction<V> {
-            Object perform(UnaryMapFunctionNode action, V val);
+    @Child protected UnaryMapFunctionNode function;
+    protected final Class<? extends RAbstractVector> operandClass;
+    protected final RType argumentType;
+    protected final RType resultType;
+
+    protected UnaryMapNode(UnaryMapFunctionNode function, RAbstractVector operand, RType argumentType, RType resultType) {
+        this.function = function;
+        this.operandClass = operand.getClass();
+        this.argumentType = argumentType;
+        this.resultType = resultType;
+    }
+
+    public static UnaryMapNode create(UnaryMapFunctionNode scalarNode, RAbstractVector operand, RType argumentType, RType resultType, boolean isGeneric) {
+        if (operand instanceof RScalarVector) {
+            return new UnaryMapScalarNode(scalarNode, operand, argumentType, resultType);
+        } else {
+            return new UnaryMapVectorNode(scalarNode, operand, argumentType, resultType, isGeneric);
         }
     }
+
+    public abstract boolean isSupported(RAbstractVector operand);
+
+    public abstract Object apply(RAbstractVector originalOperand);
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/Utils.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/Utils.java
deleted file mode 100644
index 3ec6b0e3b7df1498e1acc23b969e9d1e86f2d34e..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/Utils.java
+++ /dev/null
@@ -1,71 +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.nodes.primitive;
-
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.data.nodes.SetDataAt;
-import com.oracle.truffle.r.runtime.data.nodes.VectorIterator;
-
-abstract class Utils {
-    private Utils() {
-    }
-
-    static SetDataAt createSetDataAtNode(RType type) {
-        switch (type) {
-            case Raw:
-                return SetDataAt.Raw.create();
-            case Logical:
-                return SetDataAt.Logical.create();
-            case Integer:
-                return SetDataAt.Int.create();
-            case Double:
-                return SetDataAt.Double.create();
-            case Complex:
-                return SetDataAt.Complex.create();
-            case Character:
-                return SetDataAt.String.create();
-            default:
-                throw RInternalError.shouldNotReachHere("BinaryMapNode unexpected result type " + type);
-        }
-    }
-
-    static final class VecStore<T extends RAbstractVector> {
-        public final T vector;
-        public final Object store;
-
-        VecStore(T vector, Object store) {
-            this.vector = vector;
-            this.store = store;
-        }
-    }
-
-    public static VectorIterator.Generic createIterator() {
-        return VectorIterator.Generic.create();
-    }
-
-    public static VectorIterator.Generic createIteratorWrapAround() {
-        return VectorIterator.Generic.createWrapAround();
-    }
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java
index 8d3a0456e360fb32c4cb5eb2be2bc1a3a4a8bbea..aca07494f8ef2c9a0c228c16459d0d6c4aace97e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java
@@ -52,7 +52,7 @@ public abstract class CastStringBaseNode extends CastBaseNode {
     }
 
     protected String toString(Object value) {
-        return toString.executeString(value, false, ToStringNode.DEFAULT_SEPARATOR);
+        return toString.executeString(value, ToStringNode.DEFAULT_SEPARATOR);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
index 2b45b6639ae5045f8d4941d354b0fc0bf958e45a..034b53109fddd47662cb8d0d4807a7398de58876 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
@@ -58,7 +58,7 @@ public abstract class CastSymbolNode extends CastBaseNode {
     public abstract Object executeSymbol(Object o);
 
     private String toString(Object value) {
-        return toString.executeString(value, true, ToStringNode.DEFAULT_SEPARATOR);
+        return toString.executeString(value, ToStringNode.DEFAULT_SEPARATOR);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/NonNANode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/NonNANode.java
index 34332663004f748fa4a1f766c26fce3e7bc82ed0..d3d18f87d3c2fe1179bd58ac9e66f64055a9f83e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/NonNANode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/NonNANode.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.builtin.casts.MessageData;
@@ -29,13 +30,10 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector;
 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.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
 public abstract class NonNANode extends CastNode {
 
@@ -155,72 +153,26 @@ public abstract class NonNANode extends CastNode {
         return x;
     }
 
-    protected boolean isComplete(RAbstractContainer x) {
-        return x.isComplete();
-    }
-
-    @Specialization(guards = "isComplete(x)")
+    @Specialization(guards = "x.isComplete()")
     protected Object onCompleteContainer(RAbstractContainer x) {
         return x;
     }
 
-    @Specialization(guards = "!isComplete(x)")
-    protected Object onPossiblyIncompleteContainer(RAbstractIntVector x) {
-        int len = x.getLength();
-        for (int i = 0; i < len; i++) {
-            if (RRuntime.isNA(x.getDataAt(i))) {
-                return handleNA(x);
-            }
-        }
-        return x;
-    }
-
-    @Specialization(guards = "!isComplete(x)")
-    protected Object onPossiblyIncompleteContainer(RAbstractLogicalVector x) {
-        int len = x.getLength();
-        for (int i = 0; i < len; i++) {
-            if (RRuntime.isNA(x.getDataAt(i))) {
-                return handleNA(x);
-            }
-        }
-        return x;
-    }
-
-    @Specialization(guards = "!isComplete(x)")
-    protected Object onPossiblyIncompleteContainer(RAbstractDoubleVector x) {
-        int len = x.getLength();
-        for (int i = 0; i < len; i++) {
-            if (RRuntime.isNA(x.getDataAt(i))) {
-                return handleNA(x);
+    @Specialization(guards = {"access.supports(x)", "!x.isComplete()"})
+    protected RAbstractAtomicVector onPossiblyIncompleteContainerCached(RAbstractAtomicVector x,
+                    @Cached("x.access()") VectorAccess access) {
+        try (SequentialIterator iter = access.access(x)) {
+            while (access.next(iter)) {
+                if (access.isNA(iter)) {
+                    handleNA(x);
+                }
             }
         }
         return x;
     }
 
-    @Specialization(guards = "!isComplete(x)")
-    protected Object onPossiblyIncompleteContainer(RAbstractComplexVector x) {
-        int len = x.getLength();
-        for (int i = 0; i < len; i++) {
-            if (RRuntime.isNA(x.getDataAt(i))) {
-                return handleNA(x);
-            }
-        }
-        return x;
-    }
-
-    @Specialization(guards = "!isComplete(x)")
-    protected Object onPossiblyIncompleteContainer(RAbstractStringVector x) {
-        int len = x.getLength();
-        for (int i = 0; i < len; i++) {
-            if (RRuntime.isNA(x.getDataAt(i))) {
-                return handleNA(x);
-            }
-        }
-        return x;
-    }
-
-    @Specialization(guards = "!isComplete(x)")
-    protected Object onPossiblyIncompleteContainer(RAbstractRawVector x) {
-        return x;
+    @Specialization(replaces = "onPossiblyIncompleteContainerCached", guards = "!x.isComplete()")
+    protected RAbstractAtomicVector onPossiblyIncompleteContainerGeneric(RAbstractAtomicVector x) {
+        return onPossiblyIncompleteContainerCached(x, x.slowPathAccess());
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/SizeToOctalRawNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/SizeToOctalRawNode.java
index f830844351297e068af382b916b06b6a54c60932..83ddb43115f9529903a56305eee5b6cf7e65a8b7 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/SizeToOctalRawNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/SizeToOctalRawNode.java
@@ -1,97 +1,70 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
  *
- * 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.
+ * Copyright (c) 2000-2013, The R Core Team
+ * Copyright (c) 2017, Oracle and/or its affiliates
  *
- * 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.
+ * All rights reserved.
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.Arrays;
-
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory;
 import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.nodes.SetDataAt;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator;
 
+@ImportStatic(RRuntime.class)
 public abstract class SizeToOctalRawNode extends UnaryNode {
 
-    private Charset asciiCharset;
+    @Child private VectorFactory factory = VectorFactory.create();
+    @Child private VectorAccess resultAccess = VectorAccess.createNew(RType.Raw);
 
     public abstract RRawVector execute(Object size);
 
-    @Specialization
-    protected RRawVector doInt(int s) {
-        return RDataFactory.createRawVector(toOctalAsciiString(s));
-    }
-
-    @TruffleBoundary
-    private byte[] toOctalAsciiString(int s) {
-        if (asciiCharset == null) {
-            asciiCharset = Charset.forName("US-ASCII");
+    @Specialization(guards = "!isNA(size)")
+    protected RRawVector doInt(int size) {
+        if (size < 0) {
+            throw RError.error(RError.SHOW_CALLER, RError.Message.GENERIC, "size must be finite, >= 0 and < 2^33");
         }
-
-        ByteBuffer encode = asciiCharset.encode(Integer.toOctalString(s));
-        // reverse
-        byte[] result = new byte[11];
-        Arrays.fill(result, (byte) '0');
-        for (int i = result.length - 1; i >= 0 && encode.hasRemaining(); i--) {
-            result[i] = encode.get();
-        }
-        return result;
+        return toOctal(size);
     }
 
     // Transcribed from ".../utils/src/stubs.c"
-    @Specialization
-    protected RRawVector doDouble(double size,
-                    @Cached("create()") SetDataAt.Raw setDataNode) {
-
-        double s = size;
-        if (!RRuntime.isFinite(s) && s >= 0) {
-            throw RError.error(RError.SHOW_CALLER, RError.Message.GENERIC, "size must be finite and >= 0");
+    @Specialization(guards = "!isNAorNaN(size)")
+    protected RRawVector doDouble(double size) {
+        if (!RRuntime.isFinite(size) || size < 0 || size >= 8589934592d /* 2^33 */) {
+            throw RError.error(RError.SHOW_CALLER, RError.Message.GENERIC, "size must be finite, >= 0 and < 2^33");
         }
+        return toOctal((long) size);
+    }
 
-        RRawVector ans = RDataFactory.createRawVector(11);
-        byte[] store = ans.getInternalStore();
-
-        for (int i = 0; i < 11; i++) {
-            double s2 = Math.floor(s / 8.0);
-            double t = s - 8.0 * s2;
-            s = s2;
-            setDataNode.setDataAtAsObject(ans, store, 10 - i, (byte) (48.0 + t));
+    private RRawVector toOctal(long size) {
+        RRawVector ans = factory.createRawVector(11);
+        try (RandomIterator iter = resultAccess.randomAccess(ans)) {
+            long s = size;
+            for (int i = 0; i < 11; i++) {
+                resultAccess.setRaw(iter, 10 - i, (byte) (48.0 + (s % 8)));
+                s /= 8;
+            }
         }
         return ans;
     }
 
-    @Specialization
-    protected RRawVector doNull(@SuppressWarnings("unused") RNull n) {
+    @Fallback
+    protected RRawVector doNull(@SuppressWarnings("unused") Object obj) {
         return RDataFactory.createRawVector(11);
     }
 
     public static SizeToOctalRawNode create() {
         return SizeToOctalRawNodeGen.create();
-
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
index c28ada80ed370031b7657b128b183e7cf7036423..1aeae5ca87339c86ee0b1af963f6c76d19de0bb5 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
@@ -22,7 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.CompilerAsserts;
+import java.util.EnumMap;
+
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
@@ -32,23 +33,19 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.Utils;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RFunction;
-import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.RS4Object;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypes;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
@@ -60,72 +57,58 @@ public abstract class ToStringNode extends RBaseNode {
 
     @Child private ToStringNode recursiveToString;
 
-    private final ConditionProfile isCachedIntProfile = ConditionProfile.createBinaryProfile();
-    private final NACheck naCheck = NACheck.create();
-
-    private String toStringRecursive(Object o, boolean quotes, String separator) {
+    private String toStringRecursive(Object o, String separator) {
         if (recursiveToString == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             recursiveToString = insert(ToStringNodeGen.create());
         }
-        return recursiveToString.executeString(o, quotes, separator);
+        return recursiveToString.executeString(o, separator);
     }
 
-    public abstract String executeString(Object o, boolean quotes, String separator);
+    public abstract String executeString(Object o, String separator);
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(String value, boolean quotes, String separator) {
-        if (RRuntime.isNA(value)) {
-            return value;
-        }
-        if (quotes) {
-            return RRuntime.escapeString(value, false, true);
-        }
+    protected String toString(String value, @SuppressWarnings("unused") String separator) {
         return value;
 
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(RNull vector, boolean quotes, String separator) {
+    protected String toString(@SuppressWarnings("unused") RNull vector, @SuppressWarnings("unused") String separator) {
         return "NULL";
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(RFunction function, boolean quotes, String separator) {
+    protected String toString(RFunction function, @SuppressWarnings("unused") String separator) {
         return RRuntime.toString(function);
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(RSymbol symbol, boolean quotes, String separator) {
+    protected String toString(RSymbol symbol, @SuppressWarnings("unused") String separator) {
         return symbol.getName();
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(RComplex complex, boolean quotes, String separator) {
+    protected String toString(RComplex complex, @SuppressWarnings("unused") String separator,
+                    @Cached("create()") NACheck naCheck) {
         naCheck.enable(complex);
         return naCheck.convertComplexToString(complex);
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(RRaw raw, boolean quotes, String separator) {
+    protected String toString(RRaw raw, @SuppressWarnings("unused") String separator) {
         return RRuntime.rawToHexString(raw.getValue());
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(int operand, boolean quotes, String separator) {
+    protected String toString(int operand, @SuppressWarnings("unused") String separator) {
         return RRuntime.intToString(operand);
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(double operand, boolean quotes, String separator) {
+    protected String toString(double operand, @SuppressWarnings("unused") String separator,
+                    @Cached("createBinaryProfile()") ConditionProfile isCachedIntProfile,
+                    @Cached("create()") NACheck naCheck) {
         int intValue = (int) operand;
         if (isCachedIntProfile.profile(intValue == operand && RRuntime.isCachedNumberString(intValue))) {
             return RRuntime.getCachedNumberString(intValue);
@@ -134,104 +117,84 @@ public abstract class ToStringNode extends RBaseNode {
         return naCheck.convertDoubleToString(operand);
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(byte operand, boolean quotes, String separator) {
+    protected String toString(byte operand, @SuppressWarnings("unused") String separator) {
         return RRuntime.logicalToString(operand);
     }
 
     @Specialization
-    protected String toString(RS4Object obj, @SuppressWarnings("unused") boolean quotes, String separator,
-                    @Cached(value = "createWithImplicit()") ClassHierarchyNode hierarchy) {
+    @TruffleBoundary
+    protected String toString(RS4Object obj, @SuppressWarnings("unused") String separator,
+                    @Cached("createWithImplicit()") ClassHierarchyNode hierarchy) {
         RStringVector classHierarchy = hierarchy.execute(obj);
-        Object clazz;
-        if (classHierarchy.getLength() > 0) {
-            clazz = toString(classHierarchy.getDataAt(0), true, separator);
-        } else {
+        if (classHierarchy.getLength() == 0) {
             throw RInternalError.shouldNotReachHere("S4 object has no class");
         }
-        return Utils.stringFormat("<S4 object of class %s>", clazz);
+        return "<S4 object of class \"" + classHierarchy.getDataAt(0) + "\">";
     }
 
-    @FunctionalInterface
-    private interface ElementFunction {
-        String apply(int index, boolean quotes, String separator);
-    }
+    private static final EnumMap<RType, String> EMPTY = new EnumMap<>(RType.class);
 
-    private static String createResultForVector(RAbstractVector vector, boolean quotes, String separator, String empty, ElementFunction elementFunction) {
-        CompilerAsserts.neverPartOfCompilation();
-        int length = vector.getLength();
-        if (length == 0) {
-            return empty;
-        }
-        StringBuilder b = new StringBuilder();
-        for (int i = 0; i < length; i++) {
-            if (i > 0) {
-                b.append(separator);
-            }
-            b.append(elementFunction.apply(i, quotes, separator));
-        }
-        return b.toString();
+    static {
+        EMPTY.put(RType.Integer, "integer(0)");
+        EMPTY.put(RType.Double, "numeric(0)");
+        EMPTY.put(RType.Character, "character(0)");
+        EMPTY.put(RType.Logical, "logical(0)");
+        EMPTY.put(RType.Raw, "raw(0)");
+        EMPTY.put(RType.Complex, "complex(0)");
+        EMPTY.put(RType.List, "list()");
     }
 
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RAbstractIntVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "integer(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s));
-    }
-
-    @Specialization
     @TruffleBoundary
-    protected String toString(RAbstractDoubleVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "numeric(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s));
-    }
-
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RAbstractStringVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "character(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s));
-    }
-
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RAbstractLogicalVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "logical(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s));
-    }
-
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RAbstractRawVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "raw(0)", (index, q, s) -> RRuntime.rawToHexString(vector.getRawDataAt(index)));
+    private String vectorToString(RAbstractVector vector, String separator, VectorAccess vectorAccess) {
+        try (SequentialIterator iter = vectorAccess.access(vector)) {
+            int length = vectorAccess.getLength(iter);
+            if (length == 0) {
+                return EMPTY.get(vectorAccess.getType());
+            }
+            StringBuilder b = new StringBuilder();
+            if (vectorAccess.next(iter)) {
+                while (true) {
+                    if (vectorAccess.getType() == RType.List) {
+                        Object value = vectorAccess.getListElement(iter);
+                        if (value instanceof RAbstractListVector) {
+                            RAbstractListVector l = (RAbstractListVector) value;
+                            if (l.getLength() == 0) {
+                                b.append("list()");
+                            } else {
+                                b.append("list(").append(toStringRecursive(l, separator)).append(')');
+                            }
+                        } else {
+                            b.append(toStringRecursive(value, separator));
+                        }
+                    } else {
+                        b.append(vectorAccess.getString(iter));
+                    }
+                    if (!vectorAccess.next(iter)) {
+                        break;
+                    }
+                    b.append(separator);
+                }
+            }
+            return b.toString();
+        }
     }
 
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RAbstractComplexVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "complex(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s));
+    @Specialization(guards = "vectorAccess.supports(vector)")
+    protected String toStringVectorCached(RAbstractVector vector, String separator,
+                    @Cached("vector.access()") VectorAccess vectorAccess) {
+        return vectorToString(vector, separator, vectorAccess);
     }
 
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RList vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "list()", (index, q, s) -> {
-            Object value = vector.getDataAt(index);
-            if (value instanceof RList) {
-                RList l = (RList) value;
-                if (l.getLength() == 0) {
-                    return "list()";
-                } else {
-                    return "list(" + toStringRecursive(l, q, s) + ')';
-                }
-            } else {
-                return toStringRecursive(value, q, s);
-            }
-        });
+    @Specialization(replaces = "toStringVectorCached")
+    protected String toStringVectorGeneric(RAbstractVector vector, String separator) {
+        return vectorToString(vector, separator, vector.slowPathAccess());
     }
 
     @SuppressWarnings("unused")
     @Specialization
     @TruffleBoundary
-    protected String toString(REnvironment env, boolean quotes, String separator) {
+    protected String toString(REnvironment env, String separator) {
         return env.toString();
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java
index 1f0892d7285603e2bf2950d8ba38a5b7df910ed3..170ac15bf2741ef642c1e946b024fe507c27fd92 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java
@@ -52,42 +52,45 @@ public abstract class UnaryArithmeticNode extends UnaryNode {
     public abstract Object execute(Object value);
 
     @Specialization(guards = {"cachedNode != null", "cachedNode.isSupported(operand)"})
-    protected Object doCached(Object operand,
+    protected Object doCached(RAbstractVector operand,
                     @Cached("createCachedFast(operand)") UnaryMapNode cachedNode) {
         return cachedNode.apply(operand);
     }
 
-    protected UnaryMapNode createCachedFast(Object operand) {
+    protected UnaryMapNode createCachedFast(RAbstractVector operand) {
         if (isNumericVector(operand)) {
-            return createCached(unary.createOperation(), operand);
+            return createCached(unary.createOperation(), operand, false);
         }
         return null;
     }
 
-    protected static UnaryMapNode createCached(UnaryArithmetic arithmetic, Object operand) {
+    protected static UnaryMapNode createCached(UnaryArithmetic arithmetic, Object operand, boolean isGeneric) {
         if (operand instanceof RAbstractVector) {
             RAbstractVector castOperand = (RAbstractVector) operand;
             RType operandType = castOperand.getRType();
             if (operandType.isNumeric()) {
                 RType type = RType.maxPrecedence(operandType, arithmetic.getMinPrecedence());
                 RType resultType = arithmetic.calculateResultType(type);
-                return UnaryMapNode.create(new ScalarUnaryArithmeticNode(arithmetic), castOperand, type, resultType);
+                return UnaryMapNode.create(new ScalarUnaryArithmeticNode(arithmetic), castOperand, type, resultType, isGeneric);
             }
         }
         return null;
     }
 
-    protected static boolean isNumericVector(Object value) {
+    protected static boolean isNumericVector(RAbstractVector value) {
         return value instanceof RAbstractIntVector || value instanceof RAbstractDoubleVector || value instanceof RAbstractComplexVector || value instanceof RAbstractLogicalVector;
     }
 
     @Specialization(replaces = "doCached", guards = {"isNumericVector(operand)"})
     @TruffleBoundary
-    protected Object doGeneric(Object operand,
+    protected Object doGeneric(RAbstractVector operand,
                     @Cached("unary.createOperation()") UnaryArithmetic arithmetic,
-                    @Cached("new(createCached(arithmetic, operand))") GenericNumericVectorNode generic) {
-        RAbstractVector operandVector = (RAbstractVector) operand;
-        return generic.get(arithmetic, operandVector).apply(operandVector);
+                    @Cached("createGeneric()") GenericNumericVectorNode generic) {
+        return generic.get(arithmetic, operand).apply(operand);
+    }
+
+    protected static GenericNumericVectorNode createGeneric() {
+        return new GenericNumericVectorNode();
     }
 
     @Override
@@ -110,16 +113,12 @@ public abstract class UnaryArithmeticNode extends UnaryNode {
 
         @Child private UnaryMapNode cached;
 
-        public GenericNumericVectorNode(UnaryMapNode cachedOperation) {
-            this.cached = cachedOperation;
-        }
-
         public UnaryMapNode get(UnaryArithmetic arithmetic, RAbstractVector operand) {
-            UnaryMapNode next = cached;
-            if (!next.isSupported(operand)) {
-                next = cached.replace(createCached(arithmetic, operand));
+            UnaryMapNode map = cached;
+            if (map == null || !map.isSupported(operand)) {
+                cached = map = insert(createCached(arithmetic, operand, true));
             }
-            return next;
+            return map;
         }
     }
 }
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 4f2f375192eb681092cf8f87eef33ad04c367e80..7230d7b17e60bd571680b3792d0dc235d8562e0c 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
@@ -22,17 +22,17 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
-import com.oracle.truffle.r.nodes.control.RLengthNode;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
@@ -42,8 +42,8 @@ import com.oracle.truffle.r.runtime.data.RTypes;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.nodes.EnableNACheckNode;
-import com.oracle.truffle.r.runtime.data.nodes.VectorIterator;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
@@ -57,6 +57,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
  * only applies to some types (e.g. double or integer), for other types 'finite' seems to be ignored
  * (e.g. logical). The only situation where semantics of finite is different to na.rm is double
  * values: na.rm removes NA and NaN, but not -/+Inf.
+ *
+ * FastR handles finite consistently (setting na.rm = TRUE if finite = TRUE) in the range builtin.
  */
 @ImportStatic({RRuntime.class})
 @TypeSystemReference(RTypes.class)
@@ -64,7 +66,6 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
 
     public abstract Object executeReduce(Object value, boolean naRm, boolean finite);
 
-    @Child private MultiElemStringHandlerNode stringHandler;
     @Child private BinaryArithmetic arithmetic;
 
     private final BinaryArithmeticFactory factory;
@@ -74,6 +75,8 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
 
     private final NACheck na = NACheck.create();
     private final ConditionProfile naRmProfile = ConditionProfile.createBinaryProfile();
+    private final BranchProfile emptyProfile = BranchProfile.create();
+    private final BranchProfile naResultProfile = BranchProfile.create();
 
     protected UnaryArithmeticReduceNode(ReduceSemantics semantics, BinaryArithmeticFactory factory) {
         this.factory = factory;
@@ -83,21 +86,15 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
         this.supportComplex = semantics.supportComplex;
     }
 
-    private String handleString(RStringVector operand, boolean naRm, boolean finite, int offset) {
-        if (stringHandler == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            stringHandler = insert(new MultiElemStringHandlerNode(semantics, factory, na));
-        }
-        return stringHandler.executeString(operand, naRm, finite, offset);
-    }
-
     private void emptyWarning() {
+        emptyProfile.enter();
         if (semantics.getEmptyWarning() != null) {
             warning(semantics.emptyWarning);
         }
     }
 
     private void naResultWarning() {
+        naResultProfile.enter();
         if (semantics.getNAResultWarning() != null) {
             warning(semantics.getNAResultWarning());
         }
@@ -136,20 +133,23 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
     protected double doDouble(double operand, boolean naRm, boolean finite,
                     @Cached("createBinaryProfile()") ConditionProfile finiteProfile,
                     @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile) {
+        if (finiteProfile.profile(finite) && isInfiniteProfile.profile(!RRuntime.isFinite(operand))) {
+            emptyWarning();
+            return semantics.getIntStart();
+        }
         na.enable(operand);
-        if (naRmProfile.profile(naRm || finite)) {
-            boolean profiledFinite = finiteProfile.profile(finite);
-            if (na.checkNAorNaN(operand) || (profiledFinite && isInfiniteProfile.profile(!RRuntime.isFinite(operand)))) {
+        if (naRmProfile.profile(naRm)) {
+            if (na.checkNAorNaN(operand)) {
                 // the only value we have should be removed...
                 emptyWarning();
                 return semantics.getIntStart();
             } else {
+                // known not to be NA or NaN
                 return operand;
             }
-        } else {
-            // since !naRm and !finite, NaN or +/-Inf can be valid results
-            return na.check(operand) ? RRuntime.DOUBLE_NA : operand;
         }
+        // since !naRm and !finite, NaN or +/-Inf can be valid results
+        return na.check(operand) ? RRuntime.DOUBLE_NA : operand;
     }
 
     @Specialization
@@ -199,35 +199,47 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
         }
     }
 
-    @Specialization
-    protected Object doIntVector(RAbstractIntVector operand, boolean naRm, boolean finite,
-                    @Cached("create()") EnableNACheckNode enableNACheckNode,
-                    @Cached("create()") RLengthNode lengthNode,
-                    @Cached("create()") VectorIterator.Int iterator) {
-        RBaseNode.reportWork(this, lengthNode.executeInteger(operand));
-        boolean profiledNaRm = naRmProfile.profile(naRm || finite);
+    private Object doInt(RAbstractVector vector, boolean naRm, VectorAccess access) {
+        boolean profiledNaRm = naRmProfile.profile(naRm);
         int result = semantics.getIntStart();
-        enableNACheckNode.execute(na, operand);
-        int opCount = 0;
-        Object it = iterator.init(operand);
-        while (iterator.hasNext(operand, it)) {
-            int d = iterator.next(operand, it);
-            if (na.check(d)) {
-                if (profiledNaRm) {
-                    continue;
-                } else {
-                    return RRuntime.INT_NA;
+        boolean empty = true;
+        try (VectorAccess.SequentialIterator iter = access.access(vector)) {
+            while (access.next(iter)) {
+                int d;
+                switch (access.getType()) {
+                    case Integer:
+                        d = access.getInt(iter);
+                        if (access.na.check(d)) {
+                            if (profiledNaRm) {
+                                continue;
+                            } else {
+                                return RRuntime.INT_NA;
+                            }
+                        }
+                        break;
+                    case Logical:
+                        byte logical = access.getLogical(iter);
+                        if (access.na.check(logical)) {
+                            if (profiledNaRm) {
+                                continue;
+                            } else {
+                                return RRuntime.INT_NA;
+                            }
+                        }
+                        d = logical; // 0 or 1
+                        break;
+                    default:
+                        throw RInternalError.shouldNotReachHere();
                 }
-            } else {
                 result = arithmetic.op(result, d);
                 if (RRuntime.isNA(result)) {
                     naResultWarning();
                     return RRuntime.INT_NA;
                 }
+                empty = false;
             }
-            opCount++;
         }
-        if (opCount == 0) {
+        if (empty) {
             emptyWarning();
             if (semantics.isUseDoubleStartForEmptyVector()) {
                 return semantics.getDoubleStart();
@@ -236,88 +248,79 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
         return result;
     }
 
-    @Specialization
-    protected double doDoubleVector(RAbstractDoubleVector operand, boolean naRm, boolean finite,
-                    @Cached("create()") EnableNACheckNode enableNACheckNode,
-                    @Cached("create()") RLengthNode lengthNode,
-                    @Cached("create()") VectorIterator.Double iterator,
-                    @Cached("createBinaryProfile()") ConditionProfile finiteProfile,
-                    @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile) {
-        RBaseNode.reportWork(this, lengthNode.executeInteger(operand));
-        boolean profiledNaRm = naRmProfile.profile(naRm || finite);
-        boolean profiledFinite = finiteProfile.profile(finite);
-        double result = semantics.getDoubleStart();
-        enableNACheckNode.execute(na, operand);
-        int opCount = 0;
+    @Specialization(guards = "access.supports(vector)")
+    protected Object doIntCached(RAbstractIntVector vector, boolean naRm, @SuppressWarnings("unused") boolean finite,
+                    @Cached("vector.access()") VectorAccess access) {
+        return doInt(vector, naRm, access);
+    }
 
-        Object it = iterator.init(operand);
-        while (iterator.hasNext(operand, it)) {
-            double d = iterator.next(operand, it);
-            if (na.checkNAorNaN(d)) {
-                if (profiledNaRm) {
-                    continue;   // ignore NA/NaN
-                } else if (na.check(d)) {
-                    // NA produces NA directly, but NaN should be handled by arithmetics.op to
-                    // produce NaN. We cannot directly return NaN because if we encounter NA later
-                    // on, we should return NA not NaN
-                    return RRuntime.DOUBLE_NA;
-                }
-            } else if (profiledFinite && isInfiniteProfile.profile(!RRuntime.isFinite(d))) {
-                // ignore -/+Inf if 'infinite == TRUE'
-                continue;
-            }
+    @Specialization(replaces = "doIntCached")
+    protected Object doIntGeneric(RAbstractIntVector vector, boolean naRm, @SuppressWarnings("unused") boolean finite) {
+        return doInt(vector, naRm, vector.slowPathAccess());
+    }
 
-            result = arithmetic.op(result, d);
-            opCount++;
-        }
-        if (opCount == 0) {
-            emptyWarning();
-        }
-        return result;
+    @Specialization(guards = "access.supports(vector)")
+    protected Object doLogicalCached(RAbstractLogicalVector vector, boolean naRm, @SuppressWarnings("unused") boolean finite,
+                    @Cached("vector.access()") VectorAccess access) {
+        return doInt(vector, naRm, access);
     }
 
-    @Specialization
-    protected Object doLogicalVector(RAbstractLogicalVector operand, boolean naRm, @SuppressWarnings("unused") boolean finite,
-                    @Cached("create()") EnableNACheckNode enableNACheckNode,
-                    @Cached("create()") RLengthNode lengthNode,
-                    @Cached("create()") VectorIterator.Logical iterator) {
-        RBaseNode.reportWork(this, lengthNode.executeInteger(operand));
-        boolean profiledNaRm = naRmProfile.profile(naRm);
-        int result = semantics.getIntStart();
-        enableNACheckNode.execute(na, operand);
-        int opCount = 0;
+    @Specialization(replaces = "doIntCached")
+    protected Object doLogicalGeneric(RAbstractLogicalVector vector, boolean naRm, @SuppressWarnings("unused") boolean finite) {
+        return doInt(vector, naRm, vector.slowPathAccess());
+    }
 
-        Object it = iterator.init(operand);
-        while (iterator.hasNext(operand, it)) {
-            byte d = iterator.next(operand, it);
-            if (na.check(d)) {
-                if (profiledNaRm) {
+    private double doDouble(RAbstractDoubleVector vector, boolean naRm, boolean finite, ConditionProfile finiteProfile, ConditionProfile isInfiniteProfile, VectorAccess access) {
+        boolean profiledNaRm = naRmProfile.profile(naRm);
+        boolean profiledFinite = finiteProfile.profile(finite);
+        double result = semantics.getDoubleStart();
+        boolean empty = true;
+        try (VectorAccess.SequentialIterator iter = access.access(vector)) {
+            while (access.next(iter)) {
+                double d = access.getDouble(iter);
+                if (access.na.checkNAorNaN(d)) {
+                    if (profiledNaRm) {
+                        continue;   // ignore NA/NaN
+                    } else if (access.na.check(d)) {
+                        // NA produces NA directly, but NaN should be handled by arithmetics.op to
+                        // produce NaN. We cannot directly return NaN because if we encounter NA
+                        // later
+                        // on, we should return NA not NaN
+                        return RRuntime.DOUBLE_NA;
+                    }
+                } else if (profiledFinite && isInfiniteProfile.profile(!RRuntime.isFinite(d))) {
+                    // ignore -/+Inf if 'infinite == TRUE'
                     continue;
-                } else {
-                    return RRuntime.INT_NA;
                 }
-            } else {
                 result = arithmetic.op(result, d);
-                if (RRuntime.isNA(result)) {
-                    naResultWarning();
-                    return RRuntime.INT_NA;
-                }
+                empty = false;
             }
-            opCount++;
         }
-        if (opCount == 0) {
+        if (empty) {
             emptyWarning();
-            if (semantics.isUseDoubleStartForEmptyVector()) {
-                return semantics.getDoubleStart();
-            }
         }
         return result;
     }
 
+    @Specialization(guards = "access.supports(vector)")
+    protected double doDoubleCached(RAbstractDoubleVector vector, boolean naRm, boolean finite,
+                    @Cached("createBinaryProfile()") ConditionProfile finiteProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile,
+                    @Cached("vector.access()") VectorAccess access) {
+        return doDouble(vector, naRm, finite, finiteProfile, isInfiniteProfile, access);
+    }
+
+    @Specialization(replaces = "doDoubleCached")
+    protected double doDoubleGeneric(RAbstractDoubleVector vector, boolean naRm, boolean finite,
+                    @Cached("createBinaryProfile()") ConditionProfile finiteProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile) {
+        return doDouble(vector, naRm, finite, finiteProfile, isInfiniteProfile, vector.slowPathAccess());
+    }
+
     @Specialization(guards = "supportComplex")
-    protected RComplex doComplexVector(RComplexVector operand, boolean naRm, boolean finite) {
+    protected RComplex doComplexVector(RComplexVector operand, boolean naRm, @SuppressWarnings("unused") boolean finite) {
         RBaseNode.reportWork(this, operand.getLength());
-        boolean profiledNaRm = naRmProfile.profile(naRm || finite);
+        boolean profiledNaRm = naRmProfile.profile(naRm);
         RComplex result = RRuntime.double2complex(semantics.getDoubleStart());
         int opCount = 0;
         na.enable(operand);
@@ -344,18 +347,14 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
     // does not work for String-s as, in particular, we cannot supply the (lexicographically)
     // "largest" String for the implementation of max function
 
-    private static String doStringVectorEmptyInternal(ReduceSemantics semantics, RBaseNode invokingNode) {
+    @Specialization(guards = {"supportString", "operand.getLength() == 0"})
+    protected String doStringVectorEmpty(@SuppressWarnings("unused") RStringVector operand, @SuppressWarnings("unused") boolean naRm, @SuppressWarnings("unused") boolean finite) {
         if (semantics.getEmptyWarning() != null) {
-            RError.warning(invokingNode, semantics.emptyWarningCharacter);
+            warning(semantics.emptyWarningCharacter);
         }
         return semantics.getStringStart();
     }
 
-    @Specialization(guards = {"supportString", "operand.getLength() == 0"})
-    protected String doStringVectorEmpty(@SuppressWarnings("unused") RStringVector operand, @SuppressWarnings("unused") boolean naRm, @SuppressWarnings("unused") boolean finite) {
-        return doStringVectorEmptyInternal(semantics, this);
-    }
-
     @Specialization(guards = {"supportString", "operand.getLength() == 1"})
     protected String doStringVectorOneElem(RStringVector operand, boolean naRm, boolean finite) {
         boolean profiledNaRm = naRmProfile.profile(naRm);
@@ -371,7 +370,40 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
 
     @Specialization(guards = {"supportString", "operand.getLength() > 1"})
     protected String doStringVector(RStringVector operand, boolean naRm, boolean finite) {
-        return handleString(operand, naRm, finite, 0);
+        boolean profiledNaRm = naRmProfile.profile(naRm);
+        na.enable(operand);
+        int offset = 0;
+        String result = operand.getDataAt(offset);
+        if (profiledNaRm) {
+            while (na.check(result)) {
+                // the following is meant to eliminate leading NA-s
+                if (offset == operand.getLength() - 1) {
+                    // last element - all other are NAs
+                    return doStringVectorEmpty(operand, naRm, finite);
+                }
+                result = operand.getDataAt(++offset);
+            }
+        } else {
+            if (na.check(result)) {
+                return result;
+            }
+        }
+        // when we reach here, it means that we have already seen one non-NA element
+        assert !RRuntime.isNA(result);
+        for (int i = offset + 1; i < operand.getLength(); i++) {
+            String current = operand.getDataAt(i);
+            if (na.check(current)) {
+                if (profiledNaRm) {
+                    // skip NA-s
+                    continue;
+                } else {
+                    return RRuntime.STRING_NA;
+                }
+            } else {
+                result = arithmetic.op(result, current);
+            }
+        }
+        return result;
     }
 
     @Specialization(guards = {"isForeignObject(obj)"})
@@ -452,67 +484,4 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
             return useDoubleStartForEmptyVector;
         }
     }
-
-    private static final class MultiElemStringHandlerNode extends RBaseNode {
-
-        @Child private MultiElemStringHandlerNode recursiveStringHandler;
-        @Child private BinaryArithmetic arithmetic;
-
-        private final ReduceSemantics semantics;
-        private final BinaryArithmeticFactory factory;
-        private final NACheck na;
-        private final ConditionProfile naRmProfile = ConditionProfile.createBinaryProfile();
-
-        MultiElemStringHandlerNode(ReduceSemantics semantics, BinaryArithmeticFactory factory, NACheck na) {
-            this.semantics = semantics;
-            this.factory = factory;
-            this.arithmetic = factory.createOperation();
-            this.na = na;
-        }
-
-        private String handleString(RStringVector operand, boolean naRm, boolean finite, int offset) {
-            if (recursiveStringHandler == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                recursiveStringHandler = insert(new MultiElemStringHandlerNode(semantics, factory, na));
-            }
-            return recursiveStringHandler.executeString(operand, naRm, finite, offset);
-        }
-
-        public String executeString(RStringVector operand, boolean naRm, boolean finite, int offset) {
-            boolean profiledNaRm = naRmProfile.profile(naRm);
-            na.enable(operand);
-            String result = operand.getDataAt(offset);
-            if (profiledNaRm) {
-                if (na.check(result)) {
-                    // the following is meant to eliminate leading NA-s
-                    if (offset == operand.getLength() - 1) {
-                        // last element - all other are NAs
-                        return doStringVectorEmptyInternal(semantics, this);
-                    } else {
-                        return handleString(operand, naRm, finite, offset + 1);
-                    }
-                }
-            } else {
-                if (na.check(result)) {
-                    return result;
-                }
-            }
-            // when we reach here, it means that we have already seen one non-NA element
-            assert !RRuntime.isNA(result);
-            for (int i = offset + 1; i < operand.getLength(); i++) {
-                String current = operand.getDataAt(i);
-                if (na.check(current)) {
-                    if (profiledNaRm) {
-                        // skip NA-s
-                        continue;
-                    } else {
-                        return RRuntime.STRING_NA;
-                    }
-                } else {
-                    result = arithmetic.op(result, current);
-                }
-            }
-            return result;
-        }
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java
index acd72feaf1484c0c8e4a36165d7538c523617628..1ee0499aa4ace76f7fa3e2b83eadb38ac6d32d38 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java
@@ -32,34 +32,37 @@ import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.Message;
 import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RList;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
+import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory;
 import com.oracle.truffle.r.runtime.data.RRaw;
-import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.RVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
+import com.oracle.truffle.r.runtime.data.nodes.VectorReuse;
 import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
-import com.oracle.truffle.r.runtime.ops.na.NACheck;
 import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
-@ImportStatic({RRuntime.class})
+@ImportStatic({RRuntime.class, ForeignArray2R.class, Message.class, RType.class})
 @RBuiltin(name = "!", kind = PRIMITIVE, parameterNames = {""}, dispatch = OPS_GROUP_GENERIC, behavior = PURE_ARITHMETIC)
 public abstract class UnaryNotNode extends RBuiltinNode.Arg1 {
 
-    private final NACheck na = NACheck.create();
     private final NAProfile naProfile = NAProfile.create();
-    private final ConditionProfile zeroLengthProfile = ConditionProfile.createBinaryProfile();
+
+    @Child private GetDimAttributeNode getDims = GetDimAttributeNode.create();
+    @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create();
+    @Child private GetDimNamesAttributeNode getDimNames = GetDimNamesAttributeNode.create();
 
     static {
         Casts.noCasts(UnaryNotNode.class);
@@ -77,10 +80,6 @@ public abstract class UnaryNotNode extends RBuiltinNode.Arg1 {
         return RRuntime.asLogical(operand == 0);
     }
 
-    private static byte not(RComplex operand) {
-        return RRuntime.asLogical(operand.getRealPart() == 0 && operand.getImaginaryPart() == 0);
-    }
-
     private static byte notRaw(RRaw operand) {
         return notRaw(operand.getValue());
     }
@@ -109,112 +108,83 @@ public abstract class UnaryNotNode extends RBuiltinNode.Arg1 {
         return RDataFactory.createRaw(notRaw(operand));
     }
 
-    @Specialization
-    protected RLogicalVector doLogicalVector(RLogicalVector vector) {
-        int length = vector.getLength();
-        byte[] result;
-        if (zeroLengthProfile.profile(length == 0)) {
-            result = new byte[0];
-        } else {
-            na.enable(vector);
-            result = new byte[length];
-            for (int i = 0; i < length; i++) {
-                byte value = vector.getDataAt(i);
-                result[i] = na.check(value) ? RRuntime.LOGICAL_NA : not(value);
+    @Specialization(guards = {"vectorAccess.supports(vector)", "reuse.supports(vector)"})
+    protected RAbstractVector doLogicalVectorCached(RAbstractLogicalVector vector,
+                    @Cached("vector.access()") VectorAccess vectorAccess,
+                    @Cached("createTemporary(vector)") VectorReuse reuse) {
+        RAbstractVector result = reuse.getResult(vector);
+        VectorAccess resultAccess = reuse.access(result);
+        try (SequentialIterator vectorIter = vectorAccess.access(vector); SequentialIterator resultIter = resultAccess.access(result)) {
+            while (vectorAccess.next(vectorIter) && resultAccess.next(resultIter)) {
+                byte value = vectorAccess.getLogical(vectorIter);
+                resultAccess.setLogical(resultIter, vectorAccess.na.check(value) ? RRuntime.LOGICAL_NA : not(value));
             }
         }
-        RLogicalVector resultVector = RDataFactory.createLogicalVector(result, na.neverSeenNA());
-        resultVector.copyAttributesFrom(vector);
-        return resultVector;
-    }
-
-    @Specialization
-    protected RLogicalVector doIntVector(RAbstractIntVector vector) {
-        int length = vector.getLength();
-        byte[] result;
-        if (zeroLengthProfile.profile(length == 0)) {
-            result = new byte[0];
-        } else {
-            na.enable(vector);
-            result = new byte[length];
-            for (int i = 0; i < length; i++) {
-                int value = vector.getDataAt(i);
-                result[i] = na.check(value) ? RRuntime.LOGICAL_NA : not(value);
-            }
-        }
-        RLogicalVector resultVector = RDataFactory.createLogicalVector(result, na.neverSeenNA());
-        copyNamesDimsDimNames(vector, resultVector);
-        return resultVector;
-    }
-
-    @Specialization
-    protected RLogicalVector doDoubleVector(RAbstractDoubleVector vector) {
-        int length = vector.getLength();
-        byte[] result;
-        if (zeroLengthProfile.profile(length == 0)) {
-            result = new byte[0];
-        } else {
-            na.enable(vector);
-            result = new byte[length];
-            for (int i = 0; i < length; i++) {
-                double value = vector.getDataAt(i);
-                result[i] = na.check(value) ? RRuntime.LOGICAL_NA : not(value);
-            }
-        }
-        RLogicalVector resultVector = RDataFactory.createLogicalVector(result, na.neverSeenNA());
-        copyNamesDimsDimNames(vector, resultVector);
-        return resultVector;
-    }
-
-    @Specialization
-    protected RLogicalVector doComplexVector(RAbstractComplexVector vector) {
-        int length = vector.getLength();
-        byte[] result;
-        if (zeroLengthProfile.profile(length == 0)) {
-            result = new byte[0];
-        } else {
-            na.enable(vector);
-            result = new byte[length];
-            for (int i = 0; i < length; i++) {
-                RComplex value = vector.getDataAt(i);
-                result[i] = na.check(value) ? RRuntime.LOGICAL_NA : not(value);
-            }
-        }
-        RLogicalVector resultVector = RDataFactory.createLogicalVector(result, na.neverSeenNA());
-        copyNamesDimsDimNames(vector, resultVector);
-        return resultVector;
+        result.setComplete(vectorAccess.na.neverSeenNA());
+        return result;
     }
 
+    @Specialization(replaces = "doLogicalVectorCached")
     @TruffleBoundary
-    private void copyNamesDimsDimNames(RAbstractVector vector, RLogicalVector resultVector) {
-        resultVector.copyNamesDimsDimNamesFrom(vector, this);
-    }
-
-    @Specialization
-    protected RRawVector doRawVector(RRawVector vector) {
-        int length = vector.getLength();
-        byte[] result;
-        if (zeroLengthProfile.profile(length == 0)) {
-            result = new byte[0];
-        } else {
-            result = new byte[length];
-            for (int i = 0; i < length; i++) {
-                result[i] = notRaw(vector.getRawDataAt(i));
+    protected RAbstractVector doLogicalGenericGeneric(RAbstractLogicalVector vector,
+                    @Cached("createTemporaryGeneric()") VectorReuse reuse) {
+        return doLogicalVectorCached(vector, vector.slowPathAccess(), reuse);
+    }
+
+    @Specialization(guards = {"vectorAccess.supports(vector)", "!isRAbstractLogicalVector(vector)"})
+    protected RAbstractVector doVectorCached(RAbstractVector vector,
+                    @Cached("vector.access()") VectorAccess vectorAccess,
+                    @Cached("createNew(Logical)") VectorAccess resultAccess,
+                    @Cached("createNew(Raw)") VectorAccess rawResultAccess,
+                    @Cached("create()") VectorFactory factory) {
+        try (SequentialIterator vectorIter = vectorAccess.access(vector)) {
+            int length = vectorAccess.getLength(vectorIter);
+            RAbstractVector result;
+            switch (vectorAccess.getType()) {
+                case Character:
+                case List:
+                case Expression:
+                    // special cases:
+                    if (length == 0) {
+                        return factory.createEmptyLogicalVector();
+                    } else {
+                        throw error(RError.Message.INVALID_ARG_TYPE);
+                    }
+                case Raw:
+                    result = factory.createRawVector(length);
+                    try (SequentialIterator resultIter = rawResultAccess.access(result)) {
+                        // raw does not produce a logical result, but (255 - value)
+                        while (vectorAccess.next(vectorIter) && rawResultAccess.next(resultIter)) {
+                            rawResultAccess.setRaw(resultIter, notRaw(vectorAccess.getRaw(vectorIter)));
+                        }
+                    }
+                    ((RVector<?>) result).copyAttributesFrom(vector);
+                    break;
+                default:
+                    result = factory.createLogicalVector(length, false);
+                    try (SequentialIterator resultIter = resultAccess.access(result)) {
+                        while (vectorAccess.next(vectorIter) && resultAccess.next(resultIter)) {
+                            byte value = vectorAccess.getLogical(vectorIter);
+                            resultAccess.setLogical(resultIter, vectorAccess.na.check(value) ? RRuntime.LOGICAL_NA : not(value));
+                        }
+                    }
+                    if (vectorAccess.getType() == RType.Logical) {
+                        ((RVector<?>) result).copyAttributesFrom(vector);
+                    } else {
+                        factory.reinitializeAttributes((RVector<?>) result, getDims.getDimensions(vector), getNames.getNames(vector), getDimNames.getDimNames(vector));
+                    }
+                    break;
             }
+            result.setComplete(vectorAccess.na.neverSeenNA());
+            return result;
         }
-        RRawVector resultVector = RDataFactory.createRawVector(result);
-        resultVector.copyAttributesFrom(vector);
-        return resultVector;
     }
 
-    @Specialization(guards = {"vector.getLength() == 0"})
-    protected RLogicalVector doStringVector(@SuppressWarnings("unused") RAbstractStringVector vector) {
-        return RDataFactory.createEmptyLogicalVector();
-    }
-
-    @Specialization(guards = {"list.getLength() == 0"})
-    protected RLogicalVector doList(@SuppressWarnings("unused") RList list) {
-        return RDataFactory.createEmptyLogicalVector();
+    @Specialization(replaces = "doVectorCached", guards = "!isRAbstractLogicalVector(vector)")
+    @TruffleBoundary
+    protected RAbstractVector doGenericGeneric(RAbstractVector vector,
+                    @Cached("create()") VectorFactory factory) {
+        return doVectorCached(vector, vector.slowPathAccess(), VectorAccess.createSlowPathNew(RType.Logical), VectorAccess.createSlowPathNew(RType.Raw), factory);
     }
 
     @Specialization(guards = {"isForeignObject(obj)"})
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
index 090cd5aa987d71ee1ac1da2c7155bc2e7643cdd2..5a9c503079500a97603e9ffdb595104feaa5314e 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
@@ -62,6 +62,7 @@ public enum FastROptions {
     EmitTmpHashed("Use an SHA-256 hash as file name to reduce temporary file creation.", true),
     SpawnUsesPolyglot("use PolyglotEngine for .fastr.context.spwan", false),
     SynchronizeNativeCode("allow only one thread to enter packages' native code", false),
+    ForeignObjectWrappers("use wrappers for foreign objects (as opposed to full conversion)", false),
 
     // Promises optimizations
     EagerEval("If enabled, overrides all other EagerEval switches (see EagerEvalHelper)", false),
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
index 2cc2e1bba7016ef1c6e6ac5ce4f6336a53f9ede4..d1962cdbda9885bcd08be41996fc7601e025e062 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
@@ -789,7 +789,7 @@ public class RErrorHandling {
         String preamble = kind;
         String errorMsg = null;
         assert call instanceof RNull || call instanceof RLanguage;
-        if (call == RNull.instance || ((RLanguage) call).getRep().getSourceSection() == null) {
+        if (call == RNull.instance) {
             // generally means top-level of shell or similar
             preamble += ": ";
             errorMsg = preamble + formattedMsg;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
index d3965fab24e62015dbb1b7fe3377b7ca5df88c39..b1bc38b64be0efeffb3e466b46e68d2618ff880c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
@@ -68,6 +68,10 @@ public class RRuntime {
 
     //@formatter:on
 
+    // used in DSL expressions:
+    public static final boolean True = true;
+    public static final boolean False = false;
+
     public static final String R_APP_MIME = "application/x-r";
     public static final String R_TEXT_MIME = "text/x-r";
 
@@ -352,11 +356,6 @@ public class RRuntime {
         return rawStringCache[raw2int(operand)];
     }
 
-    @TruffleBoundary
-    public static String rawToString(byte operand) {
-        return intToString(raw2int(operand));
-    }
-
     // conversions from string
 
     @TruffleBoundary
@@ -762,6 +761,10 @@ public class RRuntime {
         return isNA(value.getRealPart()) || isNA(value.getImaginaryPart());
     }
 
+    public static boolean isNA(double real, double imag) {
+        return isNA(real) || isNA(imag);
+    }
+
     @TruffleBoundary
     public static String escapeString(String value, boolean encodeNonASCII, boolean quote) {
         if (isNA(value)) {
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 3b5cda9b10a5638ac01ece23836d09c25780e9f6..33167db9996d17a6e913220a05b9681bd97fb8da 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
@@ -53,10 +53,8 @@ import com.oracle.truffle.r.runtime.data.Closure;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.REmpty;
-import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
@@ -66,7 +64,6 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RPromise.PromiseState;
-import com.oracle.truffle.r.runtime.data.RRawVector;
 import com.oracle.truffle.r.runtime.data.RScalar;
 import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -77,11 +74,14 @@ import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractListBaseVector;
 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.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.frame.ActiveBinding;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
@@ -1262,10 +1262,8 @@ public class RSerialize {
         }
     }
 
-    // Serialize support is currently very limited, essentially to saving the CRAN package format
-    // info,
-
     private abstract static class POutputStream {
+
         protected OutputStream os;
 
         POutputStream(OutputStream os) {
@@ -1278,7 +1276,7 @@ public class RSerialize {
 
         abstract void writeDouble(double value) throws IOException;
 
-        abstract void writeRaw(byte[] value) throws IOException;
+        abstract void writeRaw(byte value) throws IOException;
 
         abstract void flush() throws IOException;
 
@@ -1339,16 +1337,9 @@ public class RSerialize {
         }
 
         @Override
-        void writeRaw(byte[] value) throws IOException {
-            int valueLen = value.length;
-            if (valueLen > buf.length) {
-                flushBuffer();
-                os.write(value);
-            } else {
-                ensureSpace(valueLen);
-                System.arraycopy(value, 0, buf, offset, valueLen);
-                offset += valueLen;
-            }
+        void writeRaw(byte value) throws IOException {
+            ensureSpace(1);
+            buf[offset++] = value;
         }
 
         @Override
@@ -1480,6 +1471,9 @@ public class RSerialize {
             Object obj = objArg;
             boolean tailCall;
             do {
+                // convert primitive types into RAbstractVectors
+                obj = RRuntime.asAbstractVector(obj);
+
                 tailCall = false;
                 SEXPTYPE specialType;
                 Object psn;
@@ -1548,70 +1542,49 @@ public class RSerialize {
                         stream.writeInt(flags);
                         switch (type) {
                             case STRSXP: {
-                                if (obj instanceof String) {
-                                    // length 1 vector
-                                    stream.writeInt(1);
-                                    writeCHARSXP((String) obj);
-                                } else {
-                                    outStringVec((RAbstractStringVector) obj, true);
-                                }
+                                outStringVec((RAbstractStringVector) obj, true);
                                 break;
                             }
 
-                            case INTSXP: {
-                                if (obj instanceof Integer) {
-                                    stream.writeInt(1);
-                                    stream.writeInt((int) obj);
-                                } else {
-                                    RAbstractIntVector vec = (RAbstractIntVector) obj;
-                                    stream.writeInt(vec.getLength());
-                                    for (int i = 0; i < vec.getLength(); i++) {
-                                        stream.writeInt(vec.getDataAt(i));
+                            case INTSXP:
+                            case LGLSXP: {
+                                // logicals are written as ints
+                                RAbstractVector vector = (RAbstractVector) obj;
+                                VectorAccess access = vector.slowPathAccess();
+                                try (SequentialIterator iter = access.access(vector)) {
+                                    stream.writeInt(access.getLength(iter));
+                                    while (access.next(iter)) {
+                                        stream.writeInt(access.getInt(iter));
                                     }
                                 }
                                 break;
                             }
 
                             case REALSXP: {
-                                if (obj instanceof Double) {
-                                    stream.writeInt(1);
-                                    stream.writeDouble((double) obj);
-                                } else {
-                                    RAbstractDoubleVector vec = (RAbstractDoubleVector) obj;
-                                    stream.writeInt(vec.getLength());
-                                    for (int i = 0; i < vec.getLength(); i++) {
-                                        stream.writeDouble(vec.getDataAt(i));
-                                    }
-                                }
-                                break;
-                            }
-
-                            case LGLSXP: {
-                                // Output as ints
-                                if (obj instanceof Byte) {
-                                    stream.writeInt(1);
-                                    stream.writeInt(RRuntime.logical2int((byte) obj));
-                                } else {
-                                    RAbstractLogicalVector vec = (RAbstractLogicalVector) obj;
-                                    stream.writeInt(vec.getLength());
-                                    for (int i = 0; i < vec.getLength(); i++) {
-                                        stream.writeInt(RRuntime.logical2int(vec.getDataAt(i)));
+                                RAbstractDoubleVector vector = (RAbstractDoubleVector) obj;
+                                VectorAccess access = vector.slowPathAccess();
+                                try (SequentialIterator iter = access.access(vector)) {
+                                    stream.writeInt(access.getLength(iter));
+                                    while (access.next(iter)) {
+                                        stream.writeDouble(access.getDouble(iter));
                                     }
                                 }
                                 break;
                             }
 
                             case CPLXSXP: {
-                                RAbstractComplexVector vec = (RAbstractComplexVector) obj;
-                                stream.writeInt(vec.getLength());
-                                for (int i = 0; i < vec.getLength(); i++) {
-                                    RComplex val = vec.getDataAt(i);
-                                    if (RRuntime.isNA(val)) {
-                                        stream.writeDouble(RRuntime.DOUBLE_NA);
-                                        stream.writeDouble(RRuntime.DOUBLE_NA);
-                                    } else {
-                                        stream.writeDouble(val.getRealPart());
-                                        stream.writeDouble(val.getImaginaryPart());
+                                RAbstractComplexVector vector = (RAbstractComplexVector) obj;
+                                VectorAccess access = vector.slowPathAccess();
+                                try (SequentialIterator iter = access.access(vector)) {
+                                    stream.writeInt(access.getLength(iter));
+                                    while (access.next(iter)) {
+                                        if (access.isNA(iter)) {
+                                            stream.writeDouble(RRuntime.DOUBLE_NA);
+                                            stream.writeDouble(RRuntime.DOUBLE_NA);
+                                        } else {
+                                            stream.writeDouble(access.getComplexR(iter));
+                                            stream.writeDouble(access.getComplexI(iter));
+                                        }
                                     }
                                 }
                                 break;
@@ -1619,25 +1592,26 @@ public class RSerialize {
 
                             case EXPRSXP:
                             case VECSXP: {
-                                RAbstractVector list;
-                                if (type == SEXPTYPE.EXPRSXP) {
-                                    list = (RExpression) obj;
-                                } else {
-                                    list = (RList) obj;
-                                }
-                                stream.writeInt(list.getLength());
-                                for (int i = 0; i < list.getLength(); i++) {
-                                    Object listObj = list.getDataAtAsObject(i);
-                                    writeItem(listObj);
+                                RAbstractListBaseVector vector = (RAbstractListBaseVector) obj;
+                                VectorAccess access = vector.slowPathAccess();
+                                try (SequentialIterator iter = access.access(vector)) {
+                                    stream.writeInt(access.getLength(iter));
+                                    while (access.next(iter)) {
+                                        writeItem(access.getListElement(iter));
+                                    }
                                 }
                                 break;
                             }
 
                             case RAWSXP: {
-                                RRawVector raw = (RRawVector) obj;
-                                byte[] data = raw.getReadonlyData();
-                                stream.writeInt(data.length);
-                                stream.writeRaw(data);
+                                RAbstractRawVector vector = (RAbstractRawVector) obj;
+                                VectorAccess access = vector.slowPathAccess();
+                                try (SequentialIterator iter = access.access(vector)) {
+                                    stream.writeInt(access.getLength(iter));
+                                    while (access.next(iter)) {
+                                        stream.writeRaw(access.getRaw(iter));
+                                    }
+                                }
                                 break;
                             }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java
index 58096f6025f86d97235ed5018532a3b3f1ada2e3..ccd1f53dc14cbaf1b67fa087ba369dc6db7ecd82 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java
@@ -96,6 +96,20 @@ public enum RType {
         }
     }
 
+    public boolean isAtomic() {
+        switch (this) {
+            case Logical:
+            case Double:
+            case Integer:
+            case Complex:
+            case Character:
+            case Raw:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     public boolean isVector() {
         switch (this) {
             case Logical:
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/NativeConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/NativeConnections.java
index 4f3a36f520cf162046f5b318e7107ccd075b4187..7d18153e4a3334d1cabe43c5d4001d8b2fbb265a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/NativeConnections.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/NativeConnections.java
@@ -302,7 +302,7 @@ public class NativeConnections {
         // converted to a pointer using RAW macro. This turns the raw vector into a native memory
         // backed vector and any consecutive (write) operations in the native code are actually not
         // done on the original vector that backs the byte buffer, so we need to copy back the date
-        // to the byte buffer. It would be more efficitent to use direct byte buffer, but then we'd
+        // to the byte buffer. It would be more efficient to use direct byte buffer, but then we'd
         // need to make the native call interface (CallRFFI.InvokeCallRootNode) more flexible so
         // that it can accept other argument types than SEXPs.
 
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 efe8ee17d0ceaf1a7ce53e88b98587c6a012117b..ab9c0f0439bf4a9b41e4a692b41e6a4f572949cd 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
@@ -314,21 +314,35 @@ public final class NativeDataAccess {
                         UnsafeAdapter.UNSAFE.getDouble(address + (index * 2 + 1) * Unsafe.ARRAY_DOUBLE_INDEX_SCALE));
     }
 
-    public static void setNativeMirrorData(Object nativeMirror, int index, double value) {
+    public static double getComplexNativeMirrorDataR(Object nativeMirror, int index) {
+        long address = ((NativeMirror) nativeMirror).dataAddress;
+        assert address != 0;
+        assert index < ((NativeMirror) nativeMirror).length;
+        return UnsafeAdapter.UNSAFE.getDouble(address + index * 2 * Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
+    }
+
+    public static double getComplexNativeMirrorDataI(Object nativeMirror, int index) {
+        long address = ((NativeMirror) nativeMirror).dataAddress;
+        assert address != 0;
+        assert index < ((NativeMirror) nativeMirror).length;
+        return UnsafeAdapter.UNSAFE.getDouble(address + (index * 2 + 1) * Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
+    }
+
+    public static void setNativeMirrorDoubleData(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 void setNativeMirrorData(Object nativeMirror, int index, byte value) {
+    public static void setNativeMirrorRawData(Object nativeMirror, int index, byte value) {
         long address = ((NativeMirror) nativeMirror).dataAddress;
         assert address != 0;
         assert index < ((NativeMirror) nativeMirror).length;
         UnsafeAdapter.UNSAFE.putByte(address + index * Unsafe.ARRAY_BYTE_INDEX_SCALE, value);
     }
 
-    public static void setNativeMirrorData(Object nativeMirror, int index, int value) {
+    public static void setNativeMirrorIntData(Object nativeMirror, int index, int value) {
         long address = ((NativeMirror) nativeMirror).dataAddress;
         assert address != 0;
         assert index < ((NativeMirror) nativeMirror).length;
@@ -390,10 +404,14 @@ public final class NativeDataAccess {
         if (noIntNative.isValid() || data != null) {
             return data.length;
         } else {
-            return (int) ((NativeMirror) vector.getNativeMirror()).length;
+            return getDataLengthFromMirror(vector.getNativeMirror());
         }
     }
 
+    static int getDataLengthFromMirror(Object mirror) {
+        return (int) ((NativeMirror) mirror).length;
+    }
+
     static void setData(RIntVector vector, int[] data, int index, int value) {
         if (noIntNative.isValid() || data != null) {
             data[index] = value;
@@ -478,7 +496,7 @@ public final class NativeDataAccess {
         if (noDoubleNative.isValid() || data != null) {
             data[index] = value;
         } else {
-            setNativeMirrorData(vector.getNativeMirror(), index, value);
+            setNativeMirrorDoubleData(vector.getNativeMirror(), index, value);
         }
     }
 
@@ -490,6 +508,22 @@ public final class NativeDataAccess {
         }
     }
 
+    static double getDataR(RComplexVector vector, double[] data, int index) {
+        if (noComplexNative.isValid() || data != null) {
+            return data[index * 2];
+        } else {
+            return getComplexNativeMirrorDataR(vector.getNativeMirror(), index);
+        }
+    }
+
+    static double getDataI(RComplexVector vector, double[] data, int index) {
+        if (noComplexNative.isValid() || data != null) {
+            return data[index * 2 + 1];
+        } else {
+            return getComplexNativeMirrorDataI(vector.getNativeMirror(), index);
+        }
+    }
+
     static int getDataLength(RComplexVector vector, double[] data) {
         if (noComplexNative.isValid() || data != null) {
             return data.length >> 1;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java
index a44c45ec7e53a2b1c5573d9b8e95511b6b98a377..ef5fb88f7cb06c6a13dc38ee7dccb3fecb069b6f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java
@@ -23,10 +23,8 @@
 package com.oracle.truffle.r.runtime.data;
 
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.CompilerDirectives.ValueType;
@@ -59,72 +57,16 @@ public final class RAttributesLayout {
     private static final AttrsLayout NAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY);
     private static final AttrsLayout DIM_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIM_ATTR_KEY);
     private static final AttrsLayout DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIMNAMES_ATTR_KEY);
+    private static final AttrsLayout NAMES_AND_DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY, RRuntime.DIMNAMES_ATTR_KEY);
     private static final AttrsLayout ROWNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.ROWNAMES_ATTR_KEY);
     private static final AttrsLayout NAMES_AND_DIM_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY, RRuntime.DIM_ATTR_KEY);
     private static final AttrsLayout DIM_AND_DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIM_ATTR_KEY, RRuntime.DIMNAMES_ATTR_KEY);
+    private static final AttrsLayout NAMES_AND_DIM_AND_DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY, RRuntime.DIM_ATTR_KEY, RRuntime.DIMNAMES_ATTR_KEY);
     private static final AttrsLayout CLASS_AND_CONNID_ATTRS_LAYOUT = new AttrsLayout(RRuntime.CLASS_ATTR_KEY, RRuntime.CONN_ID_ATTR_KEY);
 
     public static final AttrsLayout[] LAYOUTS = {EMPTY_ATTRS_LAYOUT, CLASS_ATTRS_LAYOUT, NAMES_ATTRS_LAYOUT, DIM_ATTRS_LAYOUT, DIMNAMES_ATTRS_LAYOUT, ROWNAMES_ATTRS_LAYOUT,
                     NAMES_AND_DIM_ATTRS_LAYOUT, DIM_AND_DIMNAMES_ATTRS_LAYOUT};
 
-    private static final Map<String, ConstantShapesAndProperties> constantShapesAndLocationsForAttribute = new HashMap<>();
-
-    static {
-        constantShapesAndLocationsForAttribute.put(RRuntime.CLASS_ATTR_KEY, new ConstantShapesAndProperties(
-                        new Shape[]{
-                                        CLASS_ATTRS_LAYOUT.shape,
-                                        CLASS_AND_CONNID_ATTRS_LAYOUT.shape
-                        },
-                        new Property[]{
-                                        CLASS_ATTRS_LAYOUT.properties[0],
-                                        CLASS_AND_CONNID_ATTRS_LAYOUT.properties[0]
-                        }));
-        constantShapesAndLocationsForAttribute.put(RRuntime.NAMES_ATTR_KEY, new ConstantShapesAndProperties(
-                        new Shape[]{
-                                        NAMES_ATTRS_LAYOUT.shape,
-                                        NAMES_AND_DIM_ATTRS_LAYOUT.shape
-                        },
-                        new Property[]{
-                                        NAMES_ATTRS_LAYOUT.properties[0],
-                                        NAMES_AND_DIM_ATTRS_LAYOUT.properties[0]
-                        }));
-        constantShapesAndLocationsForAttribute.put(RRuntime.DIM_ATTR_KEY, new ConstantShapesAndProperties(
-                        new Shape[]{
-                                        DIM_ATTRS_LAYOUT.shape,
-                                        NAMES_AND_DIM_ATTRS_LAYOUT.shape,
-                                        DIM_AND_DIMNAMES_ATTRS_LAYOUT.shape
-                        },
-                        new Property[]{
-                                        DIM_ATTRS_LAYOUT.properties[0],
-                                        NAMES_AND_DIM_ATTRS_LAYOUT.properties[1],
-                                        DIM_AND_DIMNAMES_ATTRS_LAYOUT.properties[0]
-                        }));
-        constantShapesAndLocationsForAttribute.put(RRuntime.DIMNAMES_ATTR_KEY, new ConstantShapesAndProperties(
-                        new Shape[]{
-                                        DIMNAMES_ATTRS_LAYOUT.shape,
-                                        DIM_AND_DIMNAMES_ATTRS_LAYOUT.shape
-                        },
-                        new Property[]{
-                                        DIMNAMES_ATTRS_LAYOUT.properties[0],
-                                        DIM_AND_DIMNAMES_ATTRS_LAYOUT.properties[1]
-                        }));
-        constantShapesAndLocationsForAttribute.put(RRuntime.CONN_ID_ATTR_KEY, new ConstantShapesAndProperties(
-                        new Shape[]{
-                                        CLASS_AND_CONNID_ATTRS_LAYOUT.shape
-                        },
-                        new Property[]{
-                                        CLASS_AND_CONNID_ATTRS_LAYOUT.properties[0]
-                        }));
-        constantShapesAndLocationsForAttribute.put(RRuntime.ROWNAMES_ATTR_KEY, new ConstantShapesAndProperties(
-                        new Shape[]{
-                                        ROWNAMES_ATTRS_LAYOUT.shape
-                        },
-                        new Property[]{
-                                        ROWNAMES_ATTRS_LAYOUT.properties[0]
-                        }));
-
-    }
-
     private RAttributesLayout() {
     }
 
@@ -155,6 +97,10 @@ public final class RAttributesLayout {
         return DIMNAMES_ATTRS_LAYOUT.factory.newInstance(dimNames);
     }
 
+    public static DynamicObject createNamesAndDimNames(Object names, Object dimNames) {
+        return NAMES_AND_DIMNAMES_ATTRS_LAYOUT.factory.newInstance(names, dimNames);
+    }
+
     public static DynamicObject createRowNames(Object rowNames) {
         return ROWNAMES_ATTRS_LAYOUT.factory.newInstance(rowNames);
     }
@@ -167,12 +113,12 @@ public final class RAttributesLayout {
         return DIM_AND_DIMNAMES_ATTRS_LAYOUT.factory.newInstance(dim, dimNames);
     }
 
-    public static DynamicObject createClassWithConnId(Object cls, Object connId) {
-        return CLASS_AND_CONNID_ATTRS_LAYOUT.factory.newInstance(cls, connId);
+    public static DynamicObject createNamesAndDimAndDimNames(Object names, Object dim, Object dimNames) {
+        return NAMES_AND_DIM_AND_DIMNAMES_ATTRS_LAYOUT.factory.newInstance(names, dim, dimNames);
     }
 
-    public static ConstantShapesAndProperties getConstantShapesAndProperties(String attrName) {
-        return constantShapesAndLocationsForAttribute.getOrDefault(attrName, ConstantShapesAndProperties.EMPTY);
+    public static DynamicObject createClassWithConnId(Object cls, Object connId) {
+        return CLASS_AND_CONNID_ATTRS_LAYOUT.factory.newInstance(cls, connId);
     }
 
     public static boolean isRAttributes(Object attrs) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java
index af6a3028bc427305beaf140ce954cc6adc365b8d..367c91a77145feb4278e3fb36013a0832efa40aa 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java
@@ -30,7 +30,11 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromComplexAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromComplexAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 @ValueType
 public final class RComplex extends RScalarVector implements RAbstractComplexVector {
@@ -143,4 +147,59 @@ public final class RComplex extends RScalarVector implements RAbstractComplexVec
             return Math.sqrt(re * re + im * im);
         }
     }
+
+    private static final class FastPathAccess extends FastPathFromComplexAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected RComplex getComplex(Object store, int index) {
+            assert index == 0;
+            return (RComplex) store;
+        }
+
+        @Override
+        protected double getComplexR(Object store, int index) {
+            assert index == 0;
+            return ((RComplex) store).realPart;
+        }
+
+        @Override
+        protected double getComplexI(Object store, int index) {
+            assert index == 0;
+            return ((RComplex) store).imaginaryPart;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromComplexAccess SLOW_PATH_ACCESS = new SlowPathFromComplexAccess() {
+        @Override
+        protected RComplex getComplex(Object store, int index) {
+            assert index == 0;
+            return (RComplex) store;
+        }
+
+        @Override
+        protected double getComplexR(Object store, int index) {
+            assert index == 0;
+            return ((RComplex) store).realPart;
+        }
+
+        @Override
+        protected double getComplexI(Object store, int index) {
+            assert index == 0;
+            return ((RComplex) store).imaginaryPart;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
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 a3cedbc0057006849cc31cfcfe2c7b37561b7d37..b42c2d6f77235b2467e3710f84f488c19e996cd0 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
@@ -30,7 +30,11 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.closures.RClosures;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromComplexAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromComplexAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public final class RComplexVector extends RVector<double[]> implements RAbstractComplexVector {
@@ -41,7 +45,7 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract
         super(complete);
         assert data.length % 2 == 0;
         this.data = data;
-        assert verify();
+        assert RAbstractVector.verify(this);
     }
 
     RComplexVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) {
@@ -104,10 +108,8 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract
         NativeDataAccess.setData(this, (double[]) store, index, value.getRealPart(), value.getImaginaryPart());
     }
 
-    @Override
-    public RComplex getDataAt(Object store, int index) {
-        assert data == store;
-        return NativeDataAccess.getData(this, (double[]) store, index);
+    public void setDataAt(int index, RComplex value) {
+        NativeDataAccess.setData(this, data, index, value.getRealPart(), value.getImaginaryPart());
     }
 
     @Override
@@ -115,23 +117,6 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract
         return NativeDataAccess.getData(this, data, index);
     }
 
-    @Override
-    public String toString() {
-        return toString(i -> getDataAt(i).toString());
-    }
-
-    @Override
-    public boolean verify() {
-        if (isComplete()) {
-            for (int i = 0; i < getLength(); i++) {
-                if (getDataAt(i).isNA()) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
     @Override
     public double[] getDataCopy() {
         if (data != null) {
@@ -219,4 +204,73 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract
             complete = false;
         }
     }
+
+    private static final class FastPathAccess extends FastPathFromComplexAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected RComplex getComplex(Object store, int index) {
+            return RComplex.valueOf(getComplexR(store, index), getComplexI(store, index));
+        }
+
+        @Override
+        protected double getComplexR(Object store, int index) {
+            return hasStore ? ((double[]) store)[index * 2] : NativeDataAccess.getDoubleNativeMirrorData(store, index * 2);
+        }
+
+        @Override
+        protected double getComplexI(Object store, int index) {
+            return hasStore ? ((double[]) store)[index * 2 + 1] : NativeDataAccess.getDoubleNativeMirrorData(store, index * 2 + 1);
+        }
+
+        @Override
+        protected void setComplex(Object store, int index, double real, double imaginary) {
+            if (hasStore) {
+                ((double[]) store)[index * 2] = real;
+                ((double[]) store)[index * 2 + 1] = imaginary;
+            } else {
+                NativeDataAccess.setNativeMirrorDoubleData(store, index * 2, real);
+                NativeDataAccess.setNativeMirrorDoubleData(store, index * 2 + 1, imaginary);
+            }
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromComplexAccess SLOW_PATH_ACCESS = new SlowPathFromComplexAccess() {
+        @Override
+        protected RComplex getComplex(Object store, int index) {
+            RComplexVector vector = (RComplexVector) store;
+            return NativeDataAccess.getData(vector, vector.data, index);
+        }
+
+        @Override
+        protected double getComplexR(Object store, int index) {
+            RComplexVector vector = (RComplexVector) store;
+            return NativeDataAccess.getDataR(vector, vector.data, index);
+        }
+
+        @Override
+        protected double getComplexI(Object store, int index) {
+            RComplexVector vector = (RComplexVector) store;
+            return NativeDataAccess.getDataI(vector, vector.data, index);
+        }
+
+        @Override
+        protected void setComplex(Object store, int index, double real, double imaginary) {
+            RComplexVector vector = (RComplexVector) store;
+            NativeDataAccess.setData(vector, vector.data, index, real, imaginary);
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
index be21c056a32b4f8646992314359d6a836e43bcc4..2587193a855ef1fc6a9fd79822a15f1459f97366 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
@@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import com.oracle.truffle.api.Assumption;
+import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.RootCallTarget;
@@ -35,10 +36,14 @@ import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.frame.FrameDescriptor;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.instrumentation.AllocationReporter;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.NodeCost;
+import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -49,6 +54,729 @@ import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 
 public final class RDataFactory {
+    private abstract static class StaticVectorFactory extends BaseVectorFactory {
+
+        @Override
+        public void reinitializeAttributes(RVector<?> vector, int[] dims, RStringVector names, RList dimNames) {
+            vector.initAttributes(dims != null || names != null || dimNames != null ? RVector.createAttributes(dims, names, dimNames) : null);
+        }
+
+        @Override
+        protected <T extends RVector<?>> T initializeAttributes(T result, int[] dims, RStringVector names, RList dimNames) {
+            if (dims != null || names != null || dimNames != null) {
+                result.initDimsNamesDimNames(dims, names, dimNames);
+            }
+            return result;
+        }
+
+        @Override
+        protected <T extends RVector<?>> T initializeAttributes(T result, int[] dims) {
+            if (dims != null) {
+                result.initDimsNamesDimNames(dims, null, null);
+            }
+            return result;
+        }
+
+        @Override
+        protected <T extends RVector<?>> T initializeAttributes(T result, RStringVector names) {
+            if (names != null) {
+                result.initDimsNamesDimNames(null, names, null);
+            }
+            return result;
+        }
+    }
+
+    private static final class DefaultStaticVectorFactory extends StaticVectorFactory {
+
+    }
+
+    private static final class PermanentStaticVectorFactory extends StaticVectorFactory {
+
+        @Override
+        protected <T> T traceDataCreated(T data) {
+            if (data instanceof RShareable) {
+                ((RShareable) data).makeSharedPermanent();
+            } else {
+                assert data instanceof Integer || data instanceof Double || data instanceof Byte || data instanceof String || data instanceof RRaw ||
+                                data instanceof RComplex : "cannot make permanent instance of non-shareable object";
+            }
+            return super.traceDataCreated(data);
+        }
+    }
+
+    private static final StaticVectorFactory INSTANCE = new DefaultStaticVectorFactory();
+    private static final StaticVectorFactory PERMANENT = new PermanentStaticVectorFactory();
+
+    /**
+     * This factory is only intended for use on slow paths, all places where a node context is
+     * available should use a dynamic {@link VectorFactory} instance.
+     */
+    public static BaseVectorFactory getInstance() {
+        CompilerAsserts.neverPartOfCompilation("RDataFactory.getInstance() can only be used in slow paths");
+        return INSTANCE;
+    }
+
+    /**
+     * This factory is intended for use in initializers that want to create "permanent" objects,
+     * i.e., objects that have their reference count set to "permanently shared".
+     */
+    public static BaseVectorFactory getPermanent() {
+        CompilerAsserts.neverPartOfCompilation("RDataFactory.getPermanent() can only be used in slow paths");
+        return PERMANENT;
+    }
+
+    public static final class VectorFactory extends BaseVectorFactory {
+
+        private VectorFactory() {
+            // private constructor
+        }
+
+        private final ConditionProfile hasAttributes = ConditionProfile.createBinaryProfile();
+
+        @Override
+        public void reinitializeAttributes(RVector<?> vector, int[] dims, RStringVector names, RList dimNames) {
+            vector.initAttributes(hasAttributes.profile(dims != null || names != null || dimNames != null) ? RVector.createAttributes(dims, names, dimNames) : null);
+        }
+
+        @Override
+        protected <T extends RVector<?>> T initializeAttributes(T result, int[] dims, RStringVector names, RList dimNames) {
+            if (hasAttributes.profile(dims != null || names != null || dimNames != null)) {
+                result.initDimsNamesDimNames(dims, names, dimNames);
+            }
+            return result;
+        }
+
+        @Override
+        protected <T extends RVector<?>> T initializeAttributes(T result, int[] dims) {
+            if (hasAttributes.profile(dims != null)) {
+                result.initDimsNamesDimNames(dims, null, null);
+            }
+            return result;
+        }
+
+        @Override
+        protected <T extends RVector<?>> T initializeAttributes(T result, RStringVector names) {
+            if (hasAttributes.profile(names != null)) {
+                result.initDimsNamesDimNames(null, names, null);
+            }
+            return result;
+        }
+
+        public static VectorFactory create() {
+            return new VectorFactory();
+        }
+    }
+
+    @SuppressWarnings("static-method")
+    public abstract static class BaseVectorFactory extends Node {
+
+        @Override
+        public final NodeCost getCost() {
+            return NodeCost.NONE;
+        }
+
+        public abstract void reinitializeAttributes(RVector<?> vector, int[] dims, RStringVector names, RList dimNames);
+
+        protected abstract <T extends RVector<?>> T initializeAttributes(T result, int[] dims, RStringVector names, RList dimNames);
+
+        protected abstract <T extends RVector<?>> T initializeAttributes(T result, int[] dims);
+
+        protected abstract <T extends RVector<?>> T initializeAttributes(T result, RStringVector names);
+
+        protected <T> T traceDataCreated(T data) {
+            if (stateAssumption.isEnabled()) {
+                reportDataCreated(data);
+            }
+            return data;
+        }
+
+        public final RIntVector createIntVector(int[] data, boolean complete) {
+            return traceDataCreated(new RIntVector(data, complete));
+        }
+
+        public final RIntVector createIntVector(int[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) {
+            return traceDataCreated(initializeAttributes(new RIntVector(data, complete), dims, names, dimNames));
+        }
+
+        public final RIntVector createIntVector(int[] data, boolean complete, int[] dims) {
+            return traceDataCreated(initializeAttributes(new RIntVector(data, complete), dims));
+        }
+
+        public final RIntVector createIntVector(int[] data, boolean complete, RStringVector names) {
+            return traceDataCreated(initializeAttributes(new RIntVector(data, complete), names));
+        }
+
+        public final RDoubleVector createDoubleVector(double[] data, boolean complete) {
+            return traceDataCreated(new RDoubleVector(data, complete));
+        }
+
+        public final RDoubleVector createDoubleVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) {
+            return traceDataCreated(initializeAttributes(new RDoubleVector(data, complete), dims, names, dimNames));
+        }
+
+        public final RDoubleVector createDoubleVector(double[] data, boolean complete, int[] dims) {
+            return traceDataCreated(initializeAttributes(new RDoubleVector(data, complete), dims));
+        }
+
+        public final RDoubleVector createDoubleVector(double[] data, boolean complete, RStringVector names) {
+            return traceDataCreated(initializeAttributes(new RDoubleVector(data, complete), names));
+        }
+
+        public final RLogicalVector createLogicalVector(byte[] data, boolean complete) {
+            return traceDataCreated(new RLogicalVector(data, complete));
+        }
+
+        public final RLogicalVector createLogicalVector(byte[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) {
+            return traceDataCreated(initializeAttributes(new RLogicalVector(data, complete), dims, names, dimNames));
+        }
+
+        public final RLogicalVector createLogicalVector(byte[] data, boolean complete, int[] dims) {
+            return traceDataCreated(initializeAttributes(new RLogicalVector(data, complete), dims));
+        }
+
+        public final RLogicalVector createLogicalVector(byte[] data, boolean complete, RStringVector names) {
+            return traceDataCreated(initializeAttributes(new RLogicalVector(data, complete), names));
+        }
+
+        public final RStringVector createStringVector(String[] data, boolean complete) {
+            return traceDataCreated(new RStringVector(data, complete));
+        }
+
+        public final RStringVector createStringVector(String[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) {
+            return traceDataCreated(initializeAttributes(new RStringVector(data, complete), dims, names, dimNames));
+        }
+
+        public final RStringVector createStringVector(String[] data, boolean complete, int[] dims) {
+            return traceDataCreated(initializeAttributes(new RStringVector(data, complete), dims));
+        }
+
+        public final RStringVector createStringVector(String[] data, boolean complete, RStringVector names) {
+            return traceDataCreated(initializeAttributes(new RStringVector(data, complete), names));
+        }
+
+        public final RComplexVector createComplexVector(double[] data, boolean complete) {
+            return traceDataCreated(new RComplexVector(data, complete));
+        }
+
+        public final RComplexVector createComplexVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) {
+            return traceDataCreated(initializeAttributes(new RComplexVector(data, complete), dims, names, dimNames));
+        }
+
+        public final RComplexVector createComplexVector(double[] data, boolean complete, int[] dims) {
+            return traceDataCreated(initializeAttributes(new RComplexVector(data, complete), dims));
+        }
+
+        public final RComplexVector createComplexVector(double[] data, boolean complete, RStringVector names) {
+            return traceDataCreated(initializeAttributes(new RComplexVector(data, complete), names));
+        }
+
+        public final RRawVector createRawVector(byte[] data) {
+            return traceDataCreated(new RRawVector(data));
+        }
+
+        public final RRawVector createRawVector(byte[] data, int[] dims, RStringVector names, RList dimNames) {
+            return traceDataCreated(initializeAttributes(new RRawVector(data), dims, names, dimNames));
+        }
+
+        public final RRawVector createRawVector(byte[] data, int[] dims) {
+            return traceDataCreated(initializeAttributes(new RRawVector(data), dims));
+        }
+
+        public final RRawVector createRawVector(byte[] data, RStringVector names) {
+            return traceDataCreated(initializeAttributes(new RRawVector(data), names));
+        }
+
+        public final RList createList(Object[] data) {
+            return traceDataCreated(new RList(data));
+        }
+
+        public final RList createList(Object[] data, int[] dims, RStringVector names, RList dimNames) {
+            return traceDataCreated(initializeAttributes(new RList(data), dims, names, dimNames));
+        }
+
+        public final RList createList(Object[] data, int[] dims) {
+            return traceDataCreated(initializeAttributes(new RList(data), dims));
+        }
+
+        public final RList createList(Object[] data, RStringVector names) {
+            return traceDataCreated(initializeAttributes(new RList(data), names));
+        }
+
+        public RExpression createExpression(int size) {
+            return createExpression(createRNullArray(size));
+        }
+
+        public RExpression createExpression(int size, RStringVector names) {
+            if (names == null) {
+                return createExpression(size);
+            }
+            assert size == names.getLength();
+            return createExpression(createRNullArray(size), names);
+        }
+
+        public RExpression createExpression(Object[] data, int[] newDimensions) {
+            return traceDataCreated(new RExpression(data, newDimensions, null, null));
+        }
+
+        public RExpression createExpression(Object[] data, RStringVector names) {
+            return traceDataCreated(new RExpression(data, null, names, null));
+        }
+
+        public RExpression createExpression(Object[] data, int[] newDimensions, RStringVector names, RList dimNames) {
+            return traceDataCreated(new RExpression(data, newDimensions, names, dimNames));
+        }
+
+        public RExpression createExpression(Object[] data) {
+            return traceDataCreated(new RExpression(data, null, null, null));
+        }
+
+        public final RVector<?> createEmptyVector(RType type) {
+            switch (type) {
+                case Double:
+                    return createEmptyDoubleVector();
+                case Integer:
+                    return createEmptyIntVector();
+                case Complex:
+                    return createEmptyComplexVector();
+                case Logical:
+                    return createEmptyLogicalVector();
+                case Character:
+                    return createEmptyStringVector();
+                case Raw:
+                    return createEmptyRawVector();
+                case List:
+                    return createList(new Object[0]);
+                default:
+                    throw RInternalError.shouldNotReachHere();
+            }
+        }
+
+        public final RVector<?> createUninitializedVector(RType type, int length, int[] dims, RStringVector names, RList dimNames) {
+            switch (type) {
+                case Logical:
+                    return createLogicalVector(new byte[length], false, dims, names, dimNames);
+                case Integer:
+                    return createIntVector(new int[length], false, dims, names, dimNames);
+                case Double:
+                    return createDoubleVector(new double[length], false, dims, names, dimNames);
+                case Complex:
+                    return createComplexVector(new double[length * 2], false, dims, names, dimNames);
+                case Character:
+                    return createStringVector(new String[length], false, dims, names, dimNames);
+                case Expression: {
+                    Object[] data = new Object[length];
+                    Arrays.fill(data, RNull.instance);
+                    return createExpression(data, dims, names, dimNames);
+                }
+                case List: {
+                    Object[] data = new Object[length];
+                    Arrays.fill(data, RNull.instance);
+                    return createList(data, dims, names, dimNames);
+                }
+                case Raw:
+                    return createRawVector(new byte[length], dims, names, dimNames);
+                default:
+                    throw RInternalError.shouldNotReachHere();
+            }
+
+        }
+
+        public final RVector<?> createVector(RType type, int length, boolean fillNA) {
+            switch (type) {
+                case Logical: {
+                    byte[] data = new byte[length];
+                    if (fillNA) {
+                        Arrays.fill(data, RRuntime.LOGICAL_NA);
+                    }
+                    return createLogicalVector(data, !fillNA);
+                }
+                case Integer: {
+                    int[] data = new int[length];
+                    if (fillNA) {
+                        Arrays.fill(data, RRuntime.INT_NA);
+                    }
+                    return createIntVector(data, !fillNA);
+                }
+                case Double: {
+                    double[] data = new double[length];
+                    if (fillNA) {
+                        Arrays.fill(data, RRuntime.LOGICAL_NA);
+                    }
+                    return createDoubleVector(data, !fillNA);
+                }
+                case Complex: {
+                    double[] data = new double[length * 2];
+                    if (fillNA) {
+                        Arrays.fill(data, RRuntime.LOGICAL_NA);
+                        for (int i = 0; i < data.length; i += 2) {
+                            data[i] = RRuntime.COMPLEX_NA_REAL_PART;
+                            data[i + 1] = RRuntime.COMPLEX_NA_IMAGINARY_PART;
+                        }
+                    }
+                    return createComplexVector(data, !fillNA);
+                }
+                case Character: {
+                    String[] data = new String[length];
+                    Arrays.fill(data, fillNA ? RRuntime.STRING_NA : "");
+                    return createStringVector(data, !fillNA);
+                }
+                case Expression: {
+                    Object[] data = new Object[length];
+                    Arrays.fill(data, RNull.instance);
+                    return createExpression(data);
+                }
+                case List: {
+                    Object[] data = new Object[length];
+                    Arrays.fill(data, RNull.instance);
+                    return createList(data);
+                }
+                case Raw:
+                    return createRawVector(new byte[length]);
+                default:
+                    throw RInternalError.shouldNotReachHere();
+            }
+        }
+
+        /*
+         * the following functions are not cleaned up yet:
+         */
+
+        public final RIntVector createIntVectorFromNative(long address, int length) {
+            return traceDataCreated(RIntVector.fromNative(address, length));
+        }
+
+        public final RIntVector createIntVector(int length) {
+            return createIntVector(new int[length], true);
+        }
+
+        public final RDoubleVector createDoubleVectorFromNative(long address, int length) {
+            return traceDataCreated(RDoubleVector.fromNative(address, length));
+        }
+
+        public final RDoubleVector createDoubleVector(int length) {
+            return createDoubleVector(new double[length], true);
+        }
+
+        public final RRawVector createRawVector(int length) {
+            return createRawVector(new byte[length]);
+        }
+
+        public final RComplexVector createComplexVectorFromNative(long address, int length) {
+            return traceDataCreated(RComplexVector.fromNative(address, length));
+        }
+
+        public final RComplexVector createComplexVector(int length) {
+            return createComplexVector(new double[length << 1], true);
+        }
+
+        public final RStringVector createStringVector(String value) {
+            return createStringVector(new String[]{value}, !RRuntime.isNA(value));
+        }
+
+        public final RStringVector createStringVector(int length) {
+            return createStringVector(createAndfillStringVector(length, ""), true);
+        }
+
+        private static String[] createAndfillStringVector(int length, String string) {
+            String[] strings = new String[length];
+            Arrays.fill(strings, string);
+            return strings;
+        }
+
+        public final RLogicalVector createLogicalVectorFromNative(long address, int length) {
+            return traceDataCreated(RLogicalVector.fromNative(address, length));
+        }
+
+        public final RLogicalVector createLogicalVector(int length) {
+            return createLogicalVector(length, false);
+        }
+
+        public final RLogicalVector createLogicalVector(int length, boolean fillNA) {
+            byte[] data = new byte[length];
+            if (fillNA) {
+                Arrays.fill(data, RRuntime.LOGICAL_NA);
+            }
+            return createLogicalVector(data, !fillNA);
+        }
+
+        public final RIntSequence createAscendingRange(int start, int end) {
+            assert start <= end;
+            return traceDataCreated(new RIntSequence(start, 1, end - start + 1));
+        }
+
+        public final RIntSequence createDescendingRange(int start, int end) {
+            assert start > end;
+            return traceDataCreated(new RIntSequence(start, -1, start - end + 1));
+        }
+
+        public final RIntSequence createIntSequence(int start, int stride, int length) {
+            return traceDataCreated(new RIntSequence(start, stride, length));
+        }
+
+        public final RDoubleSequence createAscendingRange(double start, double end) {
+            assert start <= end;
+            return traceDataCreated(new RDoubleSequence(start, 1, (int) ((end - start) + 1)));
+        }
+
+        public final RDoubleSequence createDescendingRange(double start, double end) {
+            assert start > end;
+            return traceDataCreated(new RDoubleSequence(start, -1, (int) ((start - end) + 1)));
+        }
+
+        public final RDoubleSequence createDoubleSequence(double start, double stride, int length) {
+            return traceDataCreated(new RDoubleSequence(start, stride, length));
+        }
+
+        public final RIntVector createEmptyIntVector() {
+            return createIntVector(new int[0], true);
+        }
+
+        public final RDoubleVector createEmptyDoubleVector() {
+            return createDoubleVector(new double[0], true);
+        }
+
+        public final RStringVector createEmptyStringVector() {
+            return createStringVector(new String[0], true);
+        }
+
+        public final RStringVector createNAStringVector() {
+            return createStringVector(new String[]{RRuntime.STRING_NA}, false);
+        }
+
+        public final RStringSequence createStringSequence(String prefix, String suffix, int start, int stride, int length) {
+            return traceDataCreated(new RStringSequence(prefix, suffix, start, stride, length));
+        }
+
+        public final RComplexVector createEmptyComplexVector() {
+            return createComplexVector(new double[0], true);
+        }
+
+        public final RLogicalVector createEmptyLogicalVector() {
+            return createLogicalVector(new byte[0], true);
+        }
+
+        public final RRawVector createEmptyRawVector() {
+            return createRawVector(new byte[0]);
+        }
+
+        public final RList createEmptyList() {
+            return createList(new Object[0]);
+        }
+
+        public final RComplex createComplex(double realPart, double imaginaryPart) {
+            return traceDataCreated(RComplex.valueOf(realPart, imaginaryPart));
+        }
+
+        public final RRawVector createRawVectorFromNative(long address, int length) {
+            return traceDataCreated(RRawVector.fromNative(address, length));
+        }
+
+        public final RRaw createRaw(byte value) {
+            return traceDataCreated(new RRaw(value));
+        }
+
+        /*
+         * Shared scalar conversion functions: these need to be replaced with
+         * createXyzVectorFromScalar(...).makeSharedPermanent() if scalar types are removed.
+         */
+
+        public final Object createSharedStringVectorFromScalar(String value) {
+            return value;
+        }
+
+        public final Object createSharedLogicalVectorFromScalar(boolean value) {
+            return RRuntime.asLogical(value);
+        }
+
+        public final Object createSharedLogicalVectorFromScalar(byte value) {
+            return value;
+        }
+
+        public final Object createSharedIntVectorFromScalar(int value) {
+            return value;
+        }
+
+        public final Object createSharedDoubleVectorFromScalar(double value) {
+            return value;
+        }
+
+        public final Object createSharedComplexVectorFromScalar(RComplex value) {
+            return value;
+        }
+
+        public final Object createSharedRawVectorFromScalar(RRaw value) {
+            return value;
+        }
+
+        public final RList createList(int n) {
+            return createList(createRNullArray(n));
+        }
+
+        public final RList createList(Object[] data, int[] newDimensions, RStringVector names) {
+            return traceDataCreated(new RList(data, newDimensions, names, null));
+        }
+
+        public final RSymbol createSymbol(String name) {
+            assert Utils.isInterned(name);
+            return traceDataCreated(new RSymbol(name));
+        }
+
+        /*
+         * A version of {@link createSymbol} method mostly used from native code and in
+         * serialization/deparsing.
+         */
+        public final RSymbol createSymbolInterned(String name) {
+            return createSymbol(Utils.intern(name));
+        }
+
+        public final RLanguage createLanguage(Closure closure) {
+            return traceDataCreated(new RLanguage(closure));
+        }
+
+        public final RPromise createPromise(PromiseState state, Closure closure, MaterializedFrame env) {
+            assert closure != null;
+            assert closure.getExpr() != null;
+            return traceDataCreated(new RPromise(state, env, closure));
+        }
+
+        public final RPromise createEvaluatedPromise(PromiseState state, Closure closure, Object argumentValue) {
+            return traceDataCreated(new RPromise(state, closure, argumentValue));
+        }
+
+        public final RPromise createEvaluatedPromise(Closure closure, Object value) {
+            return traceDataCreated(new RPromise(PromiseState.Explicit, closure, value));
+        }
+
+        public RPromise createEagerPromise(PromiseState state, Closure exprClosure, Object eagerValue, Assumption notChangedNonLocally, RCaller targetFrame, EagerFeedback feedback,
+                        int wrapIndex, MaterializedFrame execFrame) {
+            if (FastROptions.noEagerEval()) {
+                throw RInternalError.shouldNotReachHere();
+            }
+            return traceDataCreated(new RPromise.EagerPromise(state, exprClosure, eagerValue, notChangedNonLocally, targetFrame, feedback, wrapIndex, execFrame));
+        }
+
+        public RPromise createPromisedPromise(Closure exprClosure, Object eagerValue, Assumption notChangedNonLocally, RCaller targetFrame, EagerFeedback feedback, MaterializedFrame execFrame) {
+            if (FastROptions.noEagerEval()) {
+                throw RInternalError.shouldNotReachHere();
+            }
+            return traceDataCreated(new RPromise.EagerPromise(PromiseState.Promised, exprClosure, eagerValue, notChangedNonLocally, targetFrame, feedback, -1, execFrame));
+        }
+
+        public final Object createLangPairList(int size) {
+            if (size == 0) {
+                return RNull.instance;
+            } else {
+                return traceDataCreated(RPairList.create(size, SEXPTYPE.LANGSXP));
+            }
+        }
+
+        public final Object createPairList(int size) {
+            if (size == 0) {
+                return RNull.instance;
+            } else {
+                return traceDataCreated(RPairList.create(size));
+            }
+        }
+
+        public final RPairList createPairList() {
+            return traceDataCreated(new RPairList());
+        }
+
+        public final RPairList createPairList(Object car) {
+
+            return traceDataCreated(new RPairList(car, RNull.instance, RNull.instance, null));
+        }
+
+        public final RPairList createPairList(Object car, Object cdr) {
+            return traceDataCreated(new RPairList(car, cdr, RNull.instance, null));
+        }
+
+        public final RPairList createPairList(Object car, Object cdr, Object tag) {
+            return traceDataCreated(new RPairList(car, cdr, tag, null));
+        }
+
+        public final RPairList createPairList(Object car, Object cdr, Object tag, SEXPTYPE type) {
+            return traceDataCreated(new RPairList(car, cdr, tag, type));
+        }
+
+        public final RFunction createFunction(String name, String packageName, RootCallTarget target, RBuiltinDescriptor builtin, MaterializedFrame enclosingFrame) {
+            return traceDataCreated(new RFunction(name, packageName, target, builtin, enclosingFrame));
+        }
+
+        private static final AtomicInteger environmentCount = new AtomicInteger();
+
+        @TruffleBoundary
+        public final REnvironment createInternalEnv() {
+            return traceDataCreated(new REnvironment.NewEnv(RRuntime.createNonFunctionFrame("<internal-env-" + environmentCount.incrementAndGet() + ">"), REnvironment.UNNAMED));
+        }
+
+        @TruffleBoundary
+        public final REnvironment.NewEnv createNewEnv(FrameDescriptor desc, String name) {
+            return traceDataCreated(new REnvironment.NewEnv(RRuntime.createNewFrame(desc), name));
+        }
+
+        @TruffleBoundary
+        public final REnvironment.NewEnv createNewEnv(String name) {
+            return traceDataCreated(new REnvironment.NewEnv(RRuntime.createNonFunctionFrame("<new-env-" + environmentCount.incrementAndGet() + ">"), name));
+        }
+
+        @TruffleBoundary
+        public final REnvironment createNewEnv(String name, boolean hashed, int initialSize) {
+            REnvironment.NewEnv env = new REnvironment.NewEnv(RRuntime.createNonFunctionFrame("<new-env-" + environmentCount.incrementAndGet() + ">"), name);
+            env.setHashed(hashed);
+            env.setInitialSize(initialSize);
+            return traceDataCreated(env);
+        }
+
+        public final RS4Object createS4Object() {
+            return traceDataCreated(new RS4Object());
+        }
+
+        public final RExternalPtr createExternalPtr(SymbolHandle value, Object externalObject, Object tag, Object prot) {
+            assert tag != null : "null tag, use RNull.instance instead";
+            assert prot != null : "null prot, use RNull.instance instead";
+            return traceDataCreated(new RExternalPtr(value, externalObject, tag, prot));
+        }
+
+        public final RExternalPtr createExternalPtr(SymbolHandle value, Object tag, Object prot) {
+            assert tag != null : "null tag, use RNull.instance instead";
+            assert prot != null : "null prot, use RNull.instance instead";
+            return traceDataCreated(new RExternalPtr(value, null, tag, prot));
+        }
+
+        public final RExternalPtr createExternalPtr(SymbolHandle value, Object tag) {
+            assert tag != null : "null tag, use RNull.instance instead";
+            return traceDataCreated(new RExternalPtr(value, null, tag, RNull.instance));
+        }
+
+        public RStringVector createStringVectorFromScalar(String value) {
+            return traceDataCreated(RDataFactory.createStringVectorFromScalar(value));
+        }
+
+        public RLogicalVector createLogicalVectorFromScalar(boolean value) {
+            return traceDataCreated(RDataFactory.createLogicalVectorFromScalar(value));
+        }
+
+        public RLogicalVector createLogicalVectorFromScalar(byte value) {
+            return traceDataCreated(RDataFactory.createLogicalVectorFromScalar(value));
+        }
+
+        public RIntVector createIntVectorFromScalar(int value) {
+            return traceDataCreated(RDataFactory.createIntVectorFromScalar(value));
+        }
+
+        public RDoubleVector createDoubleVectorFromScalar(double value) {
+            return traceDataCreated(RDataFactory.createDoubleVectorFromScalar(value));
+        }
+
+        public RComplexVector createComplexVectorFromScalar(RComplex value) {
+            return traceDataCreated(RDataFactory.createComplexVectorFromScalar(value));
+        }
+
+        public RRawVector createRawVectorFromScalar(RRaw value) {
+            return traceDataCreated(RDataFactory.createRawVectorFromScalar(value));
+        }
+    }
 
     public static final boolean INCOMPLETE_VECTOR = false;
     public static final boolean COMPLETE_VECTOR = true;
@@ -456,15 +1184,15 @@ public final class RDataFactory {
     }
 
     public static RExpression createExpression(Object[] data, int[] newDimensions) {
-        return traceDataCreated(new RExpression(data, newDimensions, null));
+        return traceDataCreated(new RExpression(data, newDimensions, null, null));
     }
 
     public static RExpression createExpression(Object[] data, RStringVector names) {
-        return traceDataCreated(new RExpression(data, null, names));
+        return traceDataCreated(new RExpression(data, null, names, null));
     }
 
     public static RExpression createExpression(Object[] data) {
-        return traceDataCreated(new RExpression(data, null, null));
+        return traceDataCreated(new RExpression(data, null, null, null));
     }
 
     public static RSymbol createSymbol(String name) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java
index 6a66889e9cdeacff4129c7ab932ead664ee736bb..c0eff99975609d55764d3c577845f1e058bd7c30 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java
@@ -28,8 +28,12 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.context.RContext;
+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.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromDoubleAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromDoubleAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 @ValueType
 public final class RDouble extends RScalarVector implements RAbstractDoubleVector {
@@ -99,4 +103,35 @@ public final class RDouble extends RScalarVector implements RAbstractDoubleVecto
     public boolean isNA() {
         return RRuntime.isNA(getValue());
     }
+
+    private static final class FastPathAccess extends FastPathFromDoubleAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected double getDouble(Object store, int index) {
+            assert index == 0;
+            return ((RDouble) store).value;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromDoubleAccess SLOW_PATH_ACCESS = new SlowPathFromDoubleAccess() {
+        @Override
+        protected double getDouble(Object store, int index) {
+            assert index == 0;
+            return ((RDouble) store).value;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java
index a94cce37d00277922034d1d28749b204d1ebf17c..5d0ca6da84706471cdb8dfab9c8f4fb31f8dc2c8 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java
@@ -26,8 +26,12 @@ import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.closures.RClosures;
+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.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromDoubleAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromDoubleAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 public final class RDoubleSequence extends RSequence implements RAbstractDoubleVector {
 
@@ -134,4 +138,37 @@ public final class RDoubleSequence extends RSequence implements RAbstractDoubleV
         CompilerAsserts.neverPartOfCompilation();
         return "[" + start + " - " + getEnd() + "]";
     }
+
+    private static final class FastPathAccess extends FastPathFromDoubleAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected double getDouble(Object store, int index) {
+            RDoubleSequence vector = (RDoubleSequence) store;
+            assert index >= 0 && index < vector.getLength();
+            return vector.start + vector.stride * index;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromDoubleAccess SLOW_PATH_ACCESS = new SlowPathFromDoubleAccess() {
+        @Override
+        protected double getDouble(Object store, int index) {
+            RDoubleSequence vector = (RDoubleSequence) store;
+            assert index >= 0 && index < vector.getLength();
+            return vector.start + vector.stride * index;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
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 cc84373f42bcae0a9f153044ac545d4700966526..e37787fd868e78c8d4c0f6523e10dbc293eb290d 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
@@ -29,8 +29,12 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.closures.RClosures;
+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.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromDoubleAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromDoubleAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public final class RDoubleVector extends RVector<double[]> implements RAbstractDoubleVector {
@@ -40,7 +44,7 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD
     RDoubleVector(double[] data, boolean complete) {
         super(complete);
         this.data = data;
-        assert verify();
+        assert RAbstractVector.verify(this);
     }
 
     RDoubleVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) {
@@ -99,6 +103,10 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD
         NativeDataAccess.setData(this, (double[]) store, index, value);
     }
 
+    public void setDataAt(int index, double value) {
+        NativeDataAccess.setData(this, data, index, value);
+    }
+
     @Override
     public double getDataAt(Object store, int index) {
         assert data == store;
@@ -123,23 +131,6 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD
         return NativeDataAccess.getDataLength(this, data);
     }
 
-    @Override
-    public String toString() {
-        return toString(i -> Double.toString(getDataAt(i)));
-    }
-
-    @Override
-    public boolean verify() {
-        if (isComplete()) {
-            for (int i = 0; i < getLength(); i++) {
-                if (RRuntime.isNA(getDataAt(i))) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
     @Override
     public double getDataAt(int index) {
         return NativeDataAccess.getData(this, data, index);
@@ -238,4 +229,49 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD
             complete = false;
         }
     }
+
+    private static final class FastPathAccess extends FastPathFromDoubleAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected double getDouble(Object store, int index) {
+            return hasStore ? ((double[]) store)[index] : NativeDataAccess.getDoubleNativeMirrorData(store, index);
+        }
+
+        @Override
+        protected void setDouble(Object store, int index, double value) {
+            if (hasStore) {
+                ((double[]) store)[index] = value;
+            } else {
+                NativeDataAccess.setNativeMirrorDoubleData(store, index, value);
+            }
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromDoubleAccess SLOW_PATH_ACCESS = new SlowPathFromDoubleAccess() {
+        @Override
+        protected double getDouble(Object store, int index) {
+            RDoubleVector vector = (RDoubleVector) store;
+            return NativeDataAccess.getData(vector, vector.data, index);
+        }
+
+        @Override
+        protected void setDouble(Object store, int index, double value) {
+            RDoubleVector vector = (RDoubleVector) store;
+            NativeDataAccess.setData(vector, vector.data, index, value);
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
index 2e0463d5598a60d179459766246a95f4569ab2c7..1c9e240c9a7f3e42462694c12f8991a7a89cbe9d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
@@ -26,12 +26,20 @@ import java.util.Arrays;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 public final class RExpression extends RListBase implements RAbstractVector {
 
-    RExpression(Object[] data, int[] dims, RStringVector names) {
-        super(data, dims, names, null);
+    RExpression(Object[] data) {
+        super(data);
+    }
+
+    RExpression(Object[] data, int[] dims, RStringVector names, RList dimNames) {
+        super(data, dims, names, dimNames);
     }
 
     @Override
@@ -47,7 +55,7 @@ public final class RExpression extends RListBase implements RAbstractVector {
     @Override
     @TruffleBoundary
     protected RExpression internalCopy() {
-        return new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null);
+        return new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null, null);
     }
 
     @Override
@@ -55,7 +63,7 @@ public final class RExpression extends RListBase implements RAbstractVector {
     protected RExpression internalDeepCopy() {
         // TOOD: only used for nested list updates, but still could be made faster (through a
         // separate AST node?)
-        RExpression listCopy = new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null);
+        RExpression listCopy = new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null, null);
         for (int i = 0; i < listCopy.getLength(); i++) {
             Object el = listCopy.getDataAt(i);
             if (el instanceof RVector) {
@@ -80,4 +88,53 @@ public final class RExpression extends RListBase implements RAbstractVector {
     protected RExpression internalCopyResized(int size, boolean fillNA, int[] dimensions) {
         return RDataFactory.createExpression(copyResizedData(size, fillNA), dimensions);
     }
+
+    private static final class FastPathAccess extends FastPathFromListAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        public RType getType() {
+            return RType.Expression;
+        }
+
+        @Override
+        protected Object getListElement(Object store, int index) {
+            return ((Object[]) store)[index];
+        }
+
+        @Override
+        protected void setListElement(Object store, int index, Object value) {
+            ((Object[]) store)[index] = value;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() {
+        @Override
+        public RType getType() {
+            return RType.Expression;
+        }
+
+        @Override
+        protected Object getListElement(Object store, int index) {
+            return ((RExpression) store).data[index];
+        }
+
+        @Override
+        protected void setListElement(Object store, int index, Object value) {
+            ((RExpression) store).data[index] = value;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java
index 57aa7933b90f2b5c600d539a1aef31aa713390cd..fa03686af947f9cc3137ef97fbcb97ac4f14b686 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java
@@ -28,7 +28,7 @@ import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 /**
  * The rarely seen {@code externalptr} type used in native code.
  */
-public class RExternalPtr extends RAttributeStorage implements RTypedValue {
+public final class RExternalPtr extends RAttributeStorage implements RTypedValue {
     /**
      * In GNU R, typically the address of some C structure, so a {@code void*}. Represented here as
      * our abstraction of a "native symbol" (even though there may not actually be a symbol
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java
index 3d0746749a6a04225b2d39b7fd2d57a6f48afb92..cbda3db37fcf51e570ed59b5d818f7f2a1f392d5 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java
@@ -36,10 +36,7 @@ public final class RFactor {
      * be replaced with FactorNodes.GetLevel in the future.
      */
     public static RVector<?> getLevels(RAbstractIntVector factor) {
-        return getLevelsImpl(factor.getAttr(RRuntime.LEVELS_ATTR_KEY));
-    }
-
-    private static RVector<?> getLevelsImpl(Object attr) {
+        Object attr = factor.getAttr(RRuntime.LEVELS_ATTR_KEY);
         // convert scalar to RVector<?>if necessary
         return attr instanceof RVector ? (RVector<?>) attr : (RVector<?>) RRuntime.asAbstractVector(attr);
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignBooleanWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignBooleanWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3c30b09276c0864281b5cbd856c0b8cb0c876ea
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignBooleanWrapper.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 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.data;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnknownIdentifierException;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromLogicalAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromLogicalAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+
+public final class RForeignBooleanWrapper extends RForeignWrapper implements RAbstractLogicalVector {
+
+    public RForeignBooleanWrapper(TruffleObject delegate) {
+        super(delegate);
+    }
+
+    @Override
+    public RLogicalVector materialize() {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    @TruffleBoundary
+    public Object getDataAtAsObject(int index) {
+        return getDataAt(index);
+    }
+
+    @Override
+    @TruffleBoundary
+    public byte getDataAt(int index) {
+        try {
+            return RRuntime.asLogical((boolean) ForeignAccess.sendRead(READ, delegate, index));
+        } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+            throw RInternalError.shouldNotReachHere(e);
+        }
+    }
+
+    private static final class FastPathAccess extends FastPathFromLogicalAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Child private Node getSize = Message.GET_SIZE.createNode();
+        @Child private Node read = Message.READ.createNode();
+
+        @Override
+        protected int getLength(RAbstractContainer vector) {
+            try {
+                return (int) ForeignAccess.sendGetSize(getSize, ((RForeignWrapper) vector).delegate);
+            } catch (UnsupportedMessageException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+
+        @Override
+        protected byte getLogical(Object internalStore, int index) {
+            try {
+                return RRuntime.asLogical((boolean) ForeignAccess.sendRead(read, (TruffleObject) internalStore, index));
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromLogicalAccess SLOW_PATH_ACCESS = new SlowPathFromLogicalAccess() {
+        @Override
+        @TruffleBoundary
+        protected int getLength(RAbstractContainer vector) {
+            try {
+                return (int) ForeignAccess.sendGetSize(GET_SIZE, ((RForeignBooleanWrapper) vector).delegate);
+            } catch (UnsupportedMessageException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+
+        @Override
+        protected byte getLogical(Object store, int index) {
+            RForeignBooleanWrapper vector = (RForeignBooleanWrapper) store;
+            try {
+                return RRuntime.asLogical((boolean) ForeignAccess.sendRead(READ, vector.delegate, index));
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignDoubleWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignDoubleWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..90dbbe7faf6395e88a163bef390b916e28a1bf28
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignDoubleWrapper.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 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.data;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnknownIdentifierException;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.runtime.RInternalError;
+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.nodes.FastPathVectorAccess.FastPathFromDoubleAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromDoubleAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+
+public final class RForeignDoubleWrapper extends RForeignWrapper implements RAbstractDoubleVector {
+
+    public RForeignDoubleWrapper(TruffleObject delegate) {
+        super(delegate);
+    }
+
+    @Override
+    public RDoubleVector materialize() {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    @TruffleBoundary
+    public Object getDataAtAsObject(int index) {
+        return getDataAt(index);
+    }
+
+    @Override
+    @TruffleBoundary
+    public double getDataAt(int index) {
+        try {
+            return ((Number) ForeignAccess.sendRead(READ, delegate, index)).doubleValue();
+        } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+            throw RInternalError.shouldNotReachHere(e);
+        }
+    }
+
+    private static final class FastPathAccess extends FastPathFromDoubleAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        private final ValueProfile resultProfile = ValueProfile.createClassProfile();
+        @Child private Node getSize = Message.GET_SIZE.createNode();
+        @Child private Node read = Message.READ.createNode();
+
+        @Override
+        protected int getLength(RAbstractContainer vector) {
+            try {
+                return (int) ForeignAccess.sendGetSize(getSize, ((RForeignWrapper) vector).delegate);
+            } catch (UnsupportedMessageException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+
+        @Override
+        protected double getDouble(Object internalStore, int index) {
+            try {
+                return ((Number) resultProfile.profile(ForeignAccess.sendRead(read, (TruffleObject) internalStore, index))).doubleValue();
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromDoubleAccess SLOW_PATH_ACCESS = new SlowPathFromDoubleAccess() {
+        @Override
+        @TruffleBoundary
+        protected int getLength(RAbstractContainer vector) {
+            try {
+                return (int) ForeignAccess.sendGetSize(GET_SIZE, ((RForeignDoubleWrapper) vector).delegate);
+            } catch (UnsupportedMessageException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+
+        @Override
+        protected double getDouble(Object store, int index) {
+            RForeignDoubleWrapper vector = (RForeignDoubleWrapper) store;
+            try {
+                return ((Number) ForeignAccess.sendRead(READ, vector.delegate, index)).doubleValue();
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignIntWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignIntWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..68c4ca07ead520b8c62cc97ba41b58f6a5b94e98
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignIntWrapper.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 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.data;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnknownIdentifierException;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.runtime.RInternalError;
+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.nodes.FastPathVectorAccess.FastPathFromIntAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromIntAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+
+public final class RForeignIntWrapper extends RForeignWrapper implements RAbstractIntVector {
+
+    public RForeignIntWrapper(TruffleObject delegate) {
+        super(delegate);
+    }
+
+    @Override
+    public RIntVector materialize() {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    @TruffleBoundary
+    public Object getDataAtAsObject(int index) {
+        return getDataAt(index);
+    }
+
+    @Override
+    @TruffleBoundary
+    public int getDataAt(int index) {
+        try {
+            return ((Number) ForeignAccess.sendRead(READ, delegate, index)).intValue();
+        } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+            throw RInternalError.shouldNotReachHere(e);
+        }
+    }
+
+    private static final class FastPathAccess extends FastPathFromIntAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        private final ValueProfile resultProfile = ValueProfile.createClassProfile();
+        @Child private Node getSize = Message.GET_SIZE.createNode();
+        @Child private Node read = Message.READ.createNode();
+
+        @Override
+        protected int getLength(RAbstractContainer vector) {
+            try {
+                return (int) ForeignAccess.sendGetSize(getSize, ((RForeignWrapper) vector).delegate);
+            } catch (UnsupportedMessageException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+
+        @Override
+        protected int getInt(Object internalStore, int index) {
+            try {
+                return ((Number) resultProfile.profile(ForeignAccess.sendRead(read, (TruffleObject) internalStore, index))).intValue();
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromIntAccess SLOW_PATH_ACCESS = new SlowPathFromIntAccess() {
+        @Override
+        @TruffleBoundary
+        protected int getLength(RAbstractContainer vector) {
+            try {
+                return (int) ForeignAccess.sendGetSize(GET_SIZE, ((RForeignIntWrapper) vector).delegate);
+            } catch (UnsupportedMessageException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+
+        @Override
+        protected int getInt(Object store, int index) {
+            RForeignIntWrapper vector = (RForeignIntWrapper) store;
+            try {
+                return ((Number) ForeignAccess.sendRead(READ, vector.delegate, index)).intValue();
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignListWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignListWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..20f59b813a625a99f5a3308fb9dd0a8feb549e2b
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignListWrapper.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 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.data;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnknownIdentifierException;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.interop.Foreign2R;
+
+public final class RForeignListWrapper extends RForeignWrapper implements RAbstractListVector {
+
+    public RForeignListWrapper(TruffleObject delegate) {
+        super(delegate);
+    }
+
+    @Override
+    public RList materialize() {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    @TruffleBoundary
+    public Object getDataAtAsObject(int index) {
+        return getDataAt(index);
+    }
+
+    @Override
+    @TruffleBoundary
+    public Object getDataAt(int index) {
+        try {
+            return FOREIGN_TO_R.execute(ForeignAccess.sendRead(READ, delegate, index));
+        } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+            throw RInternalError.shouldNotReachHere(e);
+        }
+    }
+
+    private static final class FastPathAccess extends FastPathFromListAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Child private Node getSize = Message.GET_SIZE.createNode();
+        @Child private Node read = Message.READ.createNode();
+        @Child private Foreign2R foreign2r = Foreign2R.create();
+
+        @Override
+        public RType getType() {
+            return RType.List;
+        }
+
+        @Override
+        protected int getLength(RAbstractContainer vector) {
+            try {
+                return (int) ForeignAccess.sendGetSize(getSize, ((RForeignWrapper) vector).delegate);
+            } catch (UnsupportedMessageException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+
+        @Override
+        protected Object getListElement(Object internalStore, int index) {
+            try {
+                return foreign2r.execute(ForeignAccess.sendRead(read, (TruffleObject) internalStore, index));
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final Foreign2R FOREIGN_TO_R = Foreign2R.create();
+
+    private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() {
+
+        @Override
+        public RType getType() {
+            return RType.List;
+        }
+
+        @Override
+        @TruffleBoundary
+        protected int getLength(RAbstractContainer vector) {
+            try {
+                return (int) ForeignAccess.sendGetSize(GET_SIZE, ((RForeignListWrapper) vector).delegate);
+            } catch (UnsupportedMessageException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+
+        @Override
+        protected Object getListElement(Object store, int index) {
+            RForeignListWrapper vector = (RForeignListWrapper) store;
+            try {
+                return FOREIGN_TO_R.execute(ForeignAccess.sendRead(READ, vector.delegate, index));
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignNamedListWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignNamedListWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c3be432639391b85ea7362c6c8bb0bc178392d2
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignNamedListWrapper.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 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.data;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnknownIdentifierException;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.interop.Foreign2R;
+
+public final class RForeignNamedListWrapper extends RForeignWrapper implements RAbstractListVector {
+
+    private final RStringVector names;
+
+    public RForeignNamedListWrapper(TruffleObject delegate, RStringVector names) {
+        super(delegate);
+        this.names = names;
+    }
+
+    @Override
+    public Object getInternalStore() {
+        return this;
+    }
+
+    @Override
+    public int getLength() {
+        return names.getLength();
+    }
+
+    @Override
+    public RStringVector getNames() {
+        return names;
+    }
+
+    @Override
+    public RList materialize() {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    @TruffleBoundary
+    public Object getDataAtAsObject(int index) {
+        return getDataAt(index);
+    }
+
+    @Override
+    @TruffleBoundary
+    public Object getDataAt(int index) {
+        try {
+            return FOREIGN_TO_R.execute(ForeignAccess.sendRead(READ, delegate, names.getDataAt(index)));
+        } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+            throw RInternalError.shouldNotReachHere(e);
+        }
+    }
+
+    private static final class FastPathAccess extends FastPathFromListAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Child private Node getSize = Message.GET_SIZE.createNode();
+        @Child private Node read = Message.READ.createNode();
+        @Child private Foreign2R foreign2r = Foreign2R.create();
+
+        @Override
+        public RType getType() {
+            return RType.List;
+        }
+
+        @Override
+        protected int getLength(RAbstractContainer vector) {
+            return ((RForeignNamedListWrapper) vector).getLength();
+        }
+
+        @Override
+        protected Object getListElement(Object internalStore, int index) {
+            try {
+                RForeignNamedListWrapper wrapper = (RForeignNamedListWrapper) internalStore;
+                return foreign2r.execute(ForeignAccess.sendRead(read, wrapper.delegate, wrapper.names.getDataAt(index)));
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final Foreign2R FOREIGN_TO_R = Foreign2R.create();
+
+    private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() {
+        @Override
+        public RType getType() {
+            return RType.List;
+        }
+
+        @Override
+        @TruffleBoundary
+        protected int getLength(RAbstractContainer vector) {
+            return ((RForeignNamedListWrapper) vector).names.getLength();
+        }
+
+        @Override
+        protected Object getListElement(Object store, int index) {
+            RForeignNamedListWrapper vector = (RForeignNamedListWrapper) store;
+            try {
+                return FOREIGN_TO_R.execute(ForeignAccess.sendRead(READ, vector.delegate, vector.names.getDataAt(index)));
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignStringWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignStringWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..148bb9cf13a968cb98a128ef7cf69d20a3d21c8f
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignStringWrapper.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 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.data;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnknownIdentifierException;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromStringAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromStringAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+
+public final class RForeignStringWrapper extends RForeignWrapper implements RAbstractStringVector {
+
+    public RForeignStringWrapper(TruffleObject delegate) {
+        super(delegate);
+    }
+
+    @Override
+    public RStringVector materialize() {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    @TruffleBoundary
+    public Object getDataAtAsObject(int index) {
+        return getDataAt(index);
+    }
+
+    @Override
+    @TruffleBoundary
+    public String getDataAt(int index) {
+        try {
+            return ForeignAccess.sendRead(READ, delegate, index).toString();
+        } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+            throw RInternalError.shouldNotReachHere(e);
+        }
+    }
+
+    private static final class FastPathAccess extends FastPathFromStringAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        private final ValueProfile resultProfile = ValueProfile.createClassProfile();
+        @Child private Node getSize = Message.GET_SIZE.createNode();
+        @Child private Node read = Message.READ.createNode();
+
+        @Override
+        protected int getLength(RAbstractContainer vector) {
+            try {
+                return (int) ForeignAccess.sendGetSize(getSize, ((RForeignWrapper) vector).delegate);
+            } catch (UnsupportedMessageException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+
+        @Override
+        protected String getString(Object internalStore, int index) {
+            try {
+                return resultProfile.profile(ForeignAccess.sendRead(read, (TruffleObject) internalStore, index)).toString();
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromStringAccess SLOW_PATH_ACCESS = new SlowPathFromStringAccess() {
+        @Override
+        @TruffleBoundary
+        protected int getLength(RAbstractContainer vector) {
+            try {
+                return (int) ForeignAccess.sendGetSize(GET_SIZE, ((RForeignStringWrapper) vector).delegate);
+            } catch (UnsupportedMessageException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+
+        @Override
+        @TruffleBoundary
+        protected String getString(Object store, int index) {
+            RForeignStringWrapper vector = (RForeignStringWrapper) store;
+            try {
+                return ForeignAccess.sendRead(READ, vector.delegate, index).toString();
+            } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..36fece25f3205667f6fae6080373c2bb3e06e2ce
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignWrapper.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 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.data;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.object.DynamicObject;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+
+public abstract class RForeignWrapper implements RAbstractVector {
+
+    protected static final Node GET_SIZE = Message.GET_SIZE.createNode();
+    protected static final Node READ = Message.READ.createNode();
+
+    protected final TruffleObject delegate;
+
+    protected RForeignWrapper(TruffleObject delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    @TruffleBoundary
+    public int getLength() {
+        try {
+            return (int) ForeignAccess.sendGetSize(GET_SIZE, delegate);
+        } catch (UnsupportedMessageException e) {
+            throw RInternalError.shouldNotReachHere(e);
+        }
+    }
+
+    @Override
+    public final RAbstractContainer resize(int size) {
+        return materialize().resize(size);
+    }
+
+    @Override
+    public final boolean isComplete() {
+        return true;
+    }
+
+    @Override
+    public final void setComplete(boolean complete) {
+        // sequences are always complete
+    }
+
+    @Override
+    public final boolean hasDimensions() {
+        return false;
+    }
+
+    @Override
+    public final int[] getDimensions() {
+        return null;
+    }
+
+    @Override
+    public final void setDimensions(int[] newDimensions) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public final RAbstractVector copy() {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public final RAbstractVector copyDropAttributes() {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public final RAbstractVector copyWithNewDimensions(int[] newDimensions) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public RStringVector getNames() {
+        return null;
+    }
+
+    @Override
+    public final void setNames(RStringVector newNames) {
+        // should only be used on materialized sequence
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public final RList getDimNames() {
+        return null;
+    }
+
+    @Override
+    public final void setDimNames(RList newDimNames) {
+        // should only be used on materialized sequence
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public final Object getRowNames() {
+        return RNull.instance;
+    }
+
+    @Override
+    public final void setRowNames(RAbstractVector rowNames) {
+        // should only be used on materialized sequence
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public final DynamicObject initAttributes() {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public final void initAttributes(DynamicObject newAttributes) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public final DynamicObject getAttributes() {
+        return null;
+    }
+
+    @Override
+    public final boolean isMatrix() {
+        return false;
+    }
+
+    @Override
+    public final boolean isArray() {
+        return false;
+    }
+
+    @Override
+    public final boolean isObject() {
+        return false;
+    }
+
+    @Override
+    public final RTypedValue getNonShared() {
+        return materialize().getNonShared();
+    }
+
+    @Override
+    public final int getTypedValueInfo() {
+        return 0;
+    }
+
+    @Override
+    public final void setTypedValueInfo(int value) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public final boolean isS4() {
+        return false;
+    }
+
+    @Override
+    public Object getInternalStore() {
+        return delegate;
+    }
+
+    @Override
+    public final RVector<?> copyResized(int size, boolean fillNA) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public final RVector<?> copyResizedWithDimensions(int[] newDimensions, boolean fillNA) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public final RVector<?> createEmptySameType(int newLength, boolean newIsComplete) {
+        throw RInternalError.shouldNotReachHere();
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java
index 6aa8daa0c098e2863619e687adda0594003a5387..7f7bd897580a991874dfb294c3693ce0e0abf08c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java
@@ -70,7 +70,7 @@ public final class RFunction extends RSharingAttributeStorage implements RTypedV
     public RType getRType() {
         // Note: GnuR distinguishes "builtins" and "specials" (BUILTINSXP vs SPECIALSXP). The later
         // has non-evaluated args. FastR and GnuR built-ins differ in whether they have evaluated
-        // args, so we cannot correcly choose RType.Special here.
+        // args, so we cannot correctly choose RType.Special here.
         return isBuiltin() ? RType.Builtin : RType.Closure;
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java
index c0e25112c797a7e35d47f0098c827da16367249d..5182f8cba14c7c50db1c932b1a62764ef4fb36cf 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java
@@ -26,8 +26,12 @@ import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.closures.RClosures;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromIntAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromIntAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 public final class RIntSequence extends RSequence implements RAbstractIntVector {
 
@@ -143,4 +147,37 @@ public final class RIntSequence extends RSequence implements RAbstractIntVector
     public RIntVector createEmptySameType(int newLength, boolean newIsComplete) {
         return RDataFactory.createIntVector(new int[newLength], newIsComplete);
     }
+
+    private static final class FastPathAccess extends FastPathFromIntAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected int getInt(Object store, int index) {
+            RIntSequence vector = (RIntSequence) store;
+            assert index >= 0 && index < vector.getLength();
+            return vector.start + vector.stride * index;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromIntAccess SLOW_PATH_ACCESS = new SlowPathFromIntAccess() {
+        @Override
+        protected int getInt(Object store, int index) {
+            RIntSequence vector = (RIntSequence) store;
+            assert index >= 0 && index < vector.getLength();
+            return vector.start + vector.stride * index;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
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 f52c7cb614b01d9554536c7e2ee6c1618ffc13f4..17a03fc109ffdb06804919ad7e20376ae49d0f08 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
@@ -29,8 +29,12 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.closures.RClosures;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromIntAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromIntAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public final class RIntVector extends RVector<int[]> implements RAbstractIntVector {
@@ -40,7 +44,7 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect
     RIntVector(int[] data, boolean complete) {
         super(complete);
         this.data = data;
-        assert verify();
+        assert RAbstractVector.verify(this);
     }
 
     RIntVector(int[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) {
@@ -99,6 +103,10 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect
         NativeDataAccess.setData(this, (int[]) store, index, value);
     }
 
+    public void setDataAt(int index, int value) {
+        NativeDataAccess.setData(this, data, index, value);
+    }
+
     @Override
     protected RIntVector internalCopy() {
         if (data != null) {
@@ -126,23 +134,6 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect
         return NativeDataAccess.getDataLength(this, data);
     }
 
-    @Override
-    public String toString() {
-        return toString(i -> Double.toString(getDataAt(i)));
-    }
-
-    @Override
-    public boolean verify() {
-        if (isComplete()) {
-            for (int i = 0; i < getLength(); i++) {
-                if (RRuntime.isNA(getDataAt(i))) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
     @Override
     public int[] getDataCopy() {
         if (data != null) {
@@ -246,4 +237,49 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect
             complete = false;
         }
     }
+
+    private static final class FastPathAccess extends FastPathFromIntAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected int getInt(Object store, int index) {
+            return hasStore ? ((int[]) store)[index] : NativeDataAccess.getIntNativeMirrorData(store, index);
+        }
+
+        @Override
+        protected void setInt(Object store, int index, int value) {
+            if (hasStore) {
+                ((int[]) store)[index] = value;
+            } else {
+                NativeDataAccess.setNativeMirrorIntData(store, index, value);
+            }
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromIntAccess SLOW_PATH_ACCESS = new SlowPathFromIntAccess() {
+        @Override
+        protected int getInt(Object store, int index) {
+            RIntVector vector = (RIntVector) store;
+            return NativeDataAccess.getData(vector, vector.data, index);
+        }
+
+        @Override
+        protected void setInt(Object store, int index, int value) {
+            RIntVector vector = (RIntVector) store;
+            NativeDataAccess.setData(vector, vector.data, index, value);
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java
index eb0ea1f399ffd83e2dd88f286e7ec133c0467735..0eed431c3a623f0eecd166befaf467d24f241caa 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java
@@ -26,8 +26,12 @@ import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromIntAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromIntAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 @ValueType
 public final class RInteger extends RScalarVector implements RAbstractIntVector {
@@ -95,4 +99,35 @@ public final class RInteger extends RScalarVector implements RAbstractIntVector
     public boolean isNA() {
         return RRuntime.isNA(value);
     }
+
+    private static final class FastPathAccess extends FastPathFromIntAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected int getInt(Object store, int index) {
+            assert index == 0;
+            return ((RInteger) store).value;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromIntAccess SLOW_PATH_ACCESS = new SlowPathFromIntAccess() {
+        @Override
+        protected int getInt(Object store, int index) {
+            assert index == 0;
+            return ((RInteger) store).value;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
index 7fa8714d7a91980ce6aa176867b37e4e7bbedcef..43c77e0ca59aaf0dfc848b1af457ee091a24d531 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
@@ -30,6 +30,9 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
@@ -76,6 +79,11 @@ public final class RLanguage extends RSharingAttributeStorage implements RAbstra
         this.length = length;
     }
 
+    @Override
+    public Object getInternalStore() {
+        return this;
+    }
+
     @TruffleBoundary
     public static Object fromList(Object o, RLanguage.RepType type) {
         RList l;
@@ -276,4 +284,45 @@ public final class RLanguage extends RSharingAttributeStorage implements RAbstra
     private void setNamesOnPairList(RStringVector names) {
         list.setNames(names);
     }
+
+    private static final class FastPathAccess extends FastPathFromListAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        public RType getType() {
+            return RType.Language;
+        }
+
+        @TruffleBoundary
+        @Override
+        protected Object getListElement(Object store, int index) {
+            return ((RLanguage) store).getDataAtAsObject(index);
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() {
+        @Override
+        public RType getType() {
+            return RType.Language;
+        }
+
+        @TruffleBoundary
+        @Override
+        protected Object getListElement(Object store, int index) {
+            return ((RLanguage) store).getDataAtAsObject(index);
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
index 650c2f1173a80e6c7cf1f3b8dd5c56724421af39..ee3847e78bdd6e922630eb9882c3f90b42138ccd 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
@@ -25,7 +25,12 @@ package com.oracle.truffle.r.runtime.data;
 import java.util.Arrays;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 public final class RList extends RListBase implements RAbstractListVector {
 
@@ -83,4 +88,53 @@ public final class RList extends RListBase implements RAbstractListVector {
     protected RList internalCopyResized(int size, boolean fillNA, int[] dimensions) {
         return RDataFactory.createList(copyResizedData(size, fillNA), dimensions);
     }
+
+    private static final class FastPathAccess extends FastPathFromListAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        public RType getType() {
+            return RType.List;
+        }
+
+        @Override
+        protected Object getListElement(Object store, int index) {
+            return ((Object[]) store)[index];
+        }
+
+        @Override
+        protected void setListElement(Object store, int index, Object value) {
+            ((Object[]) store)[index] = value;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() {
+        @Override
+        public RType getType() {
+            return RType.List;
+        }
+
+        @Override
+        protected Object getListElement(Object store, int index) {
+            return ((RList) store).data[index];
+        }
+
+        @Override
+        protected void setListElement(Object store, int index, Object value) {
+            ((RList) store).data[index] = value;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
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 4538d1a4eecf854ffb1c05ef26e8c24113e292dc..f672375dec1e61b7580f9ab933f1256fa133365f 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
@@ -24,7 +24,6 @@ package com.oracle.truffle.r.runtime.data;
 
 import java.util.Arrays;
 
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.model.RAbstractListBaseVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
@@ -53,7 +52,7 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi
     RListBase(Object[] data) {
         super(false);
         this.data = data;
-        assert verify();
+        assert RAbstractVector.verify(this);
     }
 
     RListBase(Object[] data, int[] dims, RStringVector names, RList dimNames) {
@@ -94,21 +93,6 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi
         ((Object[]) store)[index] = value;
     }
 
-    @Override
-    public String toString() {
-        return toString(i -> RRuntime.toString(getDataAt(i)));
-    }
-
-    @Override
-    public final boolean verify() {
-        for (Object item : data) {
-            if (item == null) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     @Override
     public Object[] getInternalManagedData() {
         return data;
@@ -193,11 +177,6 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi
         return newData;
     }
 
-    @Override
-    public final boolean checkCompleteness() {
-        return true;
-    }
-
     @Override
     public final void setElement(int i, Object value) {
         data[i] = value;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java
index 7fade92f1bed1c2e7ebb42f3232d09a46e5c6184..c65961c55e9121c34a77f6b614b249cec3fbe78f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java
@@ -26,8 +26,12 @@ import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 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.FastPathVectorAccess.FastPathFromLogicalAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromLogicalAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 @ValueType
 public final class RLogical extends RScalarVector implements RAbstractLogicalVector {
@@ -105,4 +109,35 @@ public final class RLogical extends RScalarVector implements RAbstractLogicalVec
     public static boolean isValid(byte left) {
         return left == RRuntime.LOGICAL_NA || left == RRuntime.LOGICAL_FALSE || left == RRuntime.LOGICAL_TRUE;
     }
+
+    private static final class FastPathAccess extends FastPathFromLogicalAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected byte getLogical(Object store, int index) {
+            assert index == 0;
+            return ((RLogical) store).value;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromLogicalAccess SLOW_PATH_ACCESS = new SlowPathFromLogicalAccess() {
+        @Override
+        protected byte getLogical(Object store, int index) {
+            assert index == 0;
+            return ((RLogical) store).value;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
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 1d5bcca0900342eac04e280970e601c77d90ab45..8e097a7a97a430f0e34301f0e884ae43b44e47d4 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
@@ -29,8 +29,12 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.closures.RClosures;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 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.FastPathVectorAccess.FastPathFromLogicalAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromLogicalAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public final class RLogicalVector extends RVector<byte[]> implements RAbstractLogicalVector {
@@ -40,7 +44,7 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo
     RLogicalVector(byte[] data, boolean complete) {
         super(complete);
         this.data = data;
-        assert verify();
+        assert RAbstractVector.verify(this);
     }
 
     RLogicalVector(byte[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) {
@@ -95,6 +99,10 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo
         NativeDataAccess.setData(this, (byte[]) store, index, value);
     }
 
+    public void setDataAt(int index, byte value) {
+        NativeDataAccess.setData(this, data, index, value);
+    }
+
     @Override
     public byte getDataAt(Object store, int index) {
         assert data == store;
@@ -128,23 +136,6 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo
         return NativeDataAccess.getDataLength(this, data);
     }
 
-    @Override
-    public String toString() {
-        return toString(i -> RRuntime.logicalToString(getDataAt(i)));
-    }
-
-    @Override
-    public boolean verify() {
-        if (isComplete()) {
-            for (int i = 0; i < getLength(); i++) {
-                if (RRuntime.isNA(getDataAt(i))) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
     @Override
     public byte getDataAt(int index) {
         return NativeDataAccess.getData(this, data, index);
@@ -249,4 +240,49 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo
         }
         return result;
     }
+
+    private static final class FastPathAccess extends FastPathFromLogicalAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected byte getLogical(Object store, int index) {
+            return hasStore ? ((byte[]) store)[index] : NativeDataAccess.getLogicalNativeMirrorData(store, index);
+        }
+
+        @Override
+        protected void setLogical(Object store, int index, byte value) {
+            if (hasStore) {
+                ((byte[]) store)[index] = value;
+            } else {
+                NativeDataAccess.setNativeMirrorLogicalData(store, index, value);
+            }
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromLogicalAccess SLOW_PATH_ACCESS = new SlowPathFromLogicalAccess() {
+        @Override
+        protected byte getLogical(Object store, int index) {
+            RLogicalVector vector = (RLogicalVector) store;
+            return NativeDataAccess.getData(vector, vector.data, index);
+        }
+
+        @Override
+        protected void setLogical(Object store, int index, byte value) {
+            RLogicalVector vector = (RLogicalVector) store;
+            NativeDataAccess.setData(vector, vector.data, index, value);
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
index 18c853f56ae813bcfb2153c521b1464929092fea..74765b994d27f012599f7653a36f5f8db5e39810 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
@@ -33,6 +33,9 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 
 /**
@@ -73,6 +76,11 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra
         this.type = type;
     }
 
+    @Override
+    public Object getInternalStore() {
+        return this;
+    }
+
     /**
      * Creates a new pair list of given size > 0. Note: pair list of size 0 is NULL.
      */
@@ -375,4 +383,45 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra
             }
         };
     }
+
+    private static final class FastPathAccess extends FastPathFromListAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        public RType getType() {
+            return RType.PairList;
+        }
+
+        @TruffleBoundary
+        @Override
+        protected Object getListElement(Object store, int index) {
+            return ((RPairList) store).getDataAtAsObject(index);
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() {
+        @Override
+        public RType getType() {
+            return RType.PairList;
+        }
+
+        @TruffleBoundary
+        @Override
+        protected Object getListElement(Object store, int index) {
+            return ((RPairList) store).getDataAtAsObject(index);
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java
index ff3e3945beeb59beec24ff488c600d602b59aebd..78808abfca7c4d1c410787da6ae0c80777d1c473 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java
@@ -26,8 +26,12 @@ import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromRawAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromRawAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 @ValueType
 public final class RRaw extends RScalarVector implements RAbstractRawVector {
@@ -55,7 +59,7 @@ public final class RRaw extends RScalarVector implements RAbstractRawVector {
             case Complex:
                 return RComplex.valueOf(value, 0.0);
             case Character:
-                return RString.valueOf(RRuntime.rawToString(value));
+                return RString.valueOf(RRuntime.rawToHexString(value));
             default:
                 return null;
         }
@@ -99,4 +103,35 @@ public final class RRaw extends RScalarVector implements RAbstractRawVector {
     public static RRaw valueOf(byte value) {
         return new RRaw(value);
     }
+
+    private static final class FastPathAccess extends FastPathFromRawAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected byte getRaw(Object store, int index) {
+            assert index == 0;
+            return ((RRaw) store).value;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromRawAccess SLOW_PATH_ACCESS = new SlowPathFromRawAccess() {
+        @Override
+        protected byte getRaw(Object store, int index) {
+            assert index == 0;
+            return ((RRaw) store).value;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
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 97c9435c9d9db82394bd52be2eecdec1222a3d35..8da699c972bc7448564d0178c33d9e7079b15c40 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
@@ -25,12 +25,15 @@ package com.oracle.truffle.r.runtime.data;
 import java.util.Arrays;
 
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.closures.RClosures;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromRawAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromRawAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public final class RRawVector extends RVector<byte[]> implements RAbstractRawVector {
@@ -40,7 +43,7 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec
     RRawVector(byte[] data) {
         super(true);
         this.data = data;
-        assert verify();
+        assert RAbstractVector.verify(this);
     }
 
     RRawVector(byte[] data, int[] dims, RStringVector names, RList dimNames) {
@@ -92,18 +95,16 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec
         return NativeDataAccess.getData(this, data, index);
     }
 
-    @Override
-    public byte getRawDataAt(Object store, int index) {
-        assert data == store;
-        return NativeDataAccess.getData(this, (byte[]) store, index);
-    }
-
     @Override
     public void setRawDataAt(Object store, int index, byte value) {
         assert data == store;
         NativeDataAccess.setData(this, (byte[]) store, index, value);
     }
 
+    public void setRawDataAt(int index, byte value) {
+        NativeDataAccess.setData(this, data, index, value);
+    }
+
     @Override
     protected RRawVector internalCopy() {
         if (data != null) {
@@ -118,16 +119,6 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec
         return NativeDataAccess.getDataLength(this, data);
     }
 
-    @Override
-    public String toString() {
-        return toString(i -> RRuntime.rawToString(getRawDataAt(i)));
-    }
-
-    @Override
-    public boolean verify() {
-        return true;
-    }
-
     @Override
     public byte[] getDataCopy() {
         if (data != null) {
@@ -202,4 +193,49 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec
             complete = false;
         }
     }
+
+    private static final class FastPathAccess extends FastPathFromRawAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected byte getRaw(Object store, int index) {
+            return hasStore ? ((byte[]) store)[index] : NativeDataAccess.getRawNativeMirrorData(store, index);
+        }
+
+        @Override
+        protected void setRaw(Object store, int index, byte value) {
+            if (hasStore) {
+                ((byte[]) store)[index] = value;
+            } else {
+                NativeDataAccess.setNativeMirrorRawData(store, index, value);
+            }
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromRawAccess SLOW_PATH_ACCESS = new SlowPathFromRawAccess() {
+        @Override
+        protected byte getRaw(Object store, int index) {
+            RRawVector vector = (RRawVector) store;
+            return NativeDataAccess.getData(vector, vector.data, index);
+        }
+
+        @Override
+        protected void setRaw(Object store, int index, byte value) {
+            RRawVector vector = (RRawVector) store;
+            NativeDataAccess.setData(vector, vector.data, index, value);
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarList.java
index 1ea23adc66f510252e67c8aa0696a03e7e9d2993..044cdffb584ff280fe20b971d3ea9e221d69da8e 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarList.java
@@ -25,8 +25,12 @@ package com.oracle.truffle.r.runtime.data;
 import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 @ValueType
 public final class RScalarList extends RScalarVector implements RAbstractListVector {
@@ -87,4 +91,45 @@ public final class RScalarList extends RScalarVector implements RAbstractListVec
     public boolean isNA() {
         return false;
     }
+
+    private static final class FastPathAccess extends FastPathFromListAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        public RType getType() {
+            return RType.List;
+        }
+
+        @Override
+        protected Object getListElement(Object store, int index) {
+            assert index == 0;
+            return ((RScalarList) store).value;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() {
+        @Override
+        public RType getType() {
+            return RType.List;
+        }
+
+        @Override
+        protected Object getListElement(Object store, int index) {
+            assert index == 0;
+            return ((RScalarList) store).value;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java
index 80f1da3147b21cc03ee8a51ea175c0307f59413c..314b58af2dc90e4c1b3cf5653ab364312bf15f14 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java
@@ -36,6 +36,11 @@ public abstract class RScalarVector extends RScalar implements RAbstractVector {
         return this;
     }
 
+    @Override
+    public Object getInternalStore() {
+        return this;
+    }
+
     @Override
     public void setComplete(boolean complete) {
         // scalar vectors don't need this information.
@@ -170,9 +175,4 @@ public abstract class RScalarVector extends RScalar implements RAbstractVector {
     public boolean isArray() {
         return false;
     }
-
-    @Override
-    public final boolean checkCompleteness() {
-        return isComplete();
-    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java
index d9aa895489f362128e582c828f9161b20a408d2e..f9a75146fe100015669b7696d0c07fe4169de795 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java
@@ -41,6 +41,11 @@ public abstract class RSequence implements RAbstractVector {
         this.length = length;
     }
 
+    @Override
+    public Object getInternalStore() {
+        return this;
+    }
+
     @Override
     public final int getLength() {
         return length;
@@ -60,11 +65,6 @@ public abstract class RSequence implements RAbstractVector {
         return true;
     }
 
-    @Override
-    public boolean checkCompleteness() {
-        return true;
-    }
-
     @Override
     public void setComplete(boolean complete) {
         // sequences are always complete
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java
index abf51a343f797352297a0a94155670ef897b5d5b..2929ffb79f3b69310eeb31a2ffe31809f77d46a9 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java
@@ -27,8 +27,12 @@ import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 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.FastPathVectorAccess.FastPathFromStringAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromStringAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 @ValueType
 public final class RString extends RScalarVector implements RAbstractStringVector {
@@ -95,4 +99,35 @@ public final class RString extends RScalarVector implements RAbstractStringVecto
             throw new AssertionError();
         }
     }
+
+    private static final class FastPathAccess extends FastPathFromStringAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected String getString(Object store, int index) {
+            assert index == 0;
+            return ((RString) store).value;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromStringAccess SLOW_PATH_ACCESS = new SlowPathFromStringAccess() {
+        @Override
+        protected String getString(Object store, int index) {
+            assert index == 0;
+            return ((RString) store).value;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringSequence.java
index ee79af03a47bf35cf4c2b2577b3f09edbcedf22d..220df129745921d88f447758b9b1d0d2a1274d9f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringSequence.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringSequence.java
@@ -29,10 +29,14 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.closures.RClosures;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 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.FastPathVectorAccess.FastPathFromStringAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromStringAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
-public class RStringSequence extends RSequence implements RAbstractStringVector {
+public final class RStringSequence extends RSequence implements RAbstractStringVector {
 
     private final int start;
     private final int stride;
@@ -168,4 +172,37 @@ public class RStringSequence extends RSequence implements RAbstractStringVector
         CompilerAsserts.neverPartOfCompilation();
         return "[\"" + getStartObject() + "\" - \"" + prefix + getEnd() + suffix + "\"]";
     }
+
+    private static final class FastPathAccess extends FastPathFromStringAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected String getString(Object store, int index) {
+            RStringSequence vector = (RStringSequence) store;
+            assert index >= 0 && index < vector.getLength();
+            return vector.prefix + (vector.start + vector.stride * index) + vector.suffix;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromStringAccess SLOW_PATH_ACCESS = new SlowPathFromStringAccess() {
+        @Override
+        protected String getString(Object store, int index) {
+            RStringSequence vector = (RStringSequence) store;
+            assert index >= 0 && index < vector.getLength();
+            return vector.prefix + (vector.start + vector.stride * index) + vector.suffix;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
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 4a0374063a3f362a75d02fbbc2c91ba40a57a5b0..ee59d39da0552ac2d5483e9b28c762e12bbbfcf0 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
@@ -30,8 +30,12 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.closures.RClosures;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 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.FastPathVectorAccess.FastPathFromStringAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromStringAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public final class RStringVector extends RVector<String[]> implements RAbstractStringVector {
@@ -41,7 +45,7 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS
     RStringVector(String[] data, boolean complete) {
         super(complete);
         this.data = data;
-        assert verify();
+        assert RAbstractVector.verify(this);
     }
 
     RStringVector(String[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) {
@@ -78,6 +82,10 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS
         ((String[]) store)[index] = value;
     }
 
+    public void setDataAt(int index, String value) {
+        data[index] = value;
+    }
+
     @Override
     public String getDataAt(Object store, int index) {
         assert data == store;
@@ -119,23 +127,6 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS
         return data;
     }
 
-    @Override
-    public String toString() {
-        return toString(i -> getDataAt(i));
-    }
-
-    @Override
-    public boolean verify() {
-        if (isComplete()) {
-            for (String b : data) {
-                if (b == RRuntime.STRING_NA) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
     @Override
     public String getDataAt(int i) {
         return data[i];
@@ -219,4 +210,45 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS
     public void setElement(int i, Object value) {
         data[i] = (String) value;
     }
+
+    private static final class FastPathAccess extends FastPathFromStringAccess {
+
+        FastPathAccess(RAbstractContainer value) {
+            super(value);
+        }
+
+        @Override
+        protected String getString(Object store, int index) {
+            assert hasStore;
+            return ((String[]) store)[index];
+        }
+
+        @Override
+        protected void setString(Object store, int index, String value) {
+            assert hasStore;
+            ((String[]) store)[index] = value;
+        }
+    }
+
+    @Override
+    public VectorAccess access() {
+        return new FastPathAccess(this);
+    }
+
+    private static final SlowPathFromStringAccess SLOW_PATH_ACCESS = new SlowPathFromStringAccess() {
+        @Override
+        protected String getString(Object store, int index) {
+            return ((RStringVector) store).data[index];
+        }
+
+        @Override
+        protected void setString(Object store, int index, String value) {
+            ((RStringVector) store).data[index] = value;
+        }
+    };
+
+    @Override
+    public VectorAccess slowPathAccess() {
+        return SLOW_PATH_ACCESS;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java
index f11da3d123650f52a9ed9c974c93284153ae10de..582b9366c70bc6a0cdd69ba8e82cba861b652241 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java
@@ -109,21 +109,11 @@ public class RTypes {
         return RDataFactory.createDoubleVectorFromScalar(value);
     }
 
-    @ImplicitCast
-    public static RAbstractContainer toAbstractContainer(RRaw value) {
-        return RDataFactory.createRawVectorFromScalar(value);
-    }
-
     @ImplicitCast
     public static RAbstractContainer toAbstractContainer(byte value) {
         return RDataFactory.createLogicalVectorFromScalar(value);
     }
 
-    @ImplicitCast
-    public static RAbstractContainer toAbstractContainer(RComplex value) {
-        return RDataFactory.createComplexVectorFromScalar(value);
-    }
-
     @ImplicitCast
     public static RAbstractContainer toAbstractContainer(String value) {
         return RDataFactory.createStringVectorFromScalar(value);
@@ -139,21 +129,11 @@ public class RTypes {
         return RDataFactory.createDoubleVectorFromScalar(value);
     }
 
-    @ImplicitCast
-    public static RAbstractVector toAbstractVector(RRaw value) {
-        return RDataFactory.createRawVectorFromScalar(value);
-    }
-
     @ImplicitCast
     public static RAbstractVector toAbstractVector(byte value) {
         return RDataFactory.createLogicalVectorFromScalar(value);
     }
 
-    @ImplicitCast
-    public static RAbstractVector toAbstractVector(RComplex value) {
-        return RDataFactory.createComplexVectorFromScalar(value);
-    }
-
     @ImplicitCast
     public static RAbstractVector toAbstractVector(String value) {
         return RDataFactory.createStringVectorFromScalar(value);
@@ -169,21 +149,11 @@ public class RTypes {
         return RDataFactory.createDoubleVectorFromScalar(value);
     }
 
-    @ImplicitCast
-    public static RAbstractComplexVector toAbstractComplexVector(RComplex vector) {
-        return RDataFactory.createComplexVectorFromScalar(vector);
-    }
-
     @ImplicitCast
     public static RAbstractLogicalVector toAbstractLogicalVector(byte vector) {
         return RDataFactory.createLogicalVectorFromScalar(vector);
     }
 
-    @ImplicitCast
-    public static RAbstractRawVector toAbstractRawVector(RRaw vector) {
-        return RDataFactory.createRawVectorFromScalar(vector);
-    }
-
     @ImplicitCast
     public static RAbstractStringVector toAbstractStringVector(String vector) {
         return RDataFactory.createStringVectorFromScalar(vector);
@@ -199,21 +169,11 @@ public class RTypes {
         return RDataFactory.createDoubleVectorFromScalar(value);
     }
 
-    @ImplicitCast
-    public static RAbstractAtomicVector toAbstractAtomicVector(RRaw value) {
-        return RDataFactory.createRawVectorFromScalar(value);
-    }
-
     @ImplicitCast
     public static RAbstractAtomicVector toAbstractAtomicVector(byte value) {
         return RDataFactory.createLogicalVectorFromScalar(value);
     }
 
-    @ImplicitCast
-    public static RAbstractAtomicVector toAbstractAtomicVector(RComplex value) {
-        return RDataFactory.createComplexVectorFromScalar(value);
-    }
-
     @ImplicitCast
     public static RAbstractAtomicVector toAbstractAtomicVector(String value) {
         return RDataFactory.createStringVectorFromScalar(value);
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 5f7239c993e84846c1d3b7a57d589b66788301e5..2e2b076c975bf3fb8b2bf88d6582cc73b76c82a2 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
@@ -24,8 +24,6 @@ package com.oracle.truffle.r.runtime.data;
 
 import static com.oracle.truffle.r.runtime.RError.NO_CALLER;
 
-import java.util.function.Function;
-
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -33,13 +31,14 @@ import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.SuppressFBWarnings;
 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.GetReadonlyData;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
@@ -59,9 +58,6 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
  */
 public abstract class RVector<ArrayT> extends RSharingAttributeStorage implements RAbstractVector, RFFIAccess {
 
-    private static final RStringVector implicitClassHeaderArray = RDataFactory.createStringVector(new String[]{RType.Array.getName()}, true);
-    private static final RStringVector implicitClassHeaderMatrix = RDataFactory.createStringVector(new String[]{RType.Matrix.getName()}, true);
-
     protected boolean complete; // "complete" means: does not contain NAs
 
     protected RVector(boolean complete) {
@@ -140,7 +136,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     @Override
     public final void setComplete(boolean complete) {
         this.complete = complete;
-        assert verify();
+        assert RAbstractVector.verify(this);
     }
 
     private void removeAttributeMapping(String key) {
@@ -537,8 +533,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
 
     protected abstract RVector<ArrayT> internalCopy();
 
-    public abstract boolean verify();
-
     /**
      * Update a data item in the vector. Possibly not as efficient as type-specific methods, but in
      * some cases it likely does not matter (e.g. if used alongside I/O operations).
@@ -607,50 +601,52 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
      * Inits dims, names and dimnames attributes and it should only be invoked if no attributes were
      * initialized yet.
      */
-    @TruffleBoundary
-    protected final void initDimsNamesDimNames(int[] dimensions, RStringVector names, RList dimNames) {
+    final void initDimsNamesDimNames(int[] dimensions, RStringVector names, RList dimNames) {
         assert (this.attributes == null) : "Vector attributes must be null";
         assert names != this;
         assert dimNames != this;
+        assert names == null || names.getLength() == getLength() : "size mismatch: names.length=" + names.getLength() + " vs. length=" + getLength();
+        initAttributes(createAttributes(dimensions, names, dimNames));
+    }
+
+    @TruffleBoundary
+    static DynamicObject createAttributes(int[] dimensions, RStringVector names, RList dimNames) {
         if (dimNames != null) {
-            DynamicObject attrs;
             if (dimensions != null) {
                 RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true);
-                attrs = RAttributesLayout.createDimAndDimNames(dimensionsVector, dimNames);
                 // one-dimensional arrays do not have names, only dimnames with one value so do not
                 // init names in that case
                 if (names != null && dimensions.length != 1) {
-                    assert names.getLength() == getLength() : "size mismatch: names.length=" + names.getLength() + " vs. length=" + getLength();
-                    attrs.define(RRuntime.NAMES_ATTR_KEY, names);
+                    return RAttributesLayout.createNamesAndDimAndDimNames(names, dimensionsVector, dimNames);
+                } else {
+                    return RAttributesLayout.createDimAndDimNames(dimensionsVector, dimNames);
                 }
             } else {
-                attrs = RAttributesLayout.createDimNames(dimNames);
                 if (names != null) {
-                    assert names.getLength() == getLength() : "size mismatch: names.length=" + names.getLength() + " vs. length=" + getLength();
-                    attrs.define(RRuntime.NAMES_ATTR_KEY, names);
+                    return RAttributesLayout.createNamesAndDimNames(names, dimNames);
+                } else {
+                    return RAttributesLayout.createDimNames(dimNames);
                 }
             }
-            initAttributes(attrs);
         } else {
-            if (names != null) {
-                // since this constructor is for internal use only, the assertion shouldn't fail
-                assert names.getLength() == getLength() : "size mismatch: " + names.getLength() + " vs. " + getLength();
-                if (dimensions != null) {
-                    RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true);
+            if (dimensions != null) {
+                RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true);
+                if (names != null) {
                     if (dimensions.length != 1) {
-                        initAttributes(RAttributesLayout.createNamesAndDim(names, dimensionsVector));
+                        return RAttributesLayout.createNamesAndDim(names, dimensionsVector);
                     } else {
                         // one-dimensional arrays do not have names, only dimnames with one value
                         RList newDimNames = RDataFactory.createList(new Object[]{names});
-                        initAttributes(RAttributesLayout.createDimAndDimNames(dimensionsVector, newDimNames));
+                        return RAttributesLayout.createDimAndDimNames(dimensionsVector, newDimNames);
                     }
                 } else {
-                    initAttributes(RAttributesLayout.createNames(names));
+                    return RAttributesLayout.createDim(dimensionsVector);
                 }
             } else {
-                if (dimensions != null) {
-                    RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true);
-                    initAttributes(RAttributesLayout.createDim(dimensionsVector));
+                if (names != null) {
+                    return RAttributesLayout.createNames(names);
+                } else {
+                    return null;
                 }
             }
         }
@@ -749,18 +745,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         }
     }
 
-    // As shape of the vector may change at run-time we need to compute
-    // class hierarchy on the fly.
-    protected final RStringVector getClassHierarchyHelper(RStringVector implicitClassHeader) {
-        if (isMatrix()) {
-            return implicitClassHeaderMatrix;
-        }
-        if (isArray()) {
-            return implicitClassHeaderArray;
-        }
-        return implicitClassHeader;
-    }
-
     public static void verifyDimensions(int vectorLength, int[] newDimensions, RBaseNode invokingNode) {
         int length = 1;
         for (int i = 0; i < newDimensions.length; i++) {
@@ -778,18 +762,25 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
 
     private static final int MAX_TOSTRING_LENGTH = 100;
 
-    protected final String toString(Function<Integer, String> element) {
+    @Override
+    public final String toString() {
         CompilerAsserts.neverPartOfCompilation();
         StringBuilder str = new StringBuilder("[");
-        for (int i = 0; i < getLength(); i++) {
-            if (i > 0) {
-                str.append(", ");
-            }
-            str.append(element.apply(i));
-            if (str.length() > MAX_TOSTRING_LENGTH - 1) {
-                str.setLength(MAX_TOSTRING_LENGTH - 4);
-                str.append("...");
-                break;
+        VectorAccess access = slowPathAccess();
+        try (SequentialIterator iter = access.access(this)) {
+            if (access.next(iter)) {
+                while (true) {
+                    str.append(access.getType().isAtomic() ? access.getString(iter) : access.getListElement(iter).toString());
+                    if (!access.next(iter)) {
+                        break;
+                    }
+                    str.append(", ");
+                    if (str.length() > MAX_TOSTRING_LENGTH - 1) {
+                        str.setLength(MAX_TOSTRING_LENGTH - 4);
+                        str.append("...");
+                        break;
+                    }
+                }
             }
         }
         return str.append(']').toString();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java
index e8c5104485f640935efc3d2ff41c6c78bae2f052..7495f52ae81abb5793ecb327fd2aa960d8661454 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.runtime.data.closures;
 
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -31,6 +32,7 @@ import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 abstract class RToVectorClosure implements RAbstractVector {
 
@@ -49,8 +51,8 @@ abstract class RToVectorClosure implements RAbstractVector {
     }
 
     @Override
-    public EmptyInternalStore getInternalStore() {
-        return EmptyInternalStore.INSTANCE;
+    public Object getInternalStore() {
+        return this;
     }
 
     @Override
@@ -184,4 +186,14 @@ abstract class RToVectorClosure implements RAbstractVector {
         // first materialize and then cast and do not create a closure over a closure.
         return materialize().castSafe(type, isNAProfile, keepAttrs);
     }
+
+    @Override
+    public final VectorAccess access() {
+        throw RInternalError.shouldNotReachHere("access() for " + getClass().getSimpleName());
+    }
+
+    @Override
+    public final VectorAccess slowPathAccess() {
+        throw RInternalError.shouldNotReachHere("slowPathAccess() for " + getClass().getSimpleName());
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java
index b2d9e6cd06d0ad7e508393bfe0f29004d3e6f8f4..930526998fc0672d6b855b6ff55be175aafc5399 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.runtime.data.model;
 
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
@@ -36,10 +35,6 @@ public interface RAbstractComplexVector extends RAbstractAtomicVector {
 
     RComplex getDataAt(int index);
 
-    default RComplex getDataAt(@SuppressWarnings("unused") Object store, int index) {
-        return getDataAt(index);
-    }
-
     @Override
     RComplexVector materialize();
 
@@ -48,16 +43,6 @@ public interface RAbstractComplexVector extends RAbstractAtomicVector {
         throw new UnsupportedOperationException();
     }
 
-    @Override
-    default boolean checkCompleteness() {
-        for (int i = 0; i < getLength(); i++) {
-            if (RRuntime.isNA(getDataAt(i))) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     @Override
     default RType getRType() {
         return RType.Complex;
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 8723bed3da30a69e05f8e1f9405bcaf65a9ca798..93742f57b50b9c830d70599ccadaef1f576228c2 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
@@ -28,6 +28,7 @@ import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
 
 public interface RAbstractContainer extends RAttributable, RTypedValue {
 
@@ -67,9 +68,7 @@ public interface RAbstractContainer extends RAttributable, RTypedValue {
      * vector's fields, but instead read the necessary data from a local variable, which could be
      * beneficial when in loop.
      */
-    default Object getInternalStore() {
-        return EmptyInternalStore.INSTANCE;
-    }
+    Object getInternalStore();
 
     default RStringVector getNames() {
         CompilerAsserts.neverPartOfCompilation();
@@ -101,10 +100,7 @@ public interface RAbstractContainer extends RAttributable, RTypedValue {
         setAttr(RRuntime.ROWNAMES_ATTR_KEY, rowNames);
     }
 
-    final class EmptyInternalStore {
-        private EmptyInternalStore() {
-        }
+    VectorAccess access();
 
-        public static final EmptyInternalStore INSTANCE = new EmptyInternalStore();
-    }
+    VectorAccess slowPathAccess();
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java
index ab8c782a3f97d0e8882eb8d551d50debf22905f0..c223c64054322e529a90b95aa7604c89c0cd24e7 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.runtime.data.model;
 
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 
@@ -47,16 +46,6 @@ public interface RAbstractDoubleVector extends RAbstractAtomicVector {
     @Override
     RDoubleVector materialize();
 
-    @Override
-    default boolean checkCompleteness() {
-        for (int i = 0; i < getLength(); i++) {
-            if (RRuntime.isNA(getDataAt(i))) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     @Override
     default RType getRType() {
         return RType.Double;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java
index 92401aea21e6a7f5a42f0c130ab62b3c716806ce..727f43772b68078cd1061ee364a1c6185a5ffabb 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.runtime.data.model;
 
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 
@@ -47,16 +46,6 @@ public interface RAbstractIntVector extends RAbstractAtomicVector {
     @Override
     RIntVector materialize();
 
-    @Override
-    default boolean checkCompleteness() {
-        for (int i = 0; i < getLength(); i++) {
-            if (RRuntime.isNA(getDataAt(i))) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     @Override
     default RType getRType() {
         return RType.Integer;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java
index ea019fe0a4d23b6cd5a43837a78d79f5b1095925..e6f99db40e80746821447236403f97d8655b4315 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java
@@ -35,9 +35,4 @@ public interface RAbstractListBaseVector extends RAbstractVector {
     default void setDataAt(Object store, int index, Object value) {
         throw new UnsupportedOperationException();
     }
-
-    @Override
-    default boolean checkCompleteness() {
-        return true;
-    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java
index 2a1c503de5361dcd250c061344b5c621f97c0e8a..ff0ac5f5732aa924f1c6e86a7b4da6e2079d1dd6 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.runtime.data.model;
 
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 
@@ -47,16 +46,6 @@ public interface RAbstractLogicalVector extends RAbstractAtomicVector {
     @Override
     RLogicalVector materialize();
 
-    @Override
-    default boolean checkCompleteness() {
-        for (int i = 0; i < getLength(); i++) {
-            if (RRuntime.isNA(getDataAt(i))) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     @Override
     default RType getRType() {
         return RType.Logical;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java
index 5f8697e39d73b98504936405749183fdf25dd57d..f76d746806f59a662716945e38833fe32abe671c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java
@@ -33,10 +33,6 @@ public interface RAbstractRawVector extends RAbstractAtomicVector {
         return RRaw.valueOf(getRawDataAt(index));
     }
 
-    default byte getRawDataAt(@SuppressWarnings("unused") Object store, int index) {
-        return getRawDataAt(index);
-    }
-
     @SuppressWarnings("unused")
     default void setRawDataAt(Object store, int index, byte value) {
         throw new UnsupportedOperationException();
@@ -47,11 +43,6 @@ public interface RAbstractRawVector extends RAbstractAtomicVector {
     @Override
     RRawVector materialize();
 
-    @Override
-    default boolean checkCompleteness() {
-        return true;
-    }
-
     @Override
     default RType getRType() {
         return RType.Raw;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java
index af93f141e09f2791c2e7fcc4b809b2302ce22355..c6e5f960d14c5c54ded61a751aef5c19cc2d46a8 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.runtime.data.model;
 
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 
@@ -47,16 +46,6 @@ public interface RAbstractStringVector extends RAbstractAtomicVector {
     @Override
     RStringVector materialize();
 
-    @Override
-    default boolean checkCompleteness() {
-        for (int i = 0; i < getLength(); i++) {
-            if (RRuntime.isNA(getDataAt(i))) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     @Override
     default RType getRType() {
         return RType.Character;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java
index e5fe39c6a8072bf343a0f169dfe81af770a1acd1..43039d80a1facd3c392b8cf758a7f46f97081d96 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java
@@ -22,10 +22,13 @@
  */
 package com.oracle.truffle.r.runtime.data.model;
 
+import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.MemoryCopyTracer;
 import com.oracle.truffle.r.runtime.data.RVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 
 /**
  * When implementing, make sure to invoke related {@link MemoryCopyTracer} methods.
@@ -62,8 +65,6 @@ public interface RAbstractVector extends RAbstractContainer {
 
     boolean isArray();
 
-    boolean checkCompleteness();
-
     /**
      * Casts a vector to another {@link RType}. If a safe cast to the target {@link RType} is not
      * supported <code>null</code> is returned. Instead of materializing the cast for each index the
@@ -99,4 +100,31 @@ public interface RAbstractVector extends RAbstractContainer {
     }
 
     void setComplete(boolean complete);
+
+    /**
+     * Verifies the integrity of the vector, mainly whether a vector that claims to be
+     * {@link #isComplete()} contains NA values.
+     */
+    static boolean verify(RAbstractVector vector) {
+        CompilerAsserts.neverPartOfCompilation();
+        VectorAccess access = vector.slowPathAccess();
+        assert access.getType().isVector();
+        if (!access.getType().isAtomic()) {
+            // check non-atomic vectors for nullness
+            try (SequentialIterator iter = access.access(vector)) {
+                while (access.next(iter)) {
+                    assert access.getListElement(iter) != null : "element " + iter.getIndex() + " of vector " + vector + " is null";
+                }
+            }
+        }
+        if (vector.isComplete()) {
+            // check all vectors for completeness
+            try (SequentialIterator iter = access.access(vector)) {
+                while (access.next(iter)) {
+                    assert !access.isNA(iter) : "element " + iter.getIndex() + " of vector " + vector + " is NA";
+                }
+            }
+        }
+        return true;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/EnableNACheckNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/EnableNACheckNode.java
deleted file mode 100644
index d9884dc6260054d5f0cca9fcb034a26bd53f4457..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/EnableNACheckNode.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 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.data.nodes;
-
-import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.ops.na.NACheck;
-
-public abstract class EnableNACheckNode extends Node {
-    public abstract void execute(NACheck check, RAbstractVector vector);
-
-    public static EnableNACheckNode create() {
-        return EnableNACheckNodeGen.create();
-    }
-
-    @Specialization(guards = "vector.getClass() == clazz", limit = "10")
-    public void doEnable(NACheck check, RAbstractVector vector,
-                    @Cached("vector.getClass()") Class<? extends RAbstractVector> clazz) {
-        check.enable(clazz.cast(vector));
-    }
-
-    @Specialization(replaces = "doEnable")
-    public void doEnableGeneric(NACheck check, RAbstractVector vector) {
-        check.enable(vector);
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/FastPathVectorAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/FastPathVectorAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d8948d3f6913035d3a0c070767e2f138e3f0ab3
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/FastPathVectorAccess.java
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 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.data.nodes;
+
+import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RComplex;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RRaw;
+import com.oracle.truffle.r.runtime.data.RVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+
+/**
+ * Base classes for {@link VectorAccess} implementations that are used on the fast path. For
+ * implementation reasons, most of this code is mirrored in {@link SlowPathVectorAccess}, so that
+ * any changes need to be mirrored there.
+ */
+public abstract class FastPathVectorAccess extends VectorAccess {
+
+    protected boolean naReported; // TODO: move this into the iterator
+
+    protected FastPathVectorAccess(Object value) {
+        super(value.getClass(), value instanceof RAbstractContainer ? ((RAbstractContainer) value).getInternalStore() != null : true);
+    }
+
+    @Override
+    protected final Object getStore(RAbstractContainer vector) {
+        return hasStore ? vector.getInternalStore() : ((RVector<?>) vector).getNativeMirror();
+    }
+
+    protected final void warning(RError.Message message) {
+        CompilerAsserts.neverPartOfCompilation();
+        if (!naReported) {
+            RError.warning(RError.SHOW_CALLER, message);
+            naReported = true;
+        }
+    }
+
+    public abstract static class FastPathFromIntAccess extends FastPathVectorAccess {
+
+        public FastPathFromIntAccess(Object value) {
+            super(value);
+        }
+
+        @Override
+        public final RType getType() {
+            return RType.Integer;
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RRuntime.DOUBLE_NA : RRuntime.int2doubleNoCheck(value);
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            int value = getInt(store, index);
+            byte result = (byte) value;
+            if ((result & 0xff) != value) {
+                warning(Message.OUT_OF_RANGE);
+                return 0;
+            }
+            return result;
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.int2logicalNoCheck(value);
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RComplex.createNA() : RRuntime.int2complexNoCheck(value);
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value;
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0;
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RRuntime.STRING_NA : RRuntime.intToStringNoCheck(value);
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return getInt(store, index);
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setInt(store, index, sourceAccess.getInt(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setInt(store, index, sourceAccess.getInt(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            setInt(store, index, RRuntime.INT_NA);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.check(getInt(store, index));
+        }
+    }
+
+    public abstract static class FastPathFromDoubleAccess extends FastPathVectorAccess {
+
+        public FastPathFromDoubleAccess(Object value) {
+            super(value);
+        }
+
+        @Override
+        public final RType getType() {
+            return RType.Double;
+        }
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            double value = getDouble(store, index);
+            if (Double.isNaN(value)) {
+                na.enable(true);
+                return RRuntime.INT_NA;
+            }
+            if (value > Integer.MAX_VALUE || value <= Integer.MIN_VALUE) {
+                na.enable(true);
+                warning(Message.NA_INTRODUCED_COERCION_INT);
+                return RRuntime.INT_NA;
+            }
+            return (int) value;
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            int value = (int) getDouble(store, index);
+            byte result = (byte) value;
+            if ((result & 0xff) != value) {
+                warning(Message.OUT_OF_RANGE);
+                return 0;
+            }
+            return result;
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            double value = getDouble(store, index);
+            return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.double2logicalNoCheck(value);
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            double value = getDouble(store, index);
+            return na.check(value) ? RComplex.createNA() : RRuntime.double2complexNoCheck(value);
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            double value = getDouble(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value;
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            double value = getDouble(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0;
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            double value = getDouble(store, index);
+            return na.check(value) ? RRuntime.STRING_NA : RContext.getRRuntimeASTAccess().encodeDouble(value);
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return getDouble(store, index);
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setDouble(store, index, sourceAccess.getDouble(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setDouble(store, index, sourceAccess.getDouble(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            setDouble(store, index, RRuntime.DOUBLE_NA);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.check(getDouble(store, index));
+        }
+    }
+
+    public abstract static class FastPathFromLogicalAccess extends FastPathVectorAccess {
+
+        public FastPathFromLogicalAccess(Object value) {
+            super(value);
+        }
+
+        @Override
+        public final RType getType() {
+            return RType.Logical;
+        }
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RRuntime.INT_NA : RRuntime.logical2intNoCheck(value);
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RRuntime.DOUBLE_NA : RRuntime.logical2doubleNoCheck(value);
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            byte value = getLogical(store, index);
+            if (na.check(value)) {
+                warning(Message.OUT_OF_RANGE);
+                return 0;
+            }
+            return value;
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RComplex.createNA() : RRuntime.logical2complexNoCheck(value);
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value;
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0;
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RRuntime.STRING_NA : RRuntime.logicalToStringNoCheck(value);
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return getLogical(store, index);
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setLogical(store, index, sourceAccess.getLogical(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setLogical(store, index, sourceAccess.getLogical(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            setLogical(store, index, RRuntime.LOGICAL_NA);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.check(getLogical(store, index));
+        }
+    }
+
+    public abstract static class FastPathFromRawAccess extends FastPathVectorAccess {
+
+        public FastPathFromRawAccess(Object value) {
+            super(value);
+        }
+
+        @Override
+        public final RType getType() {
+            return RType.Raw;
+        }
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            return getRaw(store, index) & 0xff;
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            return getRaw(store, index) & 0xff;
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            return getRaw(store, index) == 0 ? RRuntime.LOGICAL_FALSE : RRuntime.LOGICAL_TRUE;
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            return RComplex.valueOf(getRaw(store, index) & 0xff, 0);
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            return getRaw(store, index) & 0xff;
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            return 0;
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            return RRuntime.rawToHexString(getRaw(store, index));
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return RRaw.valueOf(getRaw(store, index));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setRaw(store, index, sourceAccess.getRaw(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setRaw(store, index, sourceAccess.getRaw(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            /*
+             * There is no raw NA, but places that write NA for other types usually write 0 for raw.
+             */
+            setRaw(store, index, (byte) 0);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return false;
+        }
+    }
+
+    public abstract static class FastPathFromComplexAccess extends FastPathVectorAccess {
+
+        public FastPathFromComplexAccess(Object value) {
+            super(value);
+        }
+
+        @Override
+        public final RType getType() {
+            return RType.Complex;
+        }
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            double value = getComplexR(store, index);
+            if (Double.isNaN(value)) {
+                na.enable(true);
+                return RRuntime.INT_NA;
+            }
+            if (value > Integer.MAX_VALUE || value <= Integer.MIN_VALUE) {
+                na.enable(true);
+                warning(Message.NA_INTRODUCED_COERCION_INT);
+                return RRuntime.INT_NA;
+            }
+            if (getComplexI(store, index) != 0) {
+                warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
+            }
+            return (int) value;
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            double value = getComplexR(store, index);
+            if (Double.isNaN(value)) {
+                na.enable(true);
+                return RRuntime.DOUBLE_NA;
+            }
+            if (getComplexI(store, index) != 0) {
+                warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
+            }
+            return value;
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            double value = getComplexR(store, index);
+            if (Double.isNaN(value) || value < 0 || value >= 256) {
+                warning(Message.OUT_OF_RANGE);
+                return 0;
+            }
+            if (getComplexI(store, index) != 0) {
+                warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
+            }
+            return (byte) value;
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            RComplex value = getComplex(store, index);
+            return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.complex2logicalNoCheck(value);
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            RComplex value = getComplex(store, index);
+            return na.check(value) ? RRuntime.STRING_NA : RContext.getRRuntimeASTAccess().encodeComplex(value);
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return getComplex(store, index);
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setComplex(store, index, sourceAccess.getComplexR(sourceIter), sourceAccess.getComplexI(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setComplex(store, index, sourceAccess.getComplexR(sourceIter, sourceIndex), sourceAccess.getComplexI(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            setComplex(store, index, RRuntime.COMPLEX_NA_REAL_PART, RRuntime.COMPLEX_NA_IMAGINARY_PART);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.check(getComplexR(store, index), getComplexI(store, index));
+        }
+    }
+
+    public abstract static class FastPathFromStringAccess extends FastPathVectorAccess {
+
+        public FastPathFromStringAccess(Object value) {
+            super(value);
+        }
+
+        @Override
+        public final RType getType() {
+            return RType.Character;
+        }
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            return na.convertStringToInt(getString(store, index));
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            return na.convertStringToDouble(getString(store, index));
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            int value = na.convertStringToInt(getString(store, index));
+            return value >= 0 && value <= 255 ? (byte) value : 0;
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            return na.convertStringToLogical(getString(store, index));
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            return na.convertStringToComplex(getString(store, index));
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            return na.convertStringToComplex(getString(store, index)).getRealPart();
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            return na.convertStringToComplex(getString(store, index)).getImaginaryPart();
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return getString(store, index);
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setString(store, index, sourceAccess.getString(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setString(store, index, sourceAccess.getString(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            setString(store, index, RRuntime.STRING_NA);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.check(getString(store, index));
+        }
+    }
+
+    public abstract static class FastPathFromListAccess extends FastPathVectorAccess {
+
+        public FastPathFromListAccess(Object value) {
+            super(value);
+        }
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setListElement(store, index, sourceAccess.getListElement(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setListElement(store, index, sourceAccess.getListElement(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            /*
+             * There is no list NA, but places that write NA for other types usually write NULL for
+             * lists.
+             */
+            setListElement(store, index, RNull.instance);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.checkListElement(getListElement(store, index));
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataAt.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataAt.java
deleted file mode 100644
index e85b37ebc48af203afdc4afb8bb653f1a103da2e..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataAt.java
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright (c) 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.data.nodes;
-
-import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.Fallback;
-import com.oracle.truffle.api.dsl.ImportStatic;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.data.NativeDataAccess;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
-import com.oracle.truffle.r.runtime.data.RDoubleSequence;
-import com.oracle.truffle.r.runtime.data.RDoubleVector;
-import com.oracle.truffle.r.runtime.data.RIntSequence;
-import com.oracle.truffle.r.runtime.data.RIntVector;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
-import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-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.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.data.nodes.GetDataAtFactory.DoubleNodeGen;
-import com.oracle.truffle.r.runtime.data.nodes.GetDataAtFactory.IntNodeGen;
-
-/**
- * Contains nodes implementing fast-path versions of e.g.
- * {@link RAbstractIntVector#getDataAt(Object, int)}. The first parameter 'store' should be
- * retrieved for given vector using {@link GetDataStore} node. Store object must be used only for
- * accessing the data of the vector for which it was created. The reason for having a store object
- * is to avoid field load (field of the RVector object) on every data access.
- */
-public abstract class GetDataAt extends Node {
-
-    public abstract Object getAsObject(RAbstractVector vector, Object store, int index);
-
-    @ImportStatic(NativeDataAccess.class)
-    @SuppressWarnings("unused")
-    public abstract static class Int extends GetDataAt {
-
-        public static Int create() {
-            return IntNodeGen.create();
-        }
-
-        @Override
-        public Object getAsObject(RAbstractVector vector, Object store, int index) {
-            return get((RAbstractIntVector) vector, store, index);
-        }
-
-        public final int get(RAbstractIntVector vector, Object store, int index) {
-            return execute(vector, store, index);
-        }
-
-        public abstract int execute(RAbstractIntVector vector, Object store, int index);
-
-        protected int doRVector(RIntVector vector, int[] store, int index) {
-            return store[index];
-        }
-
-        @Specialization(guards = "isNativeMirror(store)")
-        protected int doRVector(RIntVector vector, Object store, int index) {
-            return NativeDataAccess.getIntNativeMirrorData(store, index);
-        }
-
-        @Specialization
-        protected int doSequence(RIntSequence sequence, Object store, int index) {
-            return sequence.getStart() + index * sequence.getStride();
-        }
-
-        // This accounts for other vector types, like closures
-        @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"}, limit = "3")
-        protected int doGenericCached(RAbstractIntVector vector, Object store, int index,
-                        @Cached("vector.getClass()") Class<? extends RAbstractIntVector> cachedClass) {
-            return cachedClass.cast(vector).getDataAt(store, index);
-        }
-
-        @Specialization(guards = {"isGenericVector(vector)"}, replaces = "doGenericCached")
-        protected int doGeneric(RAbstractIntVector vector, Object store, int index) {
-            return vector.getDataAt(store, index);
-        }
-
-        @Fallback
-        protected int doFallback(RAbstractIntVector vector, Object store, int index) {
-            return vector.getDataAt(store, index);
-        }
-
-        protected static boolean isGenericVector(RAbstractIntVector vector) {
-            return !(vector instanceof RIntVector) && !(vector instanceof RIntSequence);
-        }
-    }
-
-    @ImportStatic(NativeDataAccess.class)
-    @SuppressWarnings("unused")
-    public abstract static class Double extends GetDataAt {
-
-        public static Double create() {
-            return DoubleNodeGen.create();
-        }
-
-        @Override
-        public Object getAsObject(RAbstractVector vector, Object store, int index) {
-            return get((RAbstractDoubleVector) vector, store, index);
-        }
-
-        public final double get(RAbstractDoubleVector vector, Object store, int index) {
-            return execute(vector, store, index);
-        }
-
-        public abstract double execute(RAbstractDoubleVector vector, Object store, int index);
-
-        @Specialization(guards = "isNativeMirror(store)")
-        protected double doRVector(RDoubleVector vector, Object store, int index) {
-            return NativeDataAccess.getDoubleNativeMirrorData(store, index);
-        }
-
-        @Specialization
-        protected double doRVector(RDoubleVector vector, double[] store, int index) {
-            return store[index];
-        }
-
-        @Specialization
-        protected double doSequence(RDoubleSequence sequence, Object store, int index) {
-            return sequence.getStart() + index * sequence.getStride();
-        }
-
-        @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"}, limit = "3")
-        protected double doGenericCached(RAbstractDoubleVector vector, Object store, int index,
-                        @Cached("vector.getClass()") Class<?> cachedClass) {
-            return ((RAbstractDoubleVector) cachedClass.cast(vector)).getDataAt(store, index);
-        }
-
-        @Specialization(guards = "isGenericVector(vector)", replaces = "doGenericCached")
-        protected double doGeneric(RAbstractDoubleVector vector, Object store, int index) {
-            return vector.getDataAt(store, index);
-        }
-
-        @Fallback
-        protected double doFallback(RAbstractDoubleVector vector, Object store, int index) {
-            return vector.getDataAt(store, index);
-        }
-
-        protected static boolean isGenericVector(RAbstractDoubleVector vector) {
-            return !(vector instanceof RDoubleVector) && !(vector instanceof RDoubleSequence);
-        }
-    }
-
-    @ImportStatic(NativeDataAccess.class)
-    @SuppressWarnings("unused")
-    public abstract static class Logical extends GetDataAt {
-
-        public static Logical create() {
-            return GetDataAtFactory.LogicalNodeGen.create();
-        }
-
-        @Override
-        public Object getAsObject(RAbstractVector vector, Object store, int index) {
-            return get((RAbstractLogicalVector) vector, store, index);
-        }
-
-        public final byte get(RAbstractLogicalVector vector, Object store, int index) {
-            return execute(vector, store, index);
-        }
-
-        public abstract byte execute(RAbstractLogicalVector vector, Object store, int index);
-
-        protected byte doRVector(RLogicalVector vector, byte[] store, int index) {
-            return store[index];
-        }
-
-        @Specialization(guards = "isNativeMirror(store)")
-        protected byte doRVector(RLogicalVector vector, Object store, int index) {
-            return NativeDataAccess.getLogicalNativeMirrorData(store, index);
-        }
-
-        // This accounts for other vector types, like closures
-        @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"}, limit = "3")
-        protected byte doGenericCached(RAbstractLogicalVector vector, Object store, int index,
-                        @Cached("vector.getClass()") Class<? extends RAbstractLogicalVector> cachedClass) {
-            return cachedClass.cast(vector).getDataAt(store, index);
-        }
-
-        @Specialization(guards = {"isGenericVector(vector)"}, replaces = "doGenericCached")
-        protected byte doGeneric(RAbstractLogicalVector vector, Object store, int index) {
-            return vector.getDataAt(store, index);
-        }
-
-        @Fallback
-        protected byte doFallback(RAbstractLogicalVector vector, Object store, int index) {
-            return vector.getDataAt(store, index);
-        }
-
-        protected static boolean isGenericVector(RAbstractLogicalVector vector) {
-            return !(vector instanceof RLogicalVector);
-        }
-    }
-
-    @ImportStatic(NativeDataAccess.class)
-    @SuppressWarnings("unused")
-    public abstract static class Raw extends GetDataAt {
-
-        public static Raw create() {
-            return GetDataAtFactory.RawNodeGen.create();
-        }
-
-        @Override
-        public Object getAsObject(RAbstractVector vector, Object store, int index) {
-            return get((RAbstractRawVector) vector, store, index);
-        }
-
-        public final byte get(RAbstractRawVector vector, Object store, int index) {
-            return execute(vector, store, index);
-        }
-
-        public abstract byte execute(RAbstractRawVector vector, Object store, int index);
-
-        protected byte doRVector(RRawVector vector, byte[] store, int index) {
-            return store[index];
-        }
-
-        @Specialization(guards = "isNativeMirror(store)")
-        protected byte doRVector(RRawVector vector, Object store, int index) {
-            return NativeDataAccess.getRawNativeMirrorData(store, index);
-        }
-
-        // This accounts for other vector types, like closures
-        @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"}, limit = "3")
-        protected byte doGenericCached(RAbstractRawVector vector, Object store, int index,
-                        @Cached("vector.getClass()") Class<? extends RAbstractRawVector> cachedClass) {
-            return cachedClass.cast(vector).getRawDataAt(store, index);
-        }
-
-        @Specialization(guards = {"isGenericVector(vector)"}, replaces = "doGenericCached")
-        protected byte doGeneric(RAbstractRawVector vector, Object store, int index) {
-            return vector.getRawDataAt(store, index);
-        }
-
-        @Fallback
-        protected byte doFallback(RAbstractRawVector vector, Object store, int index) {
-            return vector.getRawDataAt(store, index);
-        }
-
-        protected static boolean isGenericVector(RAbstractRawVector vector) {
-            return !(vector instanceof RRawVector);
-        }
-    }
-
-    @ImportStatic(NativeDataAccess.class)
-    public abstract static class Complex extends GetDataAt {
-
-        public static Complex create() {
-            return GetDataAtFactory.ComplexNodeGen.create();
-        }
-
-        @Override
-        public Object getAsObject(RAbstractVector vector, Object store, int index) {
-            return get((RAbstractComplexVector) vector, store, index);
-        }
-
-        public final RComplex get(RAbstractComplexVector vector, Object store, int index) {
-            return execute(vector, store, index);
-        }
-
-        public abstract RComplex execute(RAbstractComplexVector vector, Object store, int index);
-
-        protected RComplex doRVector(@SuppressWarnings("unused") RComplexVector vector, double[] store, int index) {
-            return RComplex.valueOf(store[index * 2], store[index * 2 + 1]);
-        }
-
-        @SuppressWarnings("unused")
-        @Specialization(guards = "isNativeMirror(store)")
-        protected RComplex doRVector(RComplexVector vector, Object store, int index) {
-            throw RInternalError.unimplemented();
-        }
-
-        @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"}, limit = "3")
-        protected RComplex doGenericCached(RAbstractComplexVector vector, Object store, int index,
-                        @Cached("vector.getClass()") Class<? extends RAbstractComplexVector> cachedClass) {
-            return cachedClass.cast(vector).getDataAt(store, index);
-        }
-
-        @Specialization(guards = {"isGenericVector(vector)"}, replaces = "doGenericCached")
-        protected RComplex doGeneric(RAbstractComplexVector vector, Object store, int index) {
-            return vector.getDataAt(store, index);
-        }
-
-        @Fallback
-        protected RComplex doFallback(RAbstractComplexVector vector, Object store, int index) {
-            return vector.getDataAt(store, index);
-        }
-
-        protected static boolean isGenericVector(RAbstractComplexVector vector) {
-            return !(vector instanceof RComplexVector);
-        }
-    }
-
-    @ImportStatic(NativeDataAccess.class)
-    public abstract static class String extends GetDataAt {
-
-        public static String create() {
-            return GetDataAtFactory.StringNodeGen.create();
-        }
-
-        @Override
-        public Object getAsObject(RAbstractVector vector, Object store, int index) {
-            return get((RAbstractStringVector) vector, store, index);
-        }
-
-        public final java.lang.String get(RAbstractStringVector vector, Object store, int index) {
-            return execute(vector, store, index);
-        }
-
-        public abstract java.lang.String execute(RAbstractStringVector vector, Object store, int index);
-
-        protected java.lang.String doRVector(@SuppressWarnings("unused") RStringVector vector, java.lang.String[] store, int index) {
-            return store[index];
-        }
-
-        @SuppressWarnings("unused")
-        @Specialization(guards = "isNativeMirror(store)")
-        protected java.lang.String doRVector(RStringVector vector, Object store, int index) {
-            throw RInternalError.unimplemented();
-        }
-
-        @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"})
-        protected java.lang.String doGenericCached(RAbstractStringVector vector, Object store, int index,
-                        @Cached("vector.getClass()") Class<? extends RAbstractStringVector> cachedClass) {
-            return cachedClass.cast(vector).getDataAt(store, index);
-        }
-
-        @Specialization(guards = {"isGenericVector(vector)"}, replaces = "doGenericCached")
-        protected java.lang.String doGeneric(RAbstractStringVector vector, Object store, int index) {
-            return vector.getDataAt(store, index);
-        }
-
-        @Fallback
-        protected java.lang.String doFallback(RAbstractStringVector vector, Object store, int index) {
-            return vector.getDataAt(store, index);
-        }
-
-        protected static boolean isGenericVector(RAbstractStringVector vector) {
-            return !(vector instanceof RStringVector);
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataCopy.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataCopy.java
deleted file mode 100644
index ebd66da59d1822a94aeefb09136854dd9f081673..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataCopy.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 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.data.nodes;
-
-import java.util.Arrays;
-
-import com.oracle.truffle.api.dsl.Fallback;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.data.NativeDataAccess;
-import com.oracle.truffle.r.runtime.data.RDoubleVector;
-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.RAbstractStringVector;
-import com.oracle.truffle.r.runtime.data.nodes.GetDataCopyFactory.DoubleNodeGen;
-import com.oracle.truffle.r.runtime.data.nodes.GetDataCopyFactory.StringNodeGen;
-
-/**
- * Nodes contained in this class materialize given vector into an array of corresponding type. The
- * array is always a copy of the original data and can be modified freely.
- *
- * @see RVector#getDataCopy()
- */
-public abstract class GetDataCopy {
-
-    public abstract static class Double extends Node {
-        public abstract double[] execute(RAbstractDoubleVector vector);
-
-        public static Double create() {
-            return DoubleNodeGen.create();
-        }
-
-        @Specialization(guards = "!vec.hasNativeMemoryData()")
-        protected double[] doManagedRVector(RDoubleVector vec) {
-            double[] data = vec.getInternalManagedData();
-            return Arrays.copyOf(data, data.length);
-        }
-
-        @Specialization(guards = "vec.hasNativeMemoryData()")
-        protected double[] doNativeDataRVector(RDoubleVector vec) {
-            return NativeDataAccess.copyDoubleNativeData(vec.getNativeMirror());
-        }
-
-        @Fallback
-        protected double[] doOthers(RAbstractDoubleVector vec) {
-            int len = vec.getLength();
-            double[] result = new double[len];
-            Object store = vec.getInternalStore();
-            for (int i = 0; i < len; i++) {
-                result[i] = vec.getDataAt(store, i);
-            }
-            return result;
-        }
-    }
-
-    public abstract static class String extends Node {
-        public abstract java.lang.String[] execute(RAbstractStringVector vector);
-
-        public static String create() {
-            return StringNodeGen.create();
-        }
-
-        @Specialization(guards = "vec.hasNativeMemoryData()")
-        protected java.lang.String[] doManagedRVector(@SuppressWarnings("unused") RStringVector vec) {
-            throw RInternalError.unimplemented("string vectors backed by native memory");
-        }
-
-        @Specialization(guards = "!vec.hasNativeMemoryData()")
-        protected java.lang.String[] doNativeDataRVector(RStringVector vec) {
-            java.lang.String[] data = vec.getInternalManagedData();
-            return Arrays.copyOf(data, data.length);
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataStore.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataStore.java
deleted file mode 100644
index a9baa4b4177c2b71b86db8754ceb76113a8e924f..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataStore.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 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.data.nodes;
-
-import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.Fallback;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.runtime.data.RVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-
-public abstract class GetDataStore extends Node {
-
-    protected static final int CACHE_LIMIT = 6;
-
-    public static GetDataStore create() {
-        return GetDataStoreNodeGen.create();
-    }
-
-    public abstract Object execute(RAbstractVector vector);
-
-    @Specialization(guards = "vector.hasNativeMemoryData()")
-    protected Object doNative(RVector<?> vector) {
-        return vector.getNativeMirror();
-    }
-
-    @Specialization(guards = {"noNativeMemoryData(vector)", "vector.getClass() == vectorClass"}, limit = "CACHE_LIMIT")
-    protected Object doCached(RAbstractVector vector,
-                    @Cached("vector.getClass()") Class<? extends RAbstractVector> vectorClass,
-                    @Cached("getStoreClass(vector)") Class<?> storeClass) {
-        Object store = vectorClass.cast(vector).getInternalStore();
-        assert store.getClass() == storeClass : "every concrete implementation of RAbstractVector#getInternalStore() must always return a store object of the same type.";
-        return storeClass.cast(store);
-    }
-
-    @Specialization(replaces = "doCached", guards = {"noNativeMemoryData(vector)"})
-    protected Object doGeneric(RAbstractVector vector) {
-        Object store = vector.getInternalStore();
-        return store;
-    }
-
-    @Fallback
-    protected Object doFallback(RAbstractVector vector) {
-        if (noNativeMemoryData(vector)) {
-            RVector<?> vec = (RVector<?>) vector;
-            if (vec.hasNativeMemoryData()) {
-                return vec.getNativeMirror();
-            }
-        }
-        return vector.getInternalStore();
-    }
-
-    protected static boolean noNativeMemoryData(RAbstractVector vector) {
-        return !(vector instanceof RVector<?>) || !((RVector<?>) vector).hasNativeMemoryData();
-    }
-
-    protected static Class<?> getStoreClass(RAbstractVector vector) {
-        return vector.getInternalStore().getClass();
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/PrimitiveVectorAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/PrimitiveVectorAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e92d4037552dfaa038d4534f47e474f56d3f10b
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/PrimitiveVectorAccess.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 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.data.nodes;
+
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromDoubleAccess;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromIntAccess;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromLogicalAccess;
+import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromStringAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromDoubleAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromIntAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromLogicalAccess;
+import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromStringAccess;
+
+public abstract class PrimitiveVectorAccess {
+
+    public static VectorAccess create(Object value) {
+        if (value instanceof Integer) {
+            return new FastPathFromIntAccess(value) {
+                @Override
+                protected int getInt(Object store, int index) {
+                    return (Integer) store;
+                }
+            };
+        } else if (value instanceof Double) {
+            return new FastPathFromDoubleAccess(value) {
+                @Override
+                protected double getDouble(Object store, int index) {
+                    return (Double) store;
+                }
+            };
+        } else if (value instanceof Byte) {
+            return new FastPathFromLogicalAccess(value) {
+                @Override
+                protected byte getLogical(Object store, int index) {
+                    return (Byte) store;
+                }
+            };
+        } else if (value instanceof String) {
+            return new FastPathFromStringAccess(value) {
+                @Override
+                protected String getString(Object store, int index) {
+                    return (String) store;
+                }
+            };
+        } else if (value instanceof RNull) {
+            return new FastPathFromListAccess(value) {
+                @Override
+                public RType getType() {
+                    return RType.Null;
+                }
+
+                @Override
+                protected int getLength(Object vector) {
+                    return 0;
+                }
+
+                @Override
+                protected Object getListElement(Object store, int index) {
+                    throw RInternalError.shouldNotReachHere();
+                }
+            };
+        } else {
+            return null;
+        }
+    }
+
+    private static final SlowPathFromIntAccess SLOW_PATH_INT = new SlowPathFromIntAccess() {
+        @Override
+        protected int getInt(Object store, int index) {
+            return (Integer) store;
+        }
+    };
+    private static final SlowPathFromDoubleAccess SLOW_PATH_DOUBLE = new SlowPathFromDoubleAccess() {
+        @Override
+        protected double getDouble(Object store, int index) {
+            return (Double) store;
+        }
+    };
+    private static final SlowPathFromLogicalAccess SLOW_PATH_LOGICAL = new SlowPathFromLogicalAccess() {
+        @Override
+        protected byte getLogical(Object store, int index) {
+            return (Byte) store;
+        }
+    };
+    private static final SlowPathFromStringAccess SLOW_PATH_STRING = new SlowPathFromStringAccess() {
+        @Override
+        protected String getString(Object store, int index) {
+            return (String) store;
+        }
+    };
+    private static final SlowPathFromListAccess SLOW_PATH_NULL = new SlowPathFromListAccess() {
+        @Override
+        public RType getType() {
+            return RType.Null;
+        }
+
+        @Override
+        protected int getLength(Object vector) {
+            return 0;
+        }
+
+        @Override
+        protected Object getListElement(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+    };
+
+    public static VectorAccess createSlowPath(Object value) {
+        if (value instanceof Integer) {
+            return SLOW_PATH_INT;
+        } else if (value instanceof Double) {
+            return SLOW_PATH_DOUBLE;
+        } else if (value instanceof Byte) {
+            return SLOW_PATH_LOGICAL;
+        } else if (value instanceof String) {
+            return SLOW_PATH_STRING;
+        } else if (value instanceof RNull) {
+            return SLOW_PATH_NULL;
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/ReadAccessor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/ReadAccessor.java
deleted file mode 100644
index 997488a9dec3fc7235a0c4f3da6e1e13c101fa1a..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/ReadAccessor.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (c) 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.data.nodes;
-
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-
-/**
- * Convenience classes that wraps {@link VectorReadAccess} node, the vector and its store so that
- * those data can be passed around as a single paramter.
- */
-public abstract class ReadAccessor {
-    private ReadAccessor() {
-    }
-
-    public static final class Int extends ReadAccessor {
-        private final RAbstractIntVector vector;
-        private final VectorReadAccess.Int readAccess;
-        private final Object store;
-
-        public Int(RAbstractIntVector vector, VectorReadAccess.Int readAccess) {
-            this.vector = vector;
-            this.readAccess = readAccess;
-            store = readAccess.getDataStore(vector);
-        }
-
-        public int getDataAt(int index) {
-            return readAccess.getDataAt(vector, store, index);
-        }
-
-        public Object getStore() {
-            return store;
-        }
-
-        public RAbstractIntVector getVector() {
-            return vector;
-        }
-    }
-
-    public static final class Double extends ReadAccessor {
-        private final RAbstractDoubleVector vector;
-        private final VectorReadAccess.Double readAccess;
-        private final Object store;
-
-        public Double(RAbstractDoubleVector vector, VectorReadAccess.Double readAccess) {
-            this.vector = vector;
-            this.readAccess = readAccess;
-            store = readAccess.getDataStore(vector);
-        }
-
-        public double getDataAt(int index) {
-            return readAccess.getDataAt(vector, store, index);
-        }
-
-        public Object getStore() {
-            return store;
-        }
-
-        public RAbstractDoubleVector getVector() {
-            return vector;
-        }
-    }
-
-    public static final class Logical extends ReadAccessor {
-        private final RAbstractLogicalVector vector;
-        private final VectorReadAccess.Logical readAccess;
-        private final Object store;
-
-        public Logical(RAbstractLogicalVector vector, VectorReadAccess.Logical readAccess) {
-            this.vector = vector;
-            this.readAccess = readAccess;
-            store = readAccess.getDataStore(vector);
-        }
-
-        public byte getDataAt(int index) {
-            return readAccess.getDataAt(vector, store, index);
-        }
-
-        public Object getStore() {
-            return store;
-        }
-
-        public RAbstractLogicalVector getVector() {
-            return vector;
-        }
-    }
-
-    public static final class Raw extends ReadAccessor {
-        private final RAbstractRawVector vector;
-        private final VectorReadAccess.Raw readAccess;
-        private final Object store;
-
-        public Raw(RAbstractRawVector vector, VectorReadAccess.Raw readAccess) {
-            this.vector = vector;
-            this.readAccess = readAccess;
-            store = readAccess.getDataStore(vector);
-        }
-
-        public byte getDataAt(int index) {
-            return readAccess.getDataAt(vector, store, index);
-        }
-
-        public Object getStore() {
-            return store;
-        }
-
-        public RAbstractRawVector getVector() {
-            return vector;
-        }
-    }
-
-    public static final class Complex extends ReadAccessor {
-        private final RAbstractComplexVector vector;
-        private final VectorReadAccess.Complex readAccess;
-        private final Object store;
-
-        public Complex(RAbstractComplexVector vector, VectorReadAccess.Complex readAccess) {
-            this.vector = vector;
-            this.readAccess = readAccess;
-            store = readAccess.getDataStore(vector);
-        }
-
-        public RComplex getDataAt(int index) {
-            return readAccess.getDataAt(vector, store, index);
-        }
-
-        public Object getStore() {
-            return store;
-        }
-
-        public RAbstractComplexVector getVector() {
-            return vector;
-        }
-    }
-
-    public static final class String extends ReadAccessor {
-        private final RAbstractStringVector vector;
-        private final VectorReadAccess.String readAccess;
-        private final Object store;
-
-        public String(RAbstractStringVector vector, VectorReadAccess.String readAccess) {
-            this.vector = vector;
-            this.readAccess = readAccess;
-            store = readAccess.getDataStore(vector);
-        }
-
-        public java.lang.String getDataAt(int index) {
-            return readAccess.getDataAt(vector, store, index);
-        }
-
-        public Object getStore() {
-            return store;
-        }
-
-        public RAbstractStringVector getVector() {
-            return vector;
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SetDataAt.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SetDataAt.java
deleted file mode 100644
index 297b29b932ac9b31d16537c4dc78d3c7f2a9d1d8..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SetDataAt.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (c) 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.data.nodes;
-
-import com.oracle.truffle.api.dsl.ImportStatic;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.data.NativeDataAccess;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
-import com.oracle.truffle.r.runtime.data.RDoubleVector;
-import com.oracle.truffle.r.runtime.data.RIntVector;
-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;
-
-public abstract class SetDataAt extends Node {
-
-    public abstract void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value);
-
-    @ImportStatic(NativeDataAccess.class)
-    @SuppressWarnings("unused")
-    public abstract static class Double extends SetDataAt {
-
-        @Override
-        public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) {
-            setDataAt((RDoubleVector) vector, store, index, (double) value);
-        }
-
-        public final void setDataAt(RDoubleVector vector, Object store, int index, double value) {
-            execute(vector, store, index, value);
-        }
-
-        public abstract void execute(RDoubleVector vector, Object store, int index, double value);
-
-        @Specialization(guards = "!isNativeMirror(store)")
-        protected void doManagedRVector(RDoubleVector vec, Object store, int index, double value) {
-            ((double[]) store)[index] = value;
-        }
-
-        @Specialization(guards = "isNativeMirror(store)")
-        protected void doNativeDataRVector(RDoubleVector vec, Object store, int index, double value) {
-            NativeDataAccess.setNativeMirrorData(store, index, value);
-        }
-
-        public static Double create() {
-            return SetDataAtFactory.DoubleNodeGen.create();
-        }
-    }
-
-    @ImportStatic(NativeDataAccess.class)
-    @SuppressWarnings("unused")
-    public abstract static class Int extends SetDataAt {
-
-        @Override
-        public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) {
-            setDataAt((RIntVector) vector, store, index, (int) value);
-        }
-
-        public final void setDataAt(RIntVector vector, Object store, int index, int value) {
-            execute(vector, store, index, value);
-        }
-
-        public abstract void execute(RIntVector vector, Object store, int index, int value);
-
-        @Specialization(guards = "!isNativeMirror(store)")
-        protected void doManagedRVector(RIntVector vec, Object store, int index, int value) {
-            ((int[]) store)[index] = value;
-        }
-
-        @Specialization(guards = "isNativeMirror(store)")
-        protected void doNativeDataRVector(RIntVector vec, Object store, int index, int value) {
-            NativeDataAccess.setNativeMirrorData(store, index, value);
-        }
-
-        public static Int create() {
-            return SetDataAtFactory.IntNodeGen.create();
-        }
-    }
-
-    @ImportStatic(NativeDataAccess.class)
-    @SuppressWarnings("unused")
-    public abstract static class Logical extends SetDataAt {
-
-        @Override
-        public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) {
-            setDataAt((RLogicalVector) vector, store, index, (byte) value);
-        }
-
-        public final void setDataAt(RLogicalVector vector, Object store, int index, byte value) {
-            execute(vector, store, index, value);
-        }
-
-        public abstract void execute(RLogicalVector vector, Object store, int index, byte value);
-
-        @Specialization(guards = "!isNativeMirror(store)")
-        protected void doManagedRVector(RLogicalVector vec, Object store, int index, byte value) {
-            ((byte[]) store)[index] = value;
-        }
-
-        @Specialization(guards = "isNativeMirror(store)")
-        protected void doNativeDataRVector(RLogicalVector vec, Object store, int index, byte value) {
-            NativeDataAccess.setNativeMirrorData(store, index, value);
-        }
-
-        public static Logical create() {
-            return SetDataAtFactory.LogicalNodeGen.create();
-        }
-    }
-
-    @ImportStatic(NativeDataAccess.class)
-    @SuppressWarnings("unused")
-    public abstract static class Raw extends SetDataAt {
-
-        @Override
-        public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) {
-            setDataAt((RRawVector) vector, store, index, (byte) value);
-        }
-
-        public final void setDataAt(RRawVector vector, Object store, int index, byte value) {
-            execute(vector, store, index, value);
-        }
-
-        public abstract void execute(RRawVector vector, Object store, int index, byte value);
-
-        @Specialization(guards = "!isNativeMirror(store)")
-        protected void doManagedRVector(RRawVector vec, Object store, int index, byte value) {
-            ((byte[]) store)[index] = value;
-        }
-
-        @Specialization(guards = "isNativeMirror(store)")
-        protected void doNativeDataRVector(RRawVector vec, Object store, int index, byte value) {
-            NativeDataAccess.setNativeMirrorData(store, index, value);
-        }
-
-        public static Raw create() {
-            return SetDataAtFactory.RawNodeGen.create();
-        }
-    }
-
-    @ImportStatic(NativeDataAccess.class)
-    @SuppressWarnings("unused")
-    public abstract static class Complex extends SetDataAt {
-
-        @Override
-        public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) {
-            setDataAt((RComplexVector) vector, store, index, (RComplex) value);
-        }
-
-        public final void setDataAt(RComplexVector vector, Object store, int index, RComplex value) {
-            execute(vector, store, index, value);
-        }
-
-        public abstract void execute(RComplexVector vector, Object store, int index, RComplex value);
-
-        @Specialization(guards = "!isNativeMirror(storeObj)")
-        protected void doManagedRVector(RComplexVector vec, Object storeObj, int index, RComplex value) {
-            double[] store = (double[]) storeObj;
-            store[index * 2] = value.getRealPart();
-            store[index * 2 + 1] = value.getImaginaryPart();
-        }
-
-        @Specialization(guards = "isNativeMirror(store)")
-        protected void doNativeDataRVector(RComplexVector vec, Object store, int index, RComplex value) {
-            throw RInternalError.unimplemented();
-        }
-
-        public static Complex create() {
-            return SetDataAtFactory.ComplexNodeGen.create();
-        }
-    }
-
-    @ImportStatic(NativeDataAccess.class)
-    @SuppressWarnings("unused")
-    public abstract static class String extends SetDataAt {
-
-        @Override
-        public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) {
-            setDataAt((RStringVector) vector, store, index, (java.lang.String) value);
-        }
-
-        public final void setDataAt(RStringVector vector, Object store, int index, java.lang.String value) {
-            execute(vector, store, index, value);
-        }
-
-        public abstract void execute(RStringVector vector, Object store, int index, java.lang.String value);
-
-        @Specialization(guards = "!isNativeMirror(store)")
-        protected void doManagedRVector(RStringVector vec, Object store, int index, java.lang.String value) {
-            ((java.lang.String[]) store)[index] = value;
-        }
-
-        @Specialization(guards = "isNativeMirror(store)")
-        protected void doNativeDataRVector(RStringVector vec, Object store, int index, java.lang.String value) {
-            throw RInternalError.unimplemented();
-        }
-
-        public static String create() {
-            return SetDataAtFactory.StringNodeGen.create();
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SlowPathVectorAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SlowPathVectorAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..5aeab7e21738e334fe5fdf795fc6e12b7ad5f227
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SlowPathVectorAccess.java
@@ -0,0 +1,606 @@
+/*
+ * Copyright (c) 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.data.nodes;
+
+import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RComplex;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+
+/**
+ * Base classes for {@link VectorAccess} implementations that are used on the slow path, i.e., that
+ * are created as singletons. For implementation reasons, most of this code is mirrored in
+ * {@link FastPathVectorAccess}, so that any changes need to be mirrored there.
+ */
+public abstract class SlowPathVectorAccess extends VectorAccess {
+
+    protected boolean naReported; // TODO: move this into the iterator
+
+    protected SlowPathVectorAccess() {
+        // VectorAccess.supports has an assertion that relies on this being Object.class
+        super(Object.class, true);
+    }
+
+    @Override
+    protected final Object getStore(RAbstractContainer vector) {
+        return vector;
+    }
+
+    protected final void warning(RError.Message message) {
+        CompilerAsserts.neverPartOfCompilation();
+        if (!naReported) {
+            RError.warning(RError.SHOW_CALLER, message);
+            naReported = true;
+        }
+    }
+
+    public abstract static class SlowPathFromIntAccess extends SlowPathVectorAccess {
+
+        @Override
+        public final RType getType() {
+            return RType.Integer;
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RRuntime.DOUBLE_NA : RRuntime.int2doubleNoCheck(value);
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            int value = getInt(store, index);
+            byte result = (byte) value;
+            if ((result & 0xff) != value) {
+                warning(Message.OUT_OF_RANGE);
+                return 0;
+            }
+            return result;
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.int2logicalNoCheck(value);
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RComplex.createNA() : RRuntime.int2complexNoCheck(value);
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value;
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0;
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            int value = getInt(store, index);
+            return na.check(value) ? RRuntime.STRING_NA : RRuntime.intToStringNoCheck(value);
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return getInt(store, index);
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setInt(store, index, sourceAccess.getInt(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setInt(store, index, sourceAccess.getInt(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            setInt(store, index, RRuntime.INT_NA);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.check(getInt(store, index));
+        }
+    }
+
+    public abstract static class SlowPathFromDoubleAccess extends SlowPathVectorAccess {
+
+        @Override
+        public final RType getType() {
+            return RType.Double;
+        }
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            double value = getDouble(store, index);
+            if (Double.isNaN(value)) {
+                na.enable(true);
+                return RRuntime.INT_NA;
+            }
+            if (value > Integer.MAX_VALUE || value <= Integer.MIN_VALUE) {
+                na.enable(true);
+                warning(Message.NA_INTRODUCED_COERCION_INT);
+                return RRuntime.INT_NA;
+            }
+            return (int) value;
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            int value = (int) getDouble(store, index);
+            byte result = (byte) value;
+            if ((result & 0xff) != value) {
+                warning(Message.OUT_OF_RANGE);
+                return 0;
+            }
+            return result;
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            double value = getDouble(store, index);
+            return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.double2logicalNoCheck(value);
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            double value = getDouble(store, index);
+            return na.check(value) ? RComplex.createNA() : RRuntime.double2complexNoCheck(value);
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            double value = getDouble(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value;
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            double value = getDouble(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0;
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            double value = getDouble(store, index);
+            return na.check(value) ? RRuntime.STRING_NA : RContext.getRRuntimeASTAccess().encodeDouble(value);
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return getDouble(store, index);
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setDouble(store, index, sourceAccess.getDouble(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setDouble(store, index, sourceAccess.getDouble(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            setDouble(store, index, RRuntime.DOUBLE_NA);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.check(getDouble(store, index));
+        }
+    }
+
+    public abstract static class SlowPathFromLogicalAccess extends SlowPathVectorAccess {
+
+        @Override
+        public final RType getType() {
+            return RType.Logical;
+        }
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RRuntime.INT_NA : RRuntime.logical2intNoCheck(value);
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RRuntime.DOUBLE_NA : RRuntime.logical2doubleNoCheck(value);
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            byte value = getLogical(store, index);
+            if (na.check(value)) {
+                warning(Message.OUT_OF_RANGE);
+                return 0;
+            }
+            return value;
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RComplex.createNA() : RRuntime.logical2complexNoCheck(value);
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value;
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0;
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            byte value = getLogical(store, index);
+            return na.check(value) ? RRuntime.STRING_NA : RRuntime.logicalToStringNoCheck(value);
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return getLogical(store, index);
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setLogical(store, index, sourceAccess.getLogical(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setLogical(store, index, sourceAccess.getLogical(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            setLogical(store, index, RRuntime.LOGICAL_NA);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.check(getLogical(store, index));
+        }
+    }
+
+    public abstract static class SlowPathFromRawAccess extends SlowPathVectorAccess {
+
+        @Override
+        public final RType getType() {
+            return RType.Raw;
+        }
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            return getRaw(store, index) & 0xff;
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            return getRaw(store, index) & 0xff;
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            return getRaw(store, index) == 0 ? RRuntime.LOGICAL_FALSE : RRuntime.LOGICAL_TRUE;
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            return RComplex.valueOf(getRaw(store, index) & 0xff, 0);
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            return getRaw(store, index) & 0xff;
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            return 0;
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            return RRuntime.rawToHexString(getRaw(store, index));
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return getRaw(store, index);
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setRaw(store, index, sourceAccess.getRaw(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setRaw(store, index, sourceAccess.getRaw(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            /*
+             * There is no raw NA, but places that write NA for other types usually write 0 for raw.
+             */
+            setRaw(store, index, (byte) 0);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return false;
+        }
+    }
+
+    public abstract static class SlowPathFromComplexAccess extends SlowPathVectorAccess {
+
+        @Override
+        public final RType getType() {
+            return RType.Complex;
+        }
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            double value = getComplexR(store, index);
+            if (Double.isNaN(value)) {
+                na.enable(true);
+                return RRuntime.INT_NA;
+            }
+            if (value > Integer.MAX_VALUE || value <= Integer.MIN_VALUE) {
+                na.enable(true);
+                warning(Message.NA_INTRODUCED_COERCION_INT);
+                return RRuntime.INT_NA;
+            }
+            if (getComplexI(store, index) != 0) {
+                warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
+            }
+            return (int) value;
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            double value = getComplexR(store, index);
+            if (Double.isNaN(value)) {
+                na.enable(true);
+                return RRuntime.DOUBLE_NA;
+            }
+            if (getComplexI(store, index) != 0) {
+                warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
+            }
+            return value;
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            double value = getComplexR(store, index);
+            if (Double.isNaN(value) || value < 0 || value >= 256) {
+                warning(Message.OUT_OF_RANGE);
+                return 0;
+            }
+            if (getComplexI(store, index) != 0) {
+                warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
+            }
+            return (byte) value;
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            RComplex value = getComplex(store, index);
+            return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.complex2logicalNoCheck(value);
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            RComplex value = getComplex(store, index);
+            return na.check(value) ? RRuntime.STRING_NA : RContext.getRRuntimeASTAccess().encodeComplex(value);
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return getComplex(store, index);
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setComplex(store, index, sourceAccess.getComplexR(sourceIter), sourceAccess.getComplexI(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setComplex(store, index, sourceAccess.getComplexR(sourceIter, sourceIndex), sourceAccess.getComplexI(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            setComplex(store, index, RRuntime.COMPLEX_NA_REAL_PART, RRuntime.COMPLEX_NA_IMAGINARY_PART);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.check(getComplexR(store, index), getComplexI(store, index));
+        }
+    }
+
+    public abstract static class SlowPathFromStringAccess extends SlowPathVectorAccess {
+
+        @Override
+        public final RType getType() {
+            return RType.Character;
+        }
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            return na.convertStringToInt(getString(store, index));
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            return na.convertStringToDouble(getString(store, index));
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            int value = na.convertStringToInt(getString(store, index));
+            return value >= 0 && value <= 255 ? (byte) value : 0;
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            return na.convertStringToLogical(getString(store, index));
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            return na.convertStringToComplex(getString(store, index));
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            return na.convertStringToComplex(getString(store, index)).getRealPart();
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            return na.convertStringToComplex(getString(store, index)).getImaginaryPart();
+        }
+
+        @Override
+        protected final Object getListElement(Object store, int index) {
+            return getString(store, index);
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setString(store, index, sourceAccess.getString(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setString(store, index, sourceAccess.getString(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            setString(store, index, RRuntime.STRING_NA);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.check(getString(store, index));
+        }
+    }
+
+    public abstract static class SlowPathFromListAccess extends SlowPathVectorAccess {
+
+        @Override
+        protected final int getInt(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final double getDouble(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final byte getRaw(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final byte getLogical(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final RComplex getComplex(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final double getComplexR(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final double getComplexI(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final String getString(Object store, int index) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+            setListElement(store, index, sourceAccess.getListElement(sourceIter));
+        }
+
+        @Override
+        protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+            setListElement(store, index, sourceAccess.getListElement(sourceIter, sourceIndex));
+        }
+
+        @Override
+        protected void setNA(Object store, int index) {
+            /*
+             * There is no list NA, but places that write NA for other types usually write NULL for
+             * lists.
+             */
+            setListElement(store, index, RNull.instance);
+        }
+
+        @Override
+        protected boolean isNA(Object store, int index) {
+            return na.checkListElement(getListElement(store, index));
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..e64b83486777349043f84c6bcc75cc60c2470f8b
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccess.java
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 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.data.nodes;
+
+import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.RComplex;
+import com.oracle.truffle.r.runtime.data.RComplexVector;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RExpression;
+import com.oracle.truffle.r.runtime.data.RIntVector;
+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.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
+import com.oracle.truffle.r.runtime.ops.na.NACheck;
+
+/**
+ * This class is the main access point for reading and writing vectors. Every implementation of
+ * {@link RAbstractContainer} needs to be able to supply an instance of {@link VectorAccess} via the
+ * {@link RAbstractContainer#access()} function. These instances can be asked, via the
+ * {@link #supports(Object)} function, whether they support a specific object.<br/>
+ *
+ * The usual interaction with vectors looks like this:
+ * <ul>
+ * <li>{@link Specialization} {@code foo} has a vector as a parameter, and adds a {@link Cached}
+ * parameter of type {@link VectorAccess} that is initialized by {@link RAbstractContainer#access()}
+ * .</li>
+ * <li>The specialization guards with {@code access.supports(vector)} so that it only handles cases
+ * that it actually supports.</li>
+ * <li>try-with-resources is used to open an access (either sequential or random) on the vector:
+ * <br/>
+ * {@code try (SequentialIterator iter = access.access(vector))...}</li>
+ * <li>Inside the try-with-resources, individual elements can be accessed using the
+ * {@link VectorAccess#getInt(SequentialIterator)}, etc. functions</li>
+ * <li>A fallback specialization, which {@link Specialization#replaces()} the original one and
+ * creates the {@link VectorAccess} via {@link RAbstractContainer#slowPathAccess()}, calls the first
+ * specialization with the slow path vector access.</li>
+ * </ul>
+ */
+public abstract class VectorAccess extends Node {
+
+    public final NACheck na = NACheck.create();
+
+    protected final Class<?> clazz;
+    protected final boolean hasStore;
+
+    public VectorAccess(Class<?> clazz, boolean hasStore) {
+        CompilerAsserts.neverPartOfCompilation();
+        this.clazz = clazz;
+        this.hasStore = hasStore;
+    }
+
+    public static final class SequentialIterator implements AutoCloseable {
+
+        protected final Object store; // internal store, native mirror or vector
+        protected final int length;
+        protected int index;
+
+        private SequentialIterator(Object store, int length) {
+            this.store = store;
+            this.length = length;
+            this.index = -1;
+        }
+
+        @Override
+        public void close() {
+            // nothing to do
+        }
+
+        public int getIndex() {
+            return index;
+        }
+
+        Object getStore() {
+            return store;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("<iterator %d of %d, %s>", index, length, store == null ? "null" : store.getClass().getSimpleName());
+        }
+    }
+
+    public static final class RandomIterator implements AutoCloseable {
+
+        protected final Object store; // internal store, native mirror or vector
+        protected final int length;
+
+        private RandomIterator(Object store, int length) {
+            this.store = store;
+            this.length = length;
+        }
+
+        @Override
+        public void close() {
+            // nothing to do
+        }
+
+        Object getStore() {
+            return store;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("<random access %s>", store == null ? "null" : store.getClass().getSimpleName());
+        }
+    }
+
+    protected abstract int getInt(Object store, int index);
+
+    protected abstract double getDouble(Object store, int index);
+
+    protected abstract RComplex getComplex(Object store, int index);
+
+    protected abstract double getComplexR(Object store, int index);
+
+    protected abstract double getComplexI(Object store, int index);
+
+    protected abstract byte getRaw(Object store, int index);
+
+    protected abstract byte getLogical(Object store, int index);
+
+    protected abstract String getString(Object store, int index);
+
+    protected abstract Object getListElement(Object store, int index);
+
+    @SuppressWarnings("unused")
+    protected void setInt(Object store, int index, int value) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @SuppressWarnings("unused")
+    protected void setDouble(Object store, int index, double value) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @SuppressWarnings("unused")
+    protected void setComplex(Object store, int index, double real, double imaginary) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @SuppressWarnings("unused")
+    protected void setRaw(Object store, int index, byte value) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @SuppressWarnings("unused")
+    protected void setLogical(Object store, int index, byte value) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @SuppressWarnings("unused")
+    protected void setString(Object store, int index, String value) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @SuppressWarnings("unused")
+    protected void setListElement(Object store, int index, Object value) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @SuppressWarnings("unused")
+    protected void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @SuppressWarnings("unused")
+    protected void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @SuppressWarnings("unused")
+    protected void setNA(Object store, int index) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    protected abstract boolean isNA(Object store, int index);
+
+    public final Object cast(Object value) {
+        return clazz.cast(value);
+    }
+
+    public final boolean supports(Object value) {
+        assert clazz != Object.class : "cannot call 'supports' on slow path vector access";
+        if (value.getClass() != clazz) {
+            return false;
+        }
+        Object castVector = cast(value);
+        return !(castVector instanceof RAbstractContainer) || (((RAbstractContainer) castVector).getInternalStore() != null) == hasStore;
+    }
+
+    protected abstract Object getStore(RAbstractContainer vector);
+
+    protected int getLength(RAbstractContainer vector) {
+        return vector.getLength();
+    }
+
+    protected int getLength(@SuppressWarnings("unused") Object vector) {
+        return 1;
+    }
+
+    /**
+     * Creates a new iterator that will point to before the beginning of the vector, so that
+     * {@link #next(SequentialIterator)} will move it to the first element.
+     */
+    public final SequentialIterator access(Object vector) {
+        Object castVector = cast(vector);
+        if (castVector instanceof RAbstractContainer) {
+            RAbstractContainer container = (RAbstractContainer) castVector;
+            int length = getLength(container);
+            RBaseNode.reportWork(this, length);
+            na.enable(container);
+            return new SequentialIterator(getStore(container), length);
+        } else {
+            na.enable(true);
+            return new SequentialIterator(castVector, getLength(castVector));
+        }
+    }
+
+    @SuppressWarnings("static-method")
+    public final boolean next(SequentialIterator iter) {
+        return ++iter.index < iter.length;
+    }
+
+    @SuppressWarnings("static-method")
+    public final void nextWithWrap(SequentialIterator iter) {
+        assert iter.length > 0;
+        if (++iter.index >= iter.length) {
+            iter.index = 0;
+        }
+    }
+
+    @SuppressWarnings("static-method")
+    public final int getLength(SequentialIterator iter) {
+        return iter.length;
+    }
+
+    /**
+     * Resets the iterator to point to before the first element, calling
+     * {@link #next(SequentialIterator)} will move it to the first element.
+     */
+    @SuppressWarnings("static-method")
+    public final void reset(SequentialIterator iter) {
+        iter.index = -1;
+    }
+
+    public abstract RType getType();
+
+    public final int getInt(SequentialIterator iter) {
+        return getInt(iter.store, iter.index);
+    }
+
+    public final double getDouble(SequentialIterator iter) {
+        return getDouble(iter.store, iter.index);
+    }
+
+    public final RComplex getComplex(SequentialIterator iter) {
+        return getComplex(iter.store, iter.index);
+    }
+
+    public final double getComplexR(SequentialIterator iter) {
+        return getComplexR(iter.store, iter.index);
+    }
+
+    public final double getComplexI(SequentialIterator iter) {
+        return getComplexI(iter.store, iter.index);
+    }
+
+    public final byte getRaw(SequentialIterator iter) {
+        return getRaw(iter.store, iter.index);
+    }
+
+    public final byte getLogical(SequentialIterator iter) {
+        return getLogical(iter.store, iter.index);
+    }
+
+    public final String getString(SequentialIterator iter) {
+        return getString(iter.store, iter.index);
+    }
+
+    public final Object getListElement(SequentialIterator iter) {
+        return getListElement(iter.store, iter.index);
+    }
+
+    public final void setInt(SequentialIterator iter, int value) {
+        setInt(iter.store, iter.index, value);
+    }
+
+    public final void setDouble(SequentialIterator iter, double value) {
+        setDouble(iter.store, iter.index, value);
+    }
+
+    public final void setComplex(SequentialIterator iter, double real, double imaginary) {
+        setComplex(iter.store, iter.index, real, imaginary);
+    }
+
+    public final void setRaw(SequentialIterator iter, byte value) {
+        setRaw(iter.store, iter.index, value);
+    }
+
+    public final void setLogical(SequentialIterator iter, byte value) {
+        setLogical(iter.store, iter.index, value);
+    }
+
+    public final void setString(SequentialIterator iter, String value) {
+        setString(iter.store, iter.index, value);
+    }
+
+    public final void setListElement(SequentialIterator iter, Object value) {
+        setListElement(iter.store, iter.index, value);
+    }
+
+    public final void setFromSameType(SequentialIterator iter, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+        setFromSameType(iter.store, iter.index, sourceAccess, sourceIter);
+    }
+
+    public final void setFromSameType(SequentialIterator iter, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+        setFromSameType(iter.store, iter.index, sourceAccess, sourceIter, sourceIndex);
+    }
+
+    public final void setNA(SequentialIterator iter) {
+        setNA(iter.store, iter.index);
+    }
+
+    public final boolean isNA(SequentialIterator iter) {
+        return isNA(iter.store, iter.index);
+    }
+
+    /**
+     * Creates a new random access on the given vector.
+     */
+    public final RandomIterator randomAccess(RAbstractContainer vector) {
+        Object castVector = cast(vector);
+        if (castVector instanceof RAbstractContainer) {
+            RAbstractContainer container = (RAbstractContainer) castVector;
+            int length = getLength(container);
+            RBaseNode.reportWork(this, length);
+            na.enable(container);
+            return new RandomIterator(getStore(container), length);
+        } else {
+            na.enable(true);
+            return new RandomIterator(castVector, getLength(castVector));
+        }
+    }
+
+    @SuppressWarnings("static-method")
+    public final int getLength(RandomIterator iter) {
+        return iter.length;
+    }
+
+    public final int getInt(RandomIterator iter, int index) {
+        return getInt(iter.store, index);
+    }
+
+    public final double getDouble(RandomIterator iter, int index) {
+        return getDouble(iter.store, index);
+    }
+
+    public final RComplex getComplex(RandomIterator iter, int index) {
+        return getComplex(iter.store, index);
+    }
+
+    public final double getComplexR(RandomIterator iter, int index) {
+        return getComplexR(iter.store, index);
+    }
+
+    public final double getComplexI(RandomIterator iter, int index) {
+        return getComplexI(iter.store, index);
+    }
+
+    public final byte getRaw(RandomIterator iter, int index) {
+        return getRaw(iter.store, index);
+    }
+
+    public final byte getLogical(RandomIterator iter, int index) {
+        return getLogical(iter.store, index);
+    }
+
+    public final String getString(RandomIterator iter, int index) {
+        return getString(iter.store, index);
+    }
+
+    public final Object getListElement(RandomIterator iter, int index) {
+        return getListElement(iter.store, index);
+    }
+
+    public final void setInt(RandomIterator iter, int index, int value) {
+        setInt(iter.store, index, value);
+    }
+
+    public final void setDouble(RandomIterator iter, int index, double value) {
+        setDouble(iter.store, index, value);
+    }
+
+    public final void setComplex(RandomIterator iter, int index, double real, double imaginary) {
+        setComplex(iter.store, index, real, imaginary);
+    }
+
+    public final void setRaw(RandomIterator iter, int index, byte value) {
+        setRaw(iter.store, index, value);
+    }
+
+    public final void setLogical(RandomIterator iter, int index, byte value) {
+        setLogical(iter.store, index, value);
+    }
+
+    public final void setString(RandomIterator iter, int index, String value) {
+        setString(iter.store, index, value);
+    }
+
+    public final void setListElement(RandomIterator iter, int index, Object value) {
+        setListElement(iter.store, index, value);
+    }
+
+    public final void setFromSameType(RandomIterator iter, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) {
+        setFromSameType(iter.store, index, sourceAccess, sourceIter);
+    }
+
+    public final void setFromSameType(RandomIterator iter, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) {
+        setFromSameType(iter.store, index, sourceAccess, sourceIter, sourceIndex);
+    }
+
+    public final void setNA(RandomIterator iter, int index) {
+        setNA(iter.store, index);
+    }
+
+    public final boolean isNA(RandomIterator iter, int index) {
+        return isNA(iter.store, index);
+    }
+
+    /**
+     * Placed in a separate class to avoid circular dependencies during class initialization.
+     */
+    private static final class Lazy {
+        private static final RStringVector TEMPLATE_CHARACTER = RDataFactory.getPermanent().createStringVector(4);
+        private static final RComplexVector TEMPLATE_COMPLEX = RDataFactory.getPermanent().createComplexVector(4);
+        private static final RDoubleVector TEMPLATE_DOUBLE = RDataFactory.getPermanent().createDoubleVector(4);
+        private static final RIntVector TEMPLATE_INTEGER = RDataFactory.getPermanent().createIntVector(4);
+        private static final RList TEMPLATE_LIST = RDataFactory.getPermanent().createList(4);
+        private static final RExpression TEMPLATE_EXPRESSION = RDataFactory.createExpression(4);
+        private static final RLogicalVector TEMPLATE_LOGICAL = RDataFactory.getPermanent().createLogicalVector(4);
+        private static final RRawVector TEMPLATE_RAW = RDataFactory.getPermanent().createRawVector(4);
+    }
+
+    public static VectorAccess createNew(RType type) {
+        CompilerAsserts.neverPartOfCompilation();
+        switch (type) {
+            case Character:
+                return Lazy.TEMPLATE_CHARACTER.access();
+            case Complex:
+                return Lazy.TEMPLATE_COMPLEX.access();
+            case Double:
+                return Lazy.TEMPLATE_DOUBLE.access();
+            case Integer:
+                return Lazy.TEMPLATE_INTEGER.access();
+            case List:
+                return Lazy.TEMPLATE_LIST.access();
+            case Expression:
+                return Lazy.TEMPLATE_EXPRESSION.access();
+            case Logical:
+                return Lazy.TEMPLATE_LOGICAL.access();
+            case Raw:
+                return Lazy.TEMPLATE_RAW.access();
+            case RInteropChar:
+            case RInteropFloat:
+            case RInteropLong:
+            case RInteropShort:
+            default:
+                throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    @TruffleBoundary
+    public static VectorAccess createSlowPathNew(RType type) {
+        switch (type) {
+            case Character:
+                return Lazy.TEMPLATE_CHARACTER.slowPathAccess();
+            case Complex:
+                return Lazy.TEMPLATE_COMPLEX.slowPathAccess();
+            case Double:
+                return Lazy.TEMPLATE_DOUBLE.slowPathAccess();
+            case Integer:
+                return Lazy.TEMPLATE_INTEGER.slowPathAccess();
+            case List:
+                return Lazy.TEMPLATE_LIST.slowPathAccess();
+            case Expression:
+                return Lazy.TEMPLATE_EXPRESSION.slowPathAccess();
+            case Logical:
+                return Lazy.TEMPLATE_LOGICAL.slowPathAccess();
+            case Raw:
+                return Lazy.TEMPLATE_RAW.slowPathAccess();
+            case RInteropChar:
+            case RInteropFloat:
+            case RInteropLong:
+            case RInteropShort:
+            default:
+                throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    public static VectorAccess create(Object value) {
+        CompilerAsserts.neverPartOfCompilation();
+        if (value instanceof RAbstractContainer) {
+            return ((RAbstractContainer) value).access();
+        } else {
+            return PrimitiveVectorAccess.create(value);
+        }
+    }
+
+    @TruffleBoundary
+    public static VectorAccess createSlowPath(Object value) {
+        if (value instanceof RAbstractContainer) {
+            return ((RAbstractContainer) value).slowPathAccess();
+        } else {
+            return PrimitiveVectorAccess.createSlowPath(value);
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccessAdapter.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccessAdapter.java
deleted file mode 100644
index c42c45e40b347a26f98af44574d13f8be368f044..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccessAdapter.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 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.data.nodes;
-
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-
-/**
- * Factors out common code.
- */
-abstract class VectorAccessAdapter extends Node {
-    @Child private GetDataStore getDataStoreNode = GetDataStoreNodeGen.create();
-
-    public Object getDataStore(RAbstractVector vector) {
-        return getDataStoreNode.execute(vector);
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorIterator.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorIterator.java
deleted file mode 100644
index ebb528ff5b3ccd8372e846f4a9f0f33f6b06e57a..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorIterator.java
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * Copyright (c) 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.data.nodes;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.ValueType;
-import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.Fallback;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.Utils;
-import com.oracle.truffle.r.runtime.data.NativeDataAccess;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
-import com.oracle.truffle.r.runtime.data.RDoubleVector;
-import com.oracle.truffle.r.runtime.data.RIntVector;
-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.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.data.nodes.GetNextNodeGen.GetNextGenericNodeGen;
-import com.oracle.truffle.r.runtime.data.nodes.VectorIterator.IteratorData;
-
-abstract class VectorIteratorNodeAdapter extends Node {
-    public static boolean hasNoNativeMemoryData(RAbstractVector vector, Class<? extends RAbstractVector> vecClass) {
-        return !(RVector.class.isAssignableFrom(vecClass)) || !((RVector<?>) vecClass.cast(vector)).hasNativeMemoryData();
-    }
-
-    public static boolean isRVector(Class<? extends RAbstractVector> vecClass) {
-        return RVector.class.isAssignableFrom(vecClass);
-    }
-}
-
-abstract class GetIteratorNode extends VectorIteratorNodeAdapter {
-    public abstract IteratorData<?> execute(RAbstractVector vector);
-
-    @Specialization(guards = "vector.hasNativeMemoryData()")
-    protected IteratorData<?> nativeMirrorIterator(RVector<?> vector) {
-        return new IteratorData<>(vector.getNativeMirror(), vector.getLength());
-    }
-
-    @Specialization(guards = {"vectorClass == vector.getClass()", "hasNoNativeMemoryData(vector, vectorClass)"}, limit = "10")
-    protected IteratorData<?> cached(RAbstractVector vector,
-                    @Cached("vector.getClass()") Class<? extends RAbstractVector> vectorClass) {
-        RAbstractVector profiledVec = vectorClass.cast(vector);
-        return new IteratorData<>(profiledVec.getInternalStore(), profiledVec.getLength());
-    }
-
-    @Specialization(replaces = "cached", guards = {"hasNoNativeMemoryData(vector, vector.getClass())"})
-    protected IteratorData<?> generic(RAbstractVector vector) {
-        RAbstractVector profiledVec = vector;
-        return new IteratorData<>(profiledVec.getInternalStore(), profiledVec.getLength());
-    }
-
-    @Fallback
-    protected IteratorData<?> fallback(RAbstractVector vector) {
-        return new IteratorData<>(vector.getInternalStore(), vector.getLength());
-    }
-}
-
-@SuppressWarnings("unused")
-abstract class HasNextNode extends VectorIteratorNodeAdapter {
-    public abstract boolean execute(RAbstractVector vector, IteratorData<?> iterator);
-
-    @Specialization(guards = "!iter.hasNativeMirror()")
-    protected boolean intVector(RIntVector vector, IteratorData<?> iter) {
-        return iter.index < ((int[]) iter.store).length;
-    }
-
-    @Specialization(guards = "!iter.hasNativeMirror()")
-    protected boolean doubleVector(RDoubleVector vector, IteratorData<?> iter) {
-        return iter.index < ((double[]) iter.store).length;
-    }
-
-    @Specialization(guards = "!iter.hasNativeMirror()")
-    protected boolean logicalVector(RLogicalVector vector, IteratorData<?> iter) {
-        return iter.index < ((byte[]) iter.store).length;
-    }
-
-    @Specialization(guards = "!iter.hasNativeMirror()")
-    protected boolean rawVector(RRawVector vector, IteratorData<?> iter) {
-        return iter.index < ((byte[]) iter.store).length;
-    }
-
-    @Specialization(guards = "!iter.hasNativeMirror()")
-    protected boolean stringVector(RStringVector vector, IteratorData<?> iter) {
-        return iter.index < ((String[]) iter.store).length;
-    }
-
-    @Specialization(guards = {"vectorClass == vector.getClass()", "!isRVector(vectorClass)"}, limit = "10")
-    protected boolean generic(RAbstractVector vector, IteratorData<?> iter,
-                    @Cached("vector.getClass()") Class<? extends RAbstractVector> vectorClass) {
-        RAbstractVector profiledVec = vectorClass.cast(vector);
-        return iter.index < profiledVec.getLength();
-    }
-
-    @Specialization
-    protected boolean generic(RAbstractVector vector, IteratorData<?> iter) {
-        return iter.index < vector.getLength();
-    }
-}
-
-@SuppressWarnings("unused")
-abstract class GetNextNode extends VectorIteratorNodeAdapter {
-    public abstract Object execute(RAbstractVector vector, IteratorData<?> iterator);
-
-    @Specialization(guards = "!iter.hasNativeMirror()")
-    protected int intVector(RIntVector vector, IteratorData<?> iter) {
-        return ((int[]) iter.store)[iter.index];
-    }
-
-    @Specialization(guards = "!iter.hasNativeMirror()")
-    protected double doubleVector(RDoubleVector vector, IteratorData<?> iter) {
-        return ((double[]) iter.store)[iter.index];
-    }
-
-    @Specialization(guards = "!iter.hasNativeMirror()")
-    protected byte logicalVector(RLogicalVector vector, IteratorData<?> iter) {
-        return ((byte[]) iter.store)[iter.index];
-    }
-
-    @Specialization(guards = "!iter.hasNativeMirror()")
-    protected RComplex doComplexVector(RComplexVector vector, IteratorData<?> iter) {
-        double[] arr = (double[]) iter.store;
-        return RComplex.valueOf(arr[iter.index * 2], arr[iter.index * 2 + 1]);
-    }
-
-    @Specialization(guards = "!iter.hasNativeMirror()")
-    protected byte doRawVector(RRawVector vector, IteratorData<?> iter) {
-        return ((byte[]) iter.store)[iter.index];
-    }
-
-    @Specialization(guards = "!iter.hasNativeMirror()")
-    protected String doStringVector(RStringVector vector, IteratorData<?> iter) {
-        return ((String[]) iter.store)[iter.index];
-    }
-
-    @Specialization(guards = "iter.hasNativeMirror()")
-    protected int intVectorNative(RIntVector vector, IteratorData<?> iter) {
-        return NativeDataAccess.getIntNativeMirrorData(iter.store, iter.index);
-    }
-
-    @Specialization(guards = "iter.hasNativeMirror()")
-    protected double doubleVectorNative(RDoubleVector vector, IteratorData<?> iter) {
-        return NativeDataAccess.getDoubleNativeMirrorData(iter.store, iter.index);
-    }
-
-    @Specialization(guards = "iter.hasNativeMirror()")
-    protected byte logicalVectorNative(RLogicalVector vector, IteratorData<?> iter) {
-        return NativeDataAccess.getLogicalNativeMirrorData(iter.store, iter.index);
-    }
-
-    @Specialization(guards = "iter.hasNativeMirror()")
-    protected byte doubleVectorNative(RRawVector vector, IteratorData<?> iter) {
-        return NativeDataAccess.getRawNativeMirrorData(iter.store, iter.index);
-    }
-
-    @Specialization(guards = "iter.hasNativeMirror()")
-    protected RComplex complexVectorNative(RComplexVector vector, IteratorData<?> iter) {
-        return NativeDataAccess.getComplexNativeMirrorData(iter.store, iter.index);
-    }
-
-    @Specialization(guards = "iter.hasNativeMirror()")
-    protected byte stringVectorNative(RStringVector vector, IteratorData<?> iter) {
-        throw RInternalError.unimplemented("string vectors backed by native memory");
-    }
-
-    @Child private GetNextGenericNode getNextGenericNode;
-
-    @Fallback
-    protected Object doGeneric(RAbstractVector vector, IteratorData<?> iter) {
-        // we use fallback and extra node so that we do not have to explicitly check that the vector
-        // is not
-        // RVector, DSL generates fallback guard that compares the class with the all RVector
-        // subclasses
-        // used in the specializations above, "vector instanceof RVector" would not be a leaf-check.
-        if (getNextGenericNode == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            getNextGenericNode = insert(GetNextGenericNode.create());
-        }
-        return getNextGenericNode.execute(vector, iter);
-    }
-
-    abstract static class GetNextGenericNode extends Node {
-        public abstract Object execute(RAbstractVector vector, IteratorData<?> iter);
-
-        public static GetNextGenericNode create() {
-            return GetNextGenericNodeGen.create();
-        }
-
-        @Specialization
-        protected int intVectorGeneric(RAbstractIntVector vector, IteratorData<?> iter,
-                        @Cached("create()") GetDataAt.Int getDataAtNode) {
-            return getDataAtNode.get(vector, iter.store, iter.index);
-        }
-
-        @Specialization
-        protected double doubleVectorGeneric(RAbstractDoubleVector vector, IteratorData<?> iter,
-                        @Cached("create()") GetDataAt.Double getDataAtNode) {
-            return getDataAtNode.get(vector, iter.store, iter.index);
-        }
-
-        @Specialization
-        protected String stringVectorGeneric(RAbstractStringVector vector, IteratorData<?> iter,
-                        @Cached("create()") GetDataAt.String getDataAtNode) {
-            return getDataAtNode.get(vector, iter.store, iter.index);
-        }
-
-        @Specialization
-        protected byte rawVectorGeneric(RAbstractRawVector vector, IteratorData<?> iter,
-                        @Cached("create()") GetDataAt.Raw getDataAtNode) {
-            return getDataAtNode.get(vector, iter.store, iter.index);
-        }
-
-        @Specialization
-        protected byte logicalVectorGeneric(RAbstractLogicalVector vector, IteratorData<?> iter,
-                        @Cached("create()") GetDataAt.Logical getDataAtNode) {
-            return getDataAtNode.get(vector, iter.store, iter.index);
-        }
-
-        @Specialization
-        protected RComplex complexVectorGeneric(RAbstractComplexVector vector, IteratorData<?> iter,
-                        @Cached("create()") GetDataAt.Complex getDataAtNode) {
-            return getDataAtNode.get(vector, iter.store, iter.index);
-        }
-    }
-}
-
-// Checkstyle: stop final class check
-// Note: the VectorIterator cannot be final, it has inner subclasses, which probably confuses check
-// style
-
-/**
- * This node wraps 3 nodes needed to sequentially iterate a given vector and provides convenience
- * methods to invoke those nodes: {@link #init(RAbstractVector)},
- * {@link #next(RAbstractVector, Object)} and {@link #hasNext(RAbstractVector, Object)}.
- *
- * To construct use factory methods from type specialized inner classes, e.g. {@link Int#create()},
- * or generic version if the iterated vector could be of any type {@link Generic#create()}.
- *
- * Iterator can wrap around, i.e. once the iteration ends, it starts again from the first element.
- */
-public abstract class VectorIterator<T> extends Node {
-
-    // Note: it could be worth adding a LoopConditionProfile, however, it must be shared between
-    // getIteratorNode and getNextNode
-
-    @Child private GetIteratorNode getIteratorNode = GetIteratorNodeGen.create();
-    @Child private HasNextNode hasNextNode;
-    @Child private GetNextNode getNextNode = GetNextNodeGen.create();
-    private final boolean wrapAround;
-
-    private VectorIterator(boolean wrapAround) {
-        this.wrapAround = wrapAround;
-        if (!wrapAround) {
-            hasNextNode = HasNextNodeGen.create();
-        }
-    }
-
-    public Object init(RAbstractVector vector) {
-        return getIteratorNode.execute(vector);
-    }
-
-    public boolean hasNext(RAbstractVector vector, Object iterator) {
-        assert !wrapAround : "wrap-around iteration does not support hasNext";
-        return hasNextNode.execute(vector, (IteratorData<?>) iterator);
-    }
-
-    @SuppressWarnings("unchecked")
-    public T next(RAbstractVector vector, Object iterator) {
-        IteratorData<T> it = (IteratorData<T>) iterator;
-        assert it.index < it.length;
-        Object result = getNextNode.execute(vector, it);
-        if (wrapAround) {
-            it.index = Utils.incMod(it.index, it.length);
-        } else {
-            it.index++;
-        }
-        return (T) result;
-    }
-
-    public static final class Generic extends VectorIterator<Object> {
-
-        private Generic(boolean wrapAround) {
-            super(wrapAround);
-        }
-
-        public static Generic create() {
-            return new Generic(false);
-        }
-
-        public static Generic createWrapAround() {
-            return new Generic(true);
-        }
-    }
-
-    public static final class Int extends VectorIterator<Integer> {
-
-        public Int(boolean wrapAround) {
-            super(wrapAround);
-        }
-
-        public static Int create() {
-            return new Int(false);
-        }
-    }
-
-    public static final class Double extends VectorIterator<java.lang.Double> {
-        public Double(boolean wrapAround) {
-            super(wrapAround);
-        }
-
-        public static Double create() {
-            return new Double(false);
-        }
-
-        public static Double createWrapAround() {
-            return new Double(true);
-        }
-    }
-
-    public static final class Logical extends VectorIterator<Byte> {
-        public Logical(boolean wrapAround) {
-            super(wrapAround);
-        }
-
-        public static Logical create() {
-            return new Logical(false);
-        }
-    }
-
-    public static final class Raw extends VectorIterator<Byte> {
-        public Raw(boolean wrapAround) {
-            super(wrapAround);
-        }
-
-        public static Raw create() {
-            return new Raw(false);
-        }
-    }
-
-    @ValueType
-    public static final class IteratorData<StoreT> {
-        public int index = 0;
-        public final StoreT store;
-        public final int length;
-
-        public IteratorData(StoreT store, int length) {
-            this.store = store;
-            this.length = length;
-        }
-
-        public boolean hasNativeMirror() {
-            return NativeDataAccess.isNativeMirror(store);
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReadAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReadAccess.java
deleted file mode 100644
index f4d70cdf22da3fa256468fa2b6c9a5f407bd3acc..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReadAccess.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 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.data.nodes;
-
-import com.oracle.truffle.api.nodes.NodeCost;
-import com.oracle.truffle.api.nodes.NodeInfo;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-
-/**
- * Contains nodes that encapsulate {@link GetDataStore} and one of the nodes from {@link GetDataAt}
- * as these are often used together. These are convenience wrappers to be used e.g. for a @Cached
- * parameter.
- */
-public abstract class VectorReadAccess extends VectorAccessAdapter {
-
-    public abstract Object getDataAtAsObject(RAbstractVector vector, Object store, int index);
-
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class Double extends VectorReadAccess {
-        @Child private GetDataAt.Double getDataAtNode = GetDataAt.Double.create();
-
-        public double getDataAt(RAbstractDoubleVector vec, Object store, int index) {
-            return getDataAtNode.get(vec, store, index);
-        }
-
-        @Override
-        public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) {
-            return getDataAt((RAbstractDoubleVector) vector, store, index);
-        }
-
-        public static Double create() {
-            return new Double();
-        }
-    }
-
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class Int extends VectorReadAccess {
-        @Child private GetDataAt.Int getDataAtNode = GetDataAt.Int.create();
-
-        public int getDataAt(RAbstractIntVector vec, Object store, int index) {
-            return getDataAtNode.get(vec, store, index);
-        }
-
-        @Override
-        public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) {
-            return getDataAt((RAbstractIntVector) vector, store, index);
-        }
-
-        public static Int create() {
-            return new Int();
-        }
-    }
-
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class Logical extends VectorReadAccess {
-        @Child private GetDataAt.Logical getDataAtNode = GetDataAt.Logical.create();
-
-        public byte getDataAt(RAbstractLogicalVector vec, Object store, int index) {
-            return getDataAtNode.get(vec, store, index);
-        }
-
-        @Override
-        public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) {
-            return getDataAt((RAbstractLogicalVector) vector, store, index);
-        }
-
-        public static Logical create() {
-            return new Logical();
-        }
-    }
-
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class Complex extends VectorReadAccess {
-        @Child private GetDataAt.Complex getDataAtNode = GetDataAt.Complex.create();
-
-        public RComplex getDataAt(RAbstractComplexVector vec, Object store, int index) {
-            return getDataAtNode.get(vec, store, index);
-        }
-
-        @Override
-        public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) {
-            return getDataAt((RAbstractComplexVector) vector, store, index);
-        }
-
-        public static Complex create() {
-            return new Complex();
-        }
-    }
-
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class String extends VectorReadAccess {
-        @Child private GetDataAt.String getDataAtNode = GetDataAt.String.create();
-
-        public java.lang.String getDataAt(RAbstractStringVector vec, Object store, int index) {
-            return getDataAtNode.get(vec, store, index);
-        }
-
-        @Override
-        public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) {
-            return getDataAt((RAbstractStringVector) vector, store, index);
-        }
-
-        public static String create() {
-            return new String();
-        }
-    }
-
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class Raw extends VectorReadAccess {
-        @Child private GetDataAt.Raw getDataAtNode = GetDataAt.Raw.create();
-
-        public byte getDataAt(RAbstractRawVector vec, Object store, int index) {
-            return getDataAtNode.get(vec, store, index);
-        }
-
-        @Override
-        public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) {
-            return getDataAt((RAbstractRawVector) vector, store, index);
-        }
-
-        public static Raw create() {
-            return new Raw();
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReuse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReuse.java
new file mode 100644
index 0000000000000000000000000000000000000000..88106a631e544dcb6f2e2885c4e67057aaa8945f
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReuse.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 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.data.nodes;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+
+public final class VectorReuse extends Node {
+
+    @Child private VectorAccess access;
+
+    private final boolean isShareableClass;
+    private final boolean isTempOrNonShared;
+    private final boolean needsTemporary;
+    protected final boolean isGeneric;
+    protected final Class<? extends RAbstractVector> clazz;
+
+    public VectorReuse(RAbstractVector vector, boolean needsTemporary, boolean isGeneric) {
+        this.isShareableClass = isGeneric ? false : vector instanceof RSharingAttributeStorage;
+        this.clazz = isGeneric ? null : vector.getClass();
+        this.needsTemporary = needsTemporary;
+        this.isGeneric = isGeneric;
+        this.isTempOrNonShared = isShareableClass && isTempOrNonShared(vector);
+    }
+
+    protected RAbstractVector cast(RAbstractVector value) {
+        return clazz.cast(value);
+    }
+
+    public VectorAccess access(RAbstractVector result) {
+        return isGeneric ? result.slowPathAccess() : access;
+    }
+
+    public boolean supports(RAbstractVector value) {
+        assert !isGeneric : "cannot call 'supports' on generic vector reuse";
+        RSharingAttributeStorage.verify(value);
+        if (value.getClass() != clazz) {
+            return false;
+        }
+        if (access == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            access = insert(isTempOrNonShared ? value.access() : VectorAccess.createNew(value.getRType()));
+        }
+        if (!isShareableClass) {
+            return true;
+        }
+        if (isTempOrNonShared && !access.supports(value)) {
+            return false;
+        }
+        RSharingAttributeStorage vector = (RSharingAttributeStorage) cast(value);
+        return needsTemporary ? vector.isTemporary() == isTempOrNonShared : !vector.isShared() == isTempOrNonShared;
+    }
+
+    @TruffleBoundary
+    private static RAbstractVector copyVector(RAbstractVector vector) {
+        return vector.copy();
+    }
+
+    private boolean isTempOrNonShared(RAbstractVector vector) {
+        return needsTemporary ? ((RSharingAttributeStorage) vector).isTemporary() : !((RSharingAttributeStorage) vector).isShared();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends RAbstractVector> T getResult(T vector) {
+        RAbstractVector result;
+        if (isGeneric) {
+            RSharingAttributeStorage.verify(vector);
+            if (vector instanceof RSharingAttributeStorage && isTempOrNonShared(vector)) {
+                result = vector;
+            } else {
+                result = copyVector(vector);
+            }
+        } else {
+            if (!isShareableClass || !isTempOrNonShared) {
+                result = cast(vector).copy();
+            } else {
+                result = cast(vector);
+            }
+        }
+        return (T) result;
+    }
+
+    public static VectorReuse createTemporaryGeneric() {
+        return new VectorReuse(null, true, true);
+    }
+
+    public static VectorReuse createNonSharedGeneric() {
+        return new VectorReuse(null, false, true);
+    }
+
+    public static VectorReuse createTemporary(RAbstractVector vector) {
+        return new VectorReuse(vector, true, false);
+    }
+
+    public static VectorReuse createNonShared(RAbstractVector vector) {
+        return new VectorReuse(vector, false, false);
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorWriteAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorWriteAccess.java
deleted file mode 100644
index 8c8af336399fc53fedd2b6519b94420a18f6ab2a..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorWriteAccess.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 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.data.nodes;
-
-import com.oracle.truffle.api.nodes.NodeCost;
-import com.oracle.truffle.api.nodes.NodeInfo;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
-import com.oracle.truffle.r.runtime.data.RDoubleVector;
-import com.oracle.truffle.r.runtime.data.RIntVector;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
-import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-
-/**
- * Contains nodes that encapsulate {@link GetDataStore} and one of the nodes from {@link SetDataAt}
- * as these are often used together. These are convenience wrappers to be used e.g. for a @Cached
- * parameter.
- */
-public abstract class VectorWriteAccess {
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class Double extends VectorAccessAdapter {
-        @Child private SetDataAt.Double setDataAtNode = SetDataAt.Double.create();
-
-        public void setDataAt(RDoubleVector vector, Object store, int index, double value) {
-            setDataAtNode.setDataAt(vector, store, index, value);
-        }
-
-        public static Double create() {
-            return new Double();
-        }
-    }
-
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class Int extends VectorAccessAdapter {
-        @Child private SetDataAt.Int setDataAtNode = SetDataAt.Int.create();
-
-        public void setDataAt(RIntVector vector, Object store, int index, int value) {
-            setDataAtNode.setDataAt(vector, store, index, value);
-        }
-
-        public static Int create() {
-            return new Int();
-        }
-    }
-
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class Logical extends VectorAccessAdapter {
-        @Child private SetDataAt.Logical setDataAtNode = SetDataAt.Logical.create();
-
-        public void setDataAt(RLogicalVector vector, Object store, int index, byte value) {
-            setDataAtNode.setDataAt(vector, store, index, value);
-        }
-
-        public static Logical create() {
-            return new Logical();
-        }
-    }
-
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class Raw extends VectorAccessAdapter {
-        @Child private SetDataAt.Raw setDataAtNode = SetDataAt.Raw.create();
-
-        public void setDataAt(RRawVector vector, Object store, int index, byte value) {
-            setDataAtNode.setDataAt(vector, store, index, value);
-        }
-
-        public static Raw create() {
-            return new Raw();
-        }
-    }
-
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class String extends VectorAccessAdapter {
-        @Child private SetDataAt.String setDataAtNode = SetDataAt.String.create();
-
-        public void setDataAt(RStringVector vector, Object store, int index, java.lang.String value) {
-            setDataAtNode.setDataAt(vector, store, index, value);
-        }
-
-        public static String create() {
-            return new String();
-        }
-    }
-
-    @NodeInfo(cost = NodeCost.NONE)
-    public static final class Complex extends VectorAccessAdapter {
-        @Child private SetDataAt.Complex setDataAtNode = SetDataAt.Complex.create();
-
-        public void setDataAt(RComplexVector vector, Object store, int index, RComplex value) {
-            setDataAtNode.setDataAt(vector, store, index, value);
-        }
-
-        public static Complex create() {
-            return new Complex();
-        }
-    }
-}
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 014af717bc7c428eaedd64e7b0459645f8206dba..ecfce5c1599cbf35bb9781ea96fa3c7f44c1d6d5 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
@@ -1147,6 +1147,7 @@ public abstract class REnvironment extends RAttributeStorage {
         }
 
         @Override
+        @TruffleBoundary
         public void put(String key, Object value) throws PutException {
             throw new PutException(RError.Message.ENV_ASSIGN_EMPTY);
         }
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 1175bc95eb911cab80507e441c3610bd2a6e71cb..b2b566a04b42acfad7ea08777d82f7b3882d1c6a 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
@@ -56,6 +56,8 @@ 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.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 import sun.misc.Unsafe;
@@ -390,12 +392,15 @@ final class RawWrapper extends TemporaryWrapper {
     @TruffleBoundary
     public long allocate() {
         RAbstractRawVector v = (RAbstractRawVector) vector;
-        int length = v.getLength();
-        long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_BYTE_INDEX_SCALE);
-        for (int i = 0; i < length; i++) {
-            UnsafeAdapter.UNSAFE.putByte(memory + (i * Unsafe.ARRAY_BYTE_INDEX_SCALE), v.getRawDataAt(i));
+        VectorAccess access = v.slowPathAccess();
+        try (SequentialIterator iter = access.access(v)) {
+            int length = access.getLength(iter);
+            long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_BYTE_INDEX_SCALE);
+            while (access.next(iter)) {
+                UnsafeAdapter.UNSAFE.putByte(memory + (iter.getIndex() * Unsafe.ARRAY_BYTE_INDEX_SCALE), access.getRaw(iter));
+            }
+            return memory;
         }
-        return memory;
     }
 
     @Override
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java
index bb59cfc10cae05de573a6806be5509dc8c48a24c..43bffb637f5f30e311b4d1be0b663c15ddab6921 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java
@@ -43,9 +43,16 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException;
 import com.oracle.truffle.api.interop.UnsupportedTypeException;
 import com.oracle.truffle.api.interop.java.JavaInterop;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RForeignBooleanWrapper;
+import com.oracle.truffle.r.runtime.data.RForeignDoubleWrapper;
+import com.oracle.truffle.r.runtime.data.RForeignIntWrapper;
+import com.oracle.truffle.r.runtime.data.RForeignListWrapper;
+import com.oracle.truffle.r.runtime.data.RForeignStringWrapper;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
@@ -59,9 +66,10 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 public abstract class ForeignArray2R extends RBaseNode {
 
     @Child protected Node hasSize = Message.HAS_SIZE.createNode();
+    @Child protected Node getSize = Message.GET_SIZE.createNode();
     @Child private Foreign2R foreign2R;
     @Child private ForeignArray2R foreignArray2R;
-    @Child private Node read;
+    @Child private Node read = Message.READ.createNode();
     @Child private Node isNull;
     @Child private Node isBoxed;
     @Child private Node unbox;
@@ -91,25 +99,54 @@ public abstract class ForeignArray2R extends RBaseNode {
      *
      */
     public Object convert(Object obj, boolean recursive) {
-        Object result = execute(obj, recursive, null, 0);
-        if (result instanceof ForeignArrayData) {
-            ForeignArrayData arrayData = (ForeignArrayData) result;
-            if (arrayData.elements.isEmpty()) {
-                return RDataFactory.createList();
+        if (FastROptions.ForeignObjectWrappers.getBooleanValue()) {
+            if (isForeignArray(obj)) {
+                TruffleObject truffleObject = (TruffleObject) obj;
+                try {
+                    int size = (int) ForeignAccess.sendGetSize(getSize, truffleObject);
+                    if (size == 0) {
+                        return new RForeignListWrapper(truffleObject);
+                    } else {
+                        Object firstElement = ForeignAccess.sendRead(read, truffleObject, 0);
+                        switch (InteropTypeCheck.determineType(firstElement)) {
+                            case BOOLEAN:
+                                return new RForeignBooleanWrapper(truffleObject);
+                            case DOUBLE:
+                                return new RForeignDoubleWrapper(truffleObject);
+                            case INTEGER:
+                                return new RForeignIntWrapper(truffleObject);
+                            case STRING:
+                                return new RForeignStringWrapper(truffleObject);
+                            default:
+                                return new RForeignListWrapper(truffleObject);
+                        }
+                    }
+                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                    throw RInternalError.shouldNotReachHere(e);
+                }
+            } else {
+                return obj;
             }
-            return asAbstractVector(arrayData);
+        } else {
+            Object result = execute(obj, recursive, null, 0);
+            if (result instanceof ForeignArrayData) {
+                ForeignArrayData arrayData = (ForeignArrayData) result;
+                if (arrayData.elements.isEmpty()) {
+                    return RDataFactory.createList();
+                }
+                return asAbstractVector(arrayData);
+            }
+            return result;
         }
-        return result;
     }
 
     protected abstract Object execute(Object obj, boolean recursive, ForeignArrayData arrayData, int depth);
 
     @Specialization(guards = {"isForeignArray(obj)"})
     @TruffleBoundary
-    protected ForeignArrayData doArray(TruffleObject obj, boolean recursive, ForeignArrayData arrayData, int depth,
-                    @Cached("GET_SIZE.createNode()") Node getSize) {
+    protected ForeignArrayData doArray(TruffleObject obj, boolean recursive, ForeignArrayData arrayData, int depth) {
         try {
-            return collectArrayElements(arrayData == null ? new ForeignArrayData() : arrayData, obj, recursive, getSize, depth);
+            return collectArrayElements(arrayData == null ? new ForeignArrayData() : arrayData, obj, recursive, depth);
         } catch (UnsupportedMessageException | UnknownIdentifierException e) {
             throw error(RError.Message.GENERIC, "error while converting array: " + e.getMessage());
         }
@@ -132,7 +169,7 @@ public abstract class ForeignArray2R extends RBaseNode {
         return obj;
     }
 
-    private ForeignArrayData collectArrayElements(ForeignArrayData arrayData, TruffleObject obj, boolean recursive, Node getSize, int depth)
+    private ForeignArrayData collectArrayElements(ForeignArrayData arrayData, TruffleObject obj, boolean recursive, int depth)
                     throws UnsupportedMessageException, UnknownIdentifierException {
         int size = (int) ForeignAccess.sendGetSize(getSize, obj);
 
@@ -152,10 +189,6 @@ public abstract class ForeignArray2R extends RBaseNode {
             return arrayData;
         }
         for (int i = 0; i < size; i++) {
-            if (read == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                read = insert(Message.READ.createNode());
-            }
             Object element = ForeignAccess.sendRead(read, obj, i);
             if (recursive && (isForeignArray(element, hasSize) || isJavaIterable(element))) {
                 recurse(arrayData, element, depth);
@@ -387,6 +420,20 @@ public abstract class ForeignArray2R extends RBaseNode {
 
         private RType type = null;
 
+        public static RType determineType(Object value) {
+            if (value instanceof Boolean) {
+                return RType.BOOLEAN;
+            } else if (value instanceof Byte || value instanceof Integer || value instanceof Short) {
+                return RType.INTEGER;
+            } else if (value instanceof Double || value instanceof Float || value instanceof Long) {
+                return RType.DOUBLE;
+            } else if (value instanceof Character || value instanceof String) {
+                return RType.STRING;
+            } else {
+                return RType.NONE;
+            }
+        }
+
         public RType checkForeign(Object value) {
             if (value instanceof Boolean) {
                 setType(RType.BOOLEAN);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/TruffleObjectConverter.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/TruffleObjectConverter.java
index 2bb74514a080165169958abc0501ef2d95c93107..e939f44b7a402218b413034d9093cf367251f961 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/TruffleObjectConverter.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/TruffleObjectConverter.java
@@ -26,29 +26,18 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.InteropException;
 import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.interop.UnknownIdentifierException;
-import com.oracle.truffle.api.interop.UnsupportedMessageException;
 import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributeStorage;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout;
 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.RList;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
+import com.oracle.truffle.r.runtime.data.RForeignBooleanWrapper;
+import com.oracle.truffle.r.runtime.data.RForeignDoubleWrapper;
+import com.oracle.truffle.r.runtime.data.RForeignIntWrapper;
+import com.oracle.truffle.r.runtime.data.RForeignListWrapper;
+import com.oracle.truffle.r.runtime.data.RForeignNamedListWrapper;
+import com.oracle.truffle.r.runtime.data.RForeignStringWrapper;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
-import com.oracle.truffle.r.runtime.data.RVector;
-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.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;
 
 public final class TruffleObjectConverter {
 
@@ -58,93 +47,13 @@ public final class TruffleObjectConverter {
     private Node isBoxedNode = com.oracle.truffle.api.interop.Message.IS_BOXED.createNode();
     private Node unboxNode = com.oracle.truffle.api.interop.Message.UNBOX.createNode();
     private Node keysNode = com.oracle.truffle.api.interop.Message.KEYS.createNode();
-    private Foreign2R foreign2R = Foreign2R.create();
-
-    public TruffleObjectConverter() {
-    }
 
     public Node[] getSubNodes() {
-        return new Node[]{
-                        hasSizeNode, getSizeNode, readNode, isBoxedNode, unboxNode, keysNode, foreign2R
-        };
+        return new Node[]{hasSizeNode, getSizeNode, readNode, isBoxedNode, unboxNode, keysNode};
     }
 
     @TruffleBoundary
     public Object convert(TruffleObject obj) {
-        class RStringWrapper extends TruffleObjectWrapper implements RAbstractStringVector {
-            final TruffleObject object;
-
-            RStringWrapper(int length, TruffleObject object) {
-                super(length);
-                this.object = object;
-            }
-
-            @Override
-            @TruffleBoundary
-            public Object getDataAtAsObject(int index) {
-                return getDataAt(index);
-            }
-
-            @Override
-            @TruffleBoundary
-            public String getDataAt(int index) {
-                Object value;
-                try {
-                    value = ForeignAccess.sendRead(readNode, object, index);
-                    return String.valueOf(foreign2R.execute(value));
-                } catch (UnknownIdentifierException | UnsupportedMessageException e) {
-                    throw RInternalError.shouldNotReachHere(e);
-                }
-            }
-
-            @Override
-            @TruffleBoundary
-            public RStringVector materialize() {
-                throw RInternalError.shouldNotReachHere();
-            }
-        }
-        class RListWrapper extends TruffleObjectWrapper implements RAbstractListVector {
-
-            private final RStringVector names;
-
-            RListWrapper(int length, RStringVector names) {
-                super(length);
-                this.names = names;
-                if (names != null) {
-                    DynamicObject attrs = RAttributesLayout.createNames(names);
-                    initAttributes(attrs);
-                }
-            }
-
-            @Override
-            @TruffleBoundary
-            public Object getDataAtAsObject(int index) {
-                return getDataAt(index);
-            }
-
-            @Override
-            @TruffleBoundary
-            public Object getDataAt(int index) {
-                try {
-                    Object value = ForeignAccess.sendRead(readNode, obj, names != null ? names.getDataAt(index) : index);
-                    return foreign2R.execute(value);
-                } catch (UnknownIdentifierException | UnsupportedMessageException e) {
-                    throw RInternalError.shouldNotReachHere(e);
-                }
-            }
-
-            @Override
-            @TruffleBoundary
-            public RStringVector getNames() {
-                return names;
-            }
-
-            @Override
-            @TruffleBoundary
-            public RList materialize() {
-                throw RInternalError.shouldNotReachHere();
-            }
-        }
         try {
             if (ForeignAccess.sendHasSize(hasSizeNode, obj)) {
                 int size = (Integer) ForeignAccess.sendGetSize(getSizeNode, obj);
@@ -160,102 +69,15 @@ public final class TruffleObjectConverter {
                 }
                 switch (typeCheck.getType()) {
                     case BOOLEAN:
-                        class RLogicalWrapper extends TruffleObjectWrapper implements RAbstractLogicalVector {
-
-                            RLogicalWrapper(int length) {
-                                super(length);
-                            }
-
-                            @Override
-                            @TruffleBoundary
-                            public Object getDataAtAsObject(int index) {
-                                return getDataAt(index);
-                            }
-
-                            @Override
-                            @TruffleBoundary
-                            public byte getDataAt(int index) {
-                                try {
-                                    Object value = ForeignAccess.sendRead(readNode, obj, index);
-                                    return (byte) foreign2R.execute(value);
-                                } catch (UnknownIdentifierException | UnsupportedMessageException e) {
-                                    throw RInternalError.shouldNotReachHere(e);
-                                }
-                            }
-
-                            @Override
-                            @TruffleBoundary
-                            public RLogicalVector materialize() {
-                                throw RInternalError.shouldNotReachHere();
-                            }
-                        }
-                        return new RLogicalWrapper(size);
+                        return new RForeignBooleanWrapper(obj);
                     case INTEGER:
-                        class RIntWrapper extends TruffleObjectWrapper implements RAbstractIntVector {
-
-                            RIntWrapper(int length) {
-                                super(length);
-                            }
-
-                            @Override
-                            @TruffleBoundary
-                            public Object getDataAtAsObject(int index) {
-                                return getDataAt(index);
-                            }
-
-                            @Override
-                            @TruffleBoundary
-                            public int getDataAt(int index) {
-                                try {
-                                    Object value = ForeignAccess.sendRead(readNode, obj, index);
-                                    return ((Number) foreign2R.execute(value)).intValue();
-                                } catch (UnknownIdentifierException | UnsupportedMessageException e) {
-                                    throw RInternalError.shouldNotReachHere(e);
-                                }
-                            }
-
-                            @Override
-                            @TruffleBoundary
-                            public RIntVector materialize() {
-                                throw RInternalError.shouldNotReachHere();
-                            }
-                        }
-                        return new RIntWrapper(size);
+                        return new RForeignIntWrapper(obj);
                     case DOUBLE:
-                        class RDoubleWrapper extends TruffleObjectWrapper implements RAbstractDoubleVector {
-
-                            RDoubleWrapper(int length) {
-                                super(length);
-                            }
-
-                            @Override
-                            @TruffleBoundary
-                            public Object getDataAtAsObject(int index) {
-                                return getDataAt(index);
-                            }
-
-                            @Override
-                            @TruffleBoundary
-                            public double getDataAt(int index) {
-                                try {
-                                    Object value = ForeignAccess.sendRead(readNode, obj, index);
-                                    return ((Number) foreign2R.execute(value)).doubleValue();
-                                } catch (UnknownIdentifierException | UnsupportedMessageException e) {
-                                    throw RInternalError.shouldNotReachHere(e);
-                                }
-                            }
-
-                            @Override
-                            @TruffleBoundary
-                            public RDoubleVector materialize() {
-                                throw RInternalError.shouldNotReachHere();
-                            }
-                        }
-                        return new RDoubleWrapper(size);
+                        return new RForeignDoubleWrapper(obj);
                     case STRING:
-                        return new RStringWrapper(size, obj);
+                        return new RForeignStringWrapper(obj);
                     case NONE:
-                        return new RListWrapper(size, null);
+                        return new RForeignListWrapper(obj);
                     default:
                         throw RInternalError.shouldNotReachHere();
                 }
@@ -263,7 +85,7 @@ public final class TruffleObjectConverter {
             TruffleObject keys = (TruffleObject) ForeignAccess.send(keysNode, obj);
             if (keys != null) {
                 int size = (Integer) ForeignAccess.sendGetSize(getSizeNode, keys);
-                RAbstractStringVector abstractNames = new RStringWrapper(size, keys);
+                RAbstractStringVector abstractNames = new RForeignStringWrapper(keys);
                 String[] namesData = new String[size];
                 boolean namesComplete = true;
                 for (int i = 0; i < size; i++) {
@@ -272,141 +94,11 @@ public final class TruffleObjectConverter {
                 }
                 RStringVector names = RDataFactory.createStringVector(namesData, namesComplete);
 
-                return new RListWrapper(size, names);
+                return new RForeignNamedListWrapper(obj, names);
             }
         } catch (InteropException e) {
             // nothing to do
         }
         return obj;
     }
-
-    private abstract static class TruffleObjectWrapper extends RAttributeStorage implements RAbstractVector {
-
-        private final int length;
-
-        TruffleObjectWrapper(int length) {
-            this.length = length;
-        }
-
-        @Override
-        public RAbstractVector copy() {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public RVector<?> copyResized(int size, boolean fillNA) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public RAbstractVector copyWithNewDimensions(int[] newDimensions) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public RVector<?> copyResizedWithDimensions(int[] newDimensions, boolean fillNA) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public RAbstractVector copyDropAttributes() {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public RVector<?> createEmptySameType(int newLength, boolean newIsComplete) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public boolean isMatrix() {
-            return false;
-        }
-
-        @Override
-        public boolean isArray() {
-            return false;
-        }
-
-        @Override
-        public boolean checkCompleteness() {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public void setComplete(boolean complete) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public boolean isComplete() {
-            return false;
-        }
-
-        @Override
-        public int getLength() {
-            return length;
-        }
-
-        @Override
-        public RAbstractContainer resize(int size) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public boolean hasDimensions() {
-            return false;
-        }
-
-        @Override
-        public int[] getDimensions() {
-            return null;
-        }
-
-        @Override
-        public void setDimensions(int[] newDimensions) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public RTypedValue getNonShared() {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public RStringVector getNames() {
-            return null;
-        }
-
-        @Override
-        public final void setNames(RStringVector newNames) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public RList getDimNames() {
-            return null;
-        }
-
-        @Override
-        public void setDimNames(RList newDimNames) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public Object getRowNames() {
-            return null;
-        }
-
-        @Override
-        public void setRowNames(RAbstractVector rowNames) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public ForeignAccess getForeignAccess() {
-            throw RInternalError.shouldNotReachHere();
-        }
-    }
-
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RandomFunctions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RandomFunctions.java
index 736cf4b3bd9700ea33d24061aa050f83024a7b2b..3c4f0e22243010090b9fbdf03ed3a7c07449fe6b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RandomFunctions.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RandomFunctions.java
@@ -47,11 +47,11 @@ public class RandomFunctions {
         }
     }
 
-    public abstract static class RandFunction1_Double extends RandFunction2_Double {
+    public abstract static class RandFunction1_Double extends RandFunction3_Double {
         public abstract double execute(double a, RandomNumberProvider rand);
 
         @Override
-        public final double execute(double a, double b, RandomNumberProvider rand) {
+        public final double execute(double a, double b, double c, RandomNumberProvider rand) {
             return execute(a, rand);
         }
     }
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 1acc54576bcaa9a82c3d37a02ccec3d8b01fa094..822b14b94a898fa8d70e1c109de5f68dc0ca177a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/distr/RMultinom.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/distr/RMultinom.java
@@ -18,7 +18,8 @@ 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.ReadAccessor;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandomNumberProvider;
 
 public final class RMultinom {
@@ -32,7 +33,7 @@ public final class RMultinom {
      * prob[j]) , sum_j rN[j] == n, sum_j prob[j] == 1.
      */
     @TruffleBoundary
-    public static boolean rmultinom(int nIn, ReadAccessor.Double prob, int maxK, int[] rN, int rnStartIdx, RandomNumberProvider rand, Rbinom rbinom) {
+    public static boolean rmultinom(int nIn, SequentialIterator probsIter, VectorAccess probsAccess, double sum, 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
@@ -40,6 +41,7 @@ public final class RMultinom {
          */
 
         int n = nIn;
+        int maxK = probsAccess.getLength(probsIter);
         if (RRuntime.isNA(maxK) || maxK < 1 || RRuntime.isNA(n) || n < 0) {
             if (rN.length > rnStartIdx) {
                 rN[rnStartIdx] = RRuntime.INT_NA;
@@ -52,8 +54,9 @@ public final class RMultinom {
          * shorter and drop that check !
          */
         /* LDOUBLE */double pTot = 0.;
-        for (int k = 0; k < maxK; k++) {
-            double pp = prob.getDataAt(k);
+        probsAccess.reset(probsIter);
+        for (int k = 0; probsAccess.next(probsIter); k++) {
+            double pp = probsAccess.getDouble(probsIter) / sum;
             if (!Double.isFinite(pp) || pp < 0. || pp > 1.) {
                 rN[rnStartIdx + k] = RRuntime.INT_NA;
                 return false;
@@ -74,9 +77,10 @@ public final class RMultinom {
         }
 
         /* Generate the first K-1 obs. via binomials */
-        for (int k = 0; k < maxK - 1; k++) {
+        probsAccess.reset(probsIter);
+        for (int k = 0; probsAccess.next(probsIter) && k < maxK - 1; k++) {
             /* (p_tot, n) are for "remaining binomial" */
-            /* LDOUBLE */double probK = prob.getDataAt(k);
+            /* LDOUBLE */double probK = probsAccess.getDouble(probsIter) / sum;
             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/BinaryArithmetic.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
index 304d26eb4bd072fc48316aab7e49328df60f87a5..b7883f38067abbca3ed847c407596f6df09b8ad6 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
@@ -124,6 +124,7 @@ public abstract class BinaryArithmetic extends Operation {
 
     public static final class Add extends BinaryArithmetic {
 
+        @CompilationFinal private boolean introducesOverflow = false;
         @CompilationFinal private boolean introducesNA = false;
 
         public Add() {
@@ -137,17 +138,22 @@ public abstract class BinaryArithmetic extends Operation {
 
         @Override
         public boolean introducesNA() {
-            return introducesNA;
+            return introducesNA || introducesOverflow;
         }
 
         @Override
         public int op(int left, int right) {
-            if (!introducesNA) {
+            if (!introducesOverflow) {
                 try {
-                    return Math.addExact(left, right);
+                    int result = Math.addExact(left, right);
+                    // NAs can also be introduced without a 32-bit overflow
+                    if (!introducesNA && result == RRuntime.INT_NA) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        introducesNA = true;
+                    }
                 } catch (ArithmeticException e) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
-                    introducesNA = true;
+                    introducesOverflow = true;
                 }
             }
             // Borrowed from ExactMath
@@ -176,6 +182,7 @@ public abstract class BinaryArithmetic extends Operation {
 
     public static final class Subtract extends BinaryArithmetic {
 
+        @CompilationFinal private boolean introducesOverflow = false;
         @CompilationFinal private boolean introducesNA = false;
 
         public Subtract() {
@@ -189,17 +196,23 @@ public abstract class BinaryArithmetic extends Operation {
 
         @Override
         public boolean introducesNA() {
-            return introducesNA;
+            return introducesNA || introducesOverflow;
         }
 
         @Override
         public int op(int left, int right) {
-            if (!introducesNA) {
+            if (!introducesOverflow) {
                 try {
-                    return Math.subtractExact(left, right);
+                    int result = Math.subtractExact(left, right);
+                    // NAs can also be introduced without a 32-bit overflow
+                    if (!introducesNA && result == RRuntime.INT_NA) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        introducesNA = true;
+                    }
+                    return result;
                 } catch (ArithmeticException e) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
-                    introducesNA = true;
+                    introducesOverflow = true;
                 }
             }
             // Borrowed from ExactMath
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java
index cbf0f6f606a1d55a6229c0d257aa2f80a02c143b..31ce4935a26c0e7554abe576565453f55d156ab9 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java
@@ -120,6 +120,17 @@ public final class NACheck {
         return false;
     }
 
+    public boolean check(double real, double imag) {
+        if (state != NO_CHECK && RRuntime.isNA(real, imag)) {
+            if (state == CHECK_DEOPT) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                state = CHECK;
+            }
+            return true;
+        }
+        return false;
+    }
+
     public void seenNA() {
         if (state != CHECK) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -161,6 +172,7 @@ public final class NACheck {
     }
 
     public boolean checkListElement(Object value) {
+        assert value != null;
         if (state != NO_CHECK && value == RNull.instance) {
             if (state == CHECK_DEOPT) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ArithmeticWhiteList.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ArithmeticWhiteList.java
index 01d39683e7544b3e00ad15e8207550334b1970f2..336127e33bc19ebae2e870a0cbcd185bb351ff44 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ArithmeticWhiteList.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ArithmeticWhiteList.java
@@ -37,7 +37,6 @@ public class ArithmeticWhiteList {
     static {
         WHITELIST.add("{ abs((-0-1i)/(0+0i)) }", "[1] NaN\n", "[1] Inf\n");
         WHITELIST.add("{ abs((-1-0i)/(0+0i)) }", "[1] NaN\n", "[1] Inf\n");
-        WHITELIST.add("{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = FALSE)}", "[1] NaN+NaNi 4.5+7.5i\n", "[1] NaN+0.0i 4.5+7.5i\n");
         WHITELIST.add("{ ((0+1i)/0) * ((0+1i)/0) }", "[1] NaN+NaNi\n", "[1] -Inf+NaNi\n");
         WHITELIST.add("{ ((0-1i)/0) * ((-1-1i)/0) }", "[1] NaN+NaNi\n", "[1] -Inf+Infi\n");
         WHITELIST.add("{ ((0-1i)/0) * ((0+1i)/0) }", "[1] NaN+NaNi\n", "[1] Inf+NaNi\n");
@@ -55,7 +54,6 @@ public class ArithmeticWhiteList {
         WHITELIST.add("{ -((0+1i)/0)  }", "[1] NaN+NaNi\n", "[1] NaN-Infi\n");
         WHITELIST.add("{ -((1+0i)/0)  }", "[1] NaN+NaNi\n", "[1] -Inf+NaNi\n");
         WHITELIST.add("{ -c((1+0i)/0,2) }", "[1] NaN+NaNi  -2+  0i\n", "[1] -Inf+NaNi   -2+  0i\n");
-        WHITELIST.add("x <- c(NaN, 3+2i); xre <- Re(x); xim <- (0+1i) * Im(x); xre + xim", "[1] NaN+NaNi   3+  2i\n", "[1] NaN+0i   3+2i\n");
         WHITELIST.add("{ c(0/0+1i,2+1i) == c(1+1i,2+1i) }", "[1] FALSE  TRUE\n", "[1]   NA TRUE\n");
         WHITELIST.add("{ c(1+1i,2+1i) == c(0/0+1i,2+1i) }", "[1] FALSE  TRUE\n", "[1]   NA TRUE\n");
         WHITELIST.add("exp(-abs((0+1i)/(0+0i)))", "[1] NaN\n", "[1] 0\n");
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 385781ccdccd1a4173badf68d4628fad73b38392..1baf7568d6d31e56b7361ec6b1a7c9ed1fc7a4e7 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -3221,6 +3221,38 @@ In anyDuplicated.default(c(1L, 2L, 1L, 1L, 3L, 2L), incomparables = "cat") :
 #anyNA(c(1, NA, 3), recursive = TRUE)
 [1] TRUE
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(1, NA))
+[1] TRUE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(1, NA), recursive = TRUE)
+[1] TRUE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = NA))
+[1] TRUE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = NA), recursive = TRUE)
+[1] TRUE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = NA, b = 'a'))
+[1] TRUE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = NA, b = 'a'), recursive = TRUE)
+[1] TRUE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = c('asdf', NA), b = 'a'))
+[1] FALSE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = c('asdf', NA), b = 'a'), recursive = TRUE)
+[1] TRUE
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
 #anyNA(list(a = c(1, 2, 3), b = 'a'))
 [1] FALSE
@@ -3229,6 +3261,10 @@ In anyDuplicated.default(c(1L, 2L, 1L, 1L, 3L, 2L), incomparables = "cat") :
 #anyNA(list(a = c(1, 2, 3), b = 'a'), recursive = TRUE)
 [1] FALSE
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = c(1, 2, 3), b = list(NA, 'a')), recursive = TRUE)
+[1] TRUE
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
 #anyNA(list(a = c(1, NA, 3), b = 'a'))
 [1] FALSE
@@ -3237,6 +3273,14 @@ In anyDuplicated.default(c(1L, 2L, 1L, 1L, 3L, 2L), incomparables = "cat") :
 #anyNA(list(a = c(1, NA, 3), b = 'a'), recursive = TRUE)
 [1] TRUE
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = c(NA, 3), b = 'a'))
+[1] FALSE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = c(NA, 3), b = 'a'), recursive = TRUE)
+[1] TRUE
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_aperm.testAperm#
 #{ a = array(1:24,c(2,3,4)); b = aperm(a); c(dim(b)[1],dim(b)[2],dim(b)[3]) }
 [1] 4 3 2
@@ -9955,6 +9999,9 @@ Error in attributes(x) <- 44 : attributes must be a list or NULL
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_attributesassign.testArgsCasts#
 #x <- 42;  attributes(x) <- NULL
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_attributesassign.testArgsCasts#
+#x <- 42;  attributes(x) <- list()
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_attributesassign.testattributesassign1#Ignored.ImplementationError#
 #argv <- list(NULL, NULL);`attributes<-`(argv[[1]],argv[[2]]);
 NULL
@@ -11395,7 +11442,7 @@ $Residuals
 #argv <- list(structure(1208822400, class = c('POSIXct', 'POSIXt')), structure(1209168000, class = c('POSIXct', 'POSIXt')));c(argv[[1]],argv[[2]]);
 [1] "2008-04-22 GMT" "2008-04-26 GMT"
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testc14#Ignored.OutputFormatting#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testc14#
 #argv <- list(`Grand mean` = structure(103.87323943662, class = 'mtable'), structure(list(N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('N', 'V:N')));c(argv[[1]],argv[[2]]);
 [[1]]
 [1] 103.8732
@@ -24892,7 +24939,7 @@ character(0)
 #argv <- list(c('1', '2', NA), 0L, '\'', 0L, FALSE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))
 [1] "'1'" "'2'" NA
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_encodeString.testencodeString10#Ignored.ImplementationError#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_encodeString.testencodeString10#
 #argv <- list('\'class\' is a reserved slot name and cannot be redefined', 0L, '\'', 0L, FALSE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))
 [1] "'\\'class\\' is a reserved slot name and cannot be redefined'"
 
@@ -24923,7 +24970,7 @@ character(0)
 #argv <- list(c('NA', 'a', 'b', 'c', 'd', NA), 0L, '', 0L, TRUE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))
 [1] "NA"   "a"    "b"    "c"    "d"    "<NA>"
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_encodeString.testencodeString7#Ignored.ImplementationError#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_encodeString.testencodeString7#
 #argv <- list('ab\bc\ndef', 0L, '', 0L, TRUE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))
 [1] "ab\\bc\\ndef"
 
@@ -28333,7 +28380,7 @@ Error: 'x' must be a character vector
 #argv <- list('Report Information on C Stack Size and Usage', 'UTF-8', '', 'byte', FALSE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))
 [1] "Report Information on C Stack Size and Usage"
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_iconv.testiconv2#Ignored.ImplementationError#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_iconv.testiconv2#
 #argv <- list('façile'   , 'latin1', 'ASCII', NA_character_, TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))
 [1] NA
 
@@ -28408,7 +28455,7 @@ character(0)
 #argv <- list(list(), 'latin1', 'ASCII', NA_character_, TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))
 character(0)
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_iconv.testiconv7#Ignored.ImplementationError#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_iconv.testiconv7#
 #argv <- list('façile'   , 'latin1', 'ASCII', '', TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))
 [1] "faile"
 
@@ -28512,7 +28559,7 @@ attr(,"Rd_tag")
 #identical(NaN, NaN, num.eq=T, single.NA=T)
 [1] TRUE
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical#Ignored.ImplementationError#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical#
 #{ f1 <- function() {}; f2 <- function() {}; identical(f1, f2) }
 [1] TRUE
 
@@ -28540,7 +28587,7 @@ attr(,"Rd_tag")
 #{ identical(1L,1) }
 [1] FALSE
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical#Ignored.ImplementationError#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical#
 #{ identical(function() 42, function() 42) }
 [1] TRUE
 
@@ -34491,7 +34538,7 @@ attr(,"class")attr(,"package")
 [1] "methods"
 
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testlist33#Ignored.OutputFormatting#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testlist33#
 #argv <- list(tables = structure(list(`Grand mean` = 103.87323943662, N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('Grand mean', 'N', 'V:N')), n = structure(list(N = structure(c(17, 18, 18, 18), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N')), `V:N` = structure(c(6, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')))), .Names = c('N', 'V:N')));list(argv[[1]],argv[[2]]);
 [[1]]
 [[1]]$`Grand mean`
@@ -39080,7 +39127,7 @@ integer(0)
 #argv <- structure(list(x = structure(c(31, NA, NA, 31), units = 'days',     class = 'difftime'), na.rm = TRUE), .Names = c('x', 'na.rm'));do.call('mean', argv)
 Time difference of 31 days
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_mean.testmean2#Ignored.ImplementationError#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_mean.testmean2#
 #argv <- list(c(0.104166666666667, 0.285714285714286, 0.285714285714286, NA)); .Internal(mean(argv[[1]]))
 [1] NA
 
@@ -45283,7 +45330,7 @@ attr(,"class")
 #argv <- list(181L, 3.14159265358979);`*`(argv[[1]],argv[[2]]);
 [1] 568.6283
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_operators.testoperators39#Ignored.OutputFormatting#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_operators.testoperators39#
 #argv <- list(structure(c(-24.5833333333333, -5.08333333333333, 10.25, 19.4166666666667), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), strata = structure('Within', .Names = 'N'), class = 'mtable'), structure(103.972222222222, class = 'mtable'));`+`(argv[[1]],argv[[2]]);
 N
    0.0cwt    0.2cwt    0.4cwt    0.6cwt
@@ -48198,105 +48245,237 @@ sex                       -1.65487 0.483    0.38527 11.74  1.0 0.00061
 frailty(id, dist = 't', c                           20.33 13.9 0.12000
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#prod()
+#prod(1)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#prod(complex())
-[1] 1+0i
+#prod(1,2,3,4)
+[1] 24
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#prod(numeric())
+#prod(1,2,3,4,na.rm=FALSE)
+[1] 24
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(1,2,3,4,na.rm=TRUE)
+[1] 24
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(1,FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(1,FALSE,na.rm=FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(1,FALSE,na.rm=TRUE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(1,na.rm=FALSE)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{ foo <- function(...) prod(...); foo(); }
+#prod(1,na.rm=TRUE)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod('a')}
-Error in prod("a") : invalid 'type' (character) of argument
+#prod(1L,NA,5+3i)
+[1] NA
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod()}
-[1] 1
+#prod(1L,NA,5+3i,na.rm=FALSE)
+[1] NA
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(2+3i,42)}
-[1] 84+126i
+#prod(1L,NA,5+3i,na.rm=TRUE)
+[1] 5+3i
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(2+3i,42+5i)}
-[1] 69+136i
+#prod(2,TRUE)
+[1] 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(2+3i,c())}
-[1] 2+3i
+#prod(2,TRUE,na.rm=FALSE)
+[1] 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(42,2+3i)}
-[1] 84+126i
+#prod(2,TRUE,na.rm=TRUE)
+[1] 2
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(4+0i,6,NA)
+[1] NA
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(NULL)}
+#prod(4+0i,6,NA,na.rm=FALSE)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(4+0i,6,NA,na.rm=TRUE)
+[1] 24+0i
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(4L)
+[1] 4
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(4L,na.rm=FALSE)
+[1] 4
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(4L,na.rm=TRUE)
+[1] 4
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(FALSE,na.rm=FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(FALSE,na.rm=TRUE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA,c(1,2,3))
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA,c(1,2,3),na.rm=FALSE)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA,c(1,2,3),na.rm=TRUE)
+[1] 6
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA_integer_)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA_integer_,na.rm=FALSE)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA_integer_,na.rm=TRUE)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c())}
+#prod(TRUE)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(),c())}
+#prod(TRUE,na.rm=FALSE)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(1+2i))}
-[1] 1+2i
+#prod(TRUE,na.rm=TRUE)
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(1,2,NA),NA)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(1,2,NA),NA,na.rm=FALSE)
+[1] NA
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(1+2i, 2+3i))}
-[1] -4+7i
+#prod(c(1,2,NA),NA,na.rm=TRUE)
+[1] 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(1+2i,1+3i,1+45i))}
-[1] -230-220i
+#prod(c(2,4))
+[1] 8
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(1,2,3,4,5))}
-[1] 120
+#prod(c(2,4),na.rm=FALSE)
+[1] 8
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(2,4))}
+#prod(c(2,4),na.rm=TRUE)
 [1] 8
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(2,4,3))}
+#prod(c(2,4,3))
 [1] 24
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(TRUE, FALSE))}
-[1] 0
+#prod(c(2,4,3),na.rm=FALSE)
+[1] 24
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(TRUE, TRUE))}
-[1] 1
+#prod(c(2,4,3),na.rm=TRUE)
+[1] 24
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(list())}
-Error in prod(list()) : invalid 'type' (list) of argument
+#prod(c(2,4,NA))
+[1] NA
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProdNa#
-#{prod(c(1,2,3,4,5,NA),FALSE)}
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(2,4,NA),na.rm=FALSE)
 [1] NA
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProdNa#
-#{prod(c(2,4,3,NA),TRUE)}
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(2,4,NA),na.rm=TRUE)
+[1] 8
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(NA,2L,4L))
 [1] NA
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProdNa#
-#{prod(c(2,4,NA))}
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(NA,2L,4L),na.rm=FALSE)
 [1] NA
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(NA,2L,4L),na.rm=TRUE)
+[1] 8
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(complex(),numeric())
+[1] 1+0i
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(complex(),numeric(),na.rm=FALSE)
+[1] 1+0i
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(complex(),numeric(),na.rm=TRUE)
+[1] 1+0i
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric())
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric(),na.rm=FALSE)
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric(),na.rm=TRUE)
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric(),numeric())
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric(),numeric(),na.rm=FALSE)
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric(),numeric(),na.rm=TRUE)
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#{ foo <- function(...) prod(...); foo(); }
+[1] 1
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testprod1#
 #argv <- list(9L);prod(argv[[1]]);
 [1] 9
@@ -48880,7 +49059,7 @@ NULL
 #range(c(T, F, NA, NA, T))
 [1] NA NA
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithLogical#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithLogical#Ignored.ReferenceError#
 #range(c(T, F, NA, NA, T), finite=T)
 [1] NA NA
 
@@ -51177,130 +51356,138 @@ logical(0)
 Levels: A B C D
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#rep_len(1L, 4L)
-[1] 1 1 1 1
-
-##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len("RepeatTest", 5) }
+#rep_len('RepeatTest', 5)
 [1] "RepeatTest" "RepeatTest" "RepeatTest" "RepeatTest" "RepeatTest"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(1, 2) }
+#rep_len(1, 2)
 [1] 1 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(1:4, 10) }
+#rep_len(1:4, 10)
  [1] 1 2 3 4 1 2 3 4 1 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(1:4, 3) }
+#rep_len(1:4, 3)
 [1] 1 2 3
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(1:4, 4) }
+#rep_len(1:4, 4)
 [1] 1 2 3 4
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(2+6i, 4) }
+#rep_len(1L, 4L)
+[1] 1 1 1 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
+#rep_len(2+6i, 4)
 [1] 2+6i 2+6i 2+6i 2+6i
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(3.14159, 3) }
+#rep_len(3.14159, 3)
 [1] 3.14159 3.14159 3.14159
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(7, "7") }
+#rep_len(4, x='text')
+[1] "text" "text" "text" "text"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
+#rep_len(7, '7')
 [1] 7 7 7 7 7 7 7
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(7, NA) }
+#rep_len(7, NA)
 Error in rep_len(7, NA) : invalid 'length.out' value
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(7, NULL) }
+#rep_len(7, NULL)
 Error in rep_len(7, NULL) : invalid 'length.out' value
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(7, c(7, 42)) }
+#rep_len(7, c(7, 42))
 Error in rep_len(7, c(7, 42)) : invalid 'length.out' value
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(7, integer()) }
+#rep_len(7, integer())
 Error in rep_len(7, integer()) : invalid 'length.out' value
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(TRUE, 2) }
+#rep_len(TRUE, 2)
 [1] TRUE TRUE
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(c(2i+3, 4+2i), 4) }
-[1] 3+2i 4+2i 3+2i 4+2i
+#rep_len(c('abcd', 'efg'), 0)
+character(0)
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ rep_len(c(3.1415, 0.8), 1) }
-[1] 3.1415
-
-##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#Output.IgnoreErrorContext#
-#{ rep_len(function() 42, 7) }
-Error in rep_len(function() 42, 7) : attempt to replicate non-vector
+#rep_len(c('abcd', 'efg'), 1)
+[1] "abcd"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ x<-as.raw(16); rep_len(x, 2) }
-[1] 10 10
+#rep_len(c('abcd', 'efg'), 14)
+ [1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"
+[11] "abcd" "efg"  "abcd" "efg"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{ x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5) }
-[1] 10 05 10 05 10
+#rep_len(c('abcd', 'efg'), 2)
+[1] "abcd" "efg"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(4, x="text")}
-[1] "text" "text" "text" "text"
+#rep_len(c('abcd', 'efg'), 7)
+[1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 0)}
-character(0)
+#rep_len(c('abcd', 'efg'), 8)
+[1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 1)}
-[1] "abcd"
+#rep_len(c(2i+3, 4+2i), 4)
+[1] 3+2i 4+2i 3+2i 4+2i
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 14)}
- [1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"
-[11] "abcd" "efg"  "abcd" "efg"
+#rep_len(c(3.1415, 0.8), 1)
+[1] 3.1415
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 2)}
-[1] "abcd" "efg"
+#rep_len(c(a=1,b=4), 4)
+[1] 1 4 1 4
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 7)}
-[1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd"
+#rep_len(expression(1,4,'foo'), 7)
+expression(1, 4, "foo", 1, 4, "foo", 1)
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(c("abcd", "efg"), 8)}
-[1] "abcd" "efg"  "abcd" "efg"  "abcd" "efg"  "abcd" "efg"
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#Output.IgnoreErrorContext#
+#rep_len(function() 42, 7)
+Error in rep_len(function() 42, 7) : attempt to replicate non-vector
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(length.out=4, "text")}
+#rep_len(length.out=4, 'text')
 [1] "text" "text" "text" "text"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(length.out=4, x=1:2)}
+#rep_len(length.out=4, x=1:2)
 [1] 1 2 1 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{rep_len(x=1:2, length.out=4)}
+#rep_len(x=1:2, length.out=4)
 [1] 1 2 1 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{x<-"text"; length.out<-4; rep_len(length.out=length.out, x=x)}
+#x<-'text'; length.out<-4; rep_len(length.out=length.out, x=x)
 [1] "text" "text" "text" "text"
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
-#{x<-"text"; length.out<-4; rep_len(x=x, length.out=length.out)}
+#x<-'text'; length.out<-4; rep_len(x=x, length.out=length.out)
 [1] "text" "text" "text" "text"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
+#x<-as.raw(16); rep_len(x, 2)
+[1] 10 10
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#
+#x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5)
+[1] 10 05 10 05 10
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_repint.testRepInt#
 #{ rep.int("a",3) }
 [1] "a" "a" "a"
@@ -51868,7 +52055,7 @@ Error: a matrix-like object is required as argument to 'row'
 #{ rowMeans(matrix(as.complex(1:6), nrow=2)) }
 [1] 3+0i 4+0i
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans#Ignored.OutputFormatting#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans#
 #{rowMeans(matrix(NA,NA,NA),TRUE)}
 Error in matrix(NA, NA, NA) : invalid 'nrow' value (too large or NA)
 
@@ -51912,11 +52099,11 @@ Error in matrix(NA, NA, NA) : invalid 'nrow' value (too large or NA)
 #{rowMeans(matrix(c(NA,NaN,NaN,NA),ncol=2,nrow=2))}
 [1]  NA NaN
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans#WhiteList.arithmetic#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans#
 #{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = FALSE)}
 [1] NaN+0.0i 4.5+7.5i
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans#WhiteList.arithmetic#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans#
 #{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = TRUE)}
 [1] 2.0+0.0i 4.5+7.5i
 
@@ -71936,7 +72123,7 @@ In sum(argv[[1]]) : integer overflow - use sum(as.numeric(.))
    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
   1.601   1.605   1.609   1.609   1.612   1.616
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_summary.testsummary1#Ignored.OutputFormatting#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_summary.testsummary1#
 #argv <- structure(list(object = structure(c(4L, 4L, 4L, 4L, 4L,     3L, 4L, 4L, 4L, 4L, 3L, 4L, 3L, 4L, 4L, 4L, 4L, 2L, 4L, 3L,     4L, 4L, 4L, 2L), .Dim = c(6L, 4L), .Dimnames = structure(list(c('25-34',     '35-44', '45-54', '55-64', '65-74', '75+'), c('0-39g/day',     '40-79', '80-119', '120+')), .Names = c('', '')), class = 'table')),     .Names = 'object');do.call('summary', argv)
 Number of cases in table: 88
 Number of factors: 2
@@ -83595,7 +83782,7 @@ Error in as.raw(1:3) %*% 1:3 :
      [,1]
 [1,]  NaN
 
-##com.oracle.truffle.r.test.library.base.TestSimpleArithmetic.testMatricesProduct#Ignored.Unknown#
+##com.oracle.truffle.r.test.library.base.TestSimpleArithmetic.testMatricesProduct#
 #{ c(1,2,NaN,NA) %*% c(1,3,3,4) }
      [,1]
 [1,]   NA
@@ -85075,7 +85262,7 @@ logical(0)
 #{ x<-c(1,2,3);x+TRUE }
 [1] 2 3 4
 
-##com.oracle.truffle.r.test.library.base.TestSimpleArithmetic.testVectorsComplex#WhiteList.arithmetic#
+##com.oracle.truffle.r.test.library.base.TestSimpleArithmetic.testVectorsComplex#
 #x <- c(NaN, 3+2i); xre <- Re(x); xim <- (0+1i) * Im(x); xre + xim
 [1] NaN+0i   3+2i
 
@@ -166856,7 +167043,7 @@ Error: the first argument must be of mode character
      [,1] [,2]
 [2,]    2    4
 
-##com.oracle.truffle.r.test.library.utils.TestUtils.testMethods#Ignored.ImplementationError#
+##com.oracle.truffle.r.test.library.utils.TestUtils.testMethods#
 #methods(plot)
  [1] plot.HoltWinters*   plot.TukeyHSD*      plot.acf*
  [4] plot.data.frame*    plot.decomposed.ts* plot.default
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java
index faeee96e0600fc36d72a1047bf8a240945ff9999..a428859a1547f0893ad37faac5c647c59bc9717e 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java
@@ -38,7 +38,18 @@ public class TestBuiltin_anyNA extends TestBase {
         assertEval("anyNA(c(1, NA, 3), recursive = TRUE)");
         assertEval("anyNA(list(a = c(1, 2, 3), b = 'a'))");
         assertEval("anyNA(list(a = c(1, NA, 3), b = 'a'))");
+        assertEval("anyNA(list(a = c('asdf', NA), b = 'a'))");
+        assertEval("anyNA(list(a = c(NA, 3), b = 'a'))");
+        assertEval("anyNA(list(a = NA, b = 'a'))");
+        assertEval("anyNA(list(a = NA))");
+        assertEval("anyNA(list(1, NA))");
+        assertEval("anyNA(list(a = c('asdf', NA), b = 'a'), recursive = TRUE)");
+        assertEval("anyNA(list(a = c(NA, 3), b = 'a'), recursive = TRUE)");
+        assertEval("anyNA(list(a = NA, b = 'a'), recursive = TRUE)");
+        assertEval("anyNA(list(a = NA), recursive = TRUE)");
+        assertEval("anyNA(list(1, NA), recursive = TRUE)");
         assertEval("anyNA(list(a = c(1, 2, 3), b = 'a'), recursive = TRUE)");
         assertEval("anyNA(list(a = c(1, NA, 3), b = 'a'), recursive = TRUE)");
+        assertEval("anyNA(list(a = c(1, 2, 3), b = list(NA, 'a')), recursive = TRUE)");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attributesassign.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attributesassign.java
index 1b6a07daec94d0ce39da1d6c7278d3da07a44deb..3da11be7a2f0ebc185db7a324e438f4158edc955 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attributesassign.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attributesassign.java
@@ -53,5 +53,6 @@ public class TestBuiltin_attributesassign extends TestBase {
     public void testArgsCasts() {
         assertEval("x <- 42;  attributes(x) <- 44");
         assertEval("x <- 42;  attributes(x) <- NULL");
+        assertEval("x <- 42;  attributes(x) <- list()");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java
index 5b22103fc953e6e333c6a485183a380fdcde63d7..7dd4697df4814f8358a53ecbcb52206a1756bd5a 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java
@@ -86,12 +86,8 @@ public class TestBuiltin_c extends TestBase {
 
     @Test
     public void testc14() {
-        // FIXME FastR does not honor setting options(digits=ndecimaldigits)
-        // First test is a simplified problem on which the second test would fail too (besides that
-        // it should work fine)
         assertEval("options(digits=4);c(0.12345678912345,0.123)");
-        assertEval(Ignored.OutputFormatting,
-                        "argv <- list(`Grand mean` = structure(103.87323943662, class = 'mtable'), structure(list(N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('N', 'V:N')));c(argv[[1]],argv[[2]]);");
+        assertEval("argv <- list(`Grand mean` = structure(103.87323943662, class = 'mtable'), structure(list(N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('N', 'V:N')));c(argv[[1]],argv[[2]]);");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_encodeString.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_encodeString.java
index 29a4623970125f5ee95b1fd6c2a7ebcf21e9d8a9..332eb05d144e7cba6890d4f3ff3ec5ec810c3b5d 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_encodeString.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_encodeString.java
@@ -39,8 +39,7 @@ public class TestBuiltin_encodeString extends TestBase {
 
     @Test
     public void testencodeString7() {
-        // FIXME No \b and \n encoding done in FastR
-        assertEval(Ignored.ImplementationError, "argv <- list('ab\\bc\\ndef', 0L, '', 0L, TRUE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
+        assertEval("argv <- list('ab\\bc\\ndef', 0L, '', 0L, TRUE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
     }
 
     @Test
@@ -55,9 +54,7 @@ public class TestBuiltin_encodeString extends TestBase {
 
     @Test
     public void testencodeString10() {
-        // FIXME No \ to \\ encoding done
-        assertEval(Ignored.ImplementationError,
-                        "argv <- list('\\\'class\\\' is a reserved slot name and cannot be redefined', 0L, '\\\'', 0L, FALSE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
+        assertEval("argv <- list('\\\'class\\\' is a reserved slot name and cannot be redefined', 0L, '\\\'', 0L, FALSE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_iconv.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_iconv.java
index 9bb79a5737fe67f7dd476bf9b6253da18a1fe47f..2f835d1662a72087ddf0588bf61708b844b29641 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_iconv.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_iconv.java
@@ -24,10 +24,7 @@ public class TestBuiltin_iconv extends TestBase {
 
     @Test
     public void testiconv2() {
-        // FIXME ç is not an ASCII char (although it's an extended ASCII char wit code==135)
-        // and NA_character_ replacement leads to whole output to become NA
-        assertEval(Ignored.ImplementationError,
-                        "argv <- list('façile'   , 'latin1', 'ASCII', NA_character_, TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))");
+        assertEval("argv <- list('façile'   , 'latin1', 'ASCII', NA_character_, TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))");
     }
 
     @Test
@@ -55,9 +52,7 @@ public class TestBuiltin_iconv extends TestBase {
 
     @Test
     public void testiconv7() {
-        // FIXME ç is not an ASCII char (although it's an extended ASCII char wit code==135)
-        // so GnuR elimination of ç character is correct.
-        assertEval(Ignored.ImplementationError, "argv <- list('façile'   , 'latin1', 'ASCII', '', TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))");
+        assertEval("argv <- list('façile'   , 'latin1', 'ASCII', '', TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java
index c5fd6055e22beaaed6ce3435a407ee714c0c02fa..ecb854a29ac5e63c7d73d1ea071155f655d4ab3c 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java
@@ -256,11 +256,8 @@ public class TestBuiltin_identical extends TestBase {
 
         // functions
 
-        // GnuR adds a srcref attribute, FastR does not, so we really can't do any comparative
-        // tests.
-        assertEval(Ignored.ImplementationError, "{ f1 <- function() {}; f2 <- function() {}; identical(f1, f2) }");
-        assertEval(Ignored.ImplementationError, "{ identical(function() 42, function() 42) }");
-
+        assertEval("{ f1 <- function() {}; f2 <- function() {}; identical(f1, f2) }");
+        assertEval("{ identical(function() 42, function() 42) }");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
index 9087339f297cad5b996b7a51b28b870a1a8cc221..7b5ffe64deb8b49683d103d3d20bccf3a60bdb27 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
@@ -187,8 +187,7 @@ public class TestBuiltin_list extends TestBase {
 
     @Test
     public void testlist33() {
-        assertEval(Ignored.OutputFormatting,
-                        "argv <- list(tables = structure(list(`Grand mean` = 103.87323943662, N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('Grand mean', 'N', 'V:N')), n = structure(list(N = structure(c(17, 18, 18, 18), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N')), `V:N` = structure(c(6, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')))), .Names = c('N', 'V:N')));list(argv[[1]],argv[[2]]);");
+        assertEval("argv <- list(tables = structure(list(`Grand mean` = 103.87323943662, N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('Grand mean', 'N', 'V:N')), n = structure(list(N = structure(c(17, 18, 18, 18), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N')), `V:N` = structure(c(6, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')))), .Names = c('N', 'V:N')));list(argv[[1]],argv[[2]]);");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_mean.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_mean.java
index e0eb250d0b058e83e9325a6a904ddeb3e76b8272..450cfba4a7e0720977f648d9cb9ffe00ea3def90 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_mean.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_mean.java
@@ -24,11 +24,7 @@ public class TestBuiltin_mean extends TestBase {
 
     @Test
     public void testmean2() {
-        // FIXME NA is returned by GnuR for NA input
-        // Expected output: [1] NA
-        // FastR output: [1] NaN
-
-        assertEval(Ignored.ImplementationError, "argv <- list(c(0.104166666666667, 0.285714285714286, 0.285714285714286, NA)); .Internal(mean(argv[[1]]))");
+        assertEval("argv <- list(c(0.104166666666667, 0.285714285714286, 0.285714285714286, NA)); .Internal(mean(argv[[1]]))");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java
index 81dafef3a6aa80aa8da0ddbd86aaca31f810d4ee..d5454e3d33b83845c5902346709a439527322809 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java
@@ -223,11 +223,7 @@ public class TestBuiltin_operators extends TestBase {
 
     @Test
     public void testoperators39() {
-        // FIXME number of digits in output:
-        // GnuR: 79.38889 98.88889 114.22222 123.38889
-        // FastR: 79.3889 98.8889 114.2222 123.3889
-        assertEval(Ignored.OutputFormatting,
-                        "argv <- list(structure(c(-24.5833333333333, -5.08333333333333, 10.25, 19.4166666666667), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), strata = structure('Within', .Names = 'N'), class = 'mtable'), structure(103.972222222222, class = 'mtable'));`+`(argv[[1]],argv[[2]]);");
+        assertEval("argv <- list(structure(c(-24.5833333333333, -5.08333333333333, 10.25, 19.4166666666667), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), strata = structure('Within', .Names = 'N'), class = 'mtable'), structure(103.972222222222, class = 'mtable'));`+`(argv[[1]],argv[[2]]);");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java
index 42a9f0ef49eb81f41d325bbc09fcefceac17ba45..387c17b835001191ea2a0c0ac737ea68aecb02c2 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java
@@ -72,36 +72,13 @@ public class TestBuiltin_prod extends TestBase {
         assertEval("argv <- list(numeric(0));prod(argv[[1]]);");
     }
 
+    private static final String[] VALUES = {"FALSE", "TRUE", "1,FALSE", "2,TRUE", "c(2,4)", "c(2,4,3)", "c(2,4,NA)", "c(NA,2L,4L)", "1", "4L", "NA_integer_", "NA,c(1,2,3)", "c(1,2,NA),NA", "1,2,3,4",
+                    "1L,NA,5+3i", "4+0i,6,NA", "numeric(),numeric()", "numeric()", "complex(),numeric()"};
+    private static final String[] OPTIONS = {"", ",na.rm=TRUE", ",na.rm=FALSE"};
+
     @Test
     public void testProd() {
-        assertEval("{prod(c(2,4))}");
-        assertEval("{prod(c(2,4,3))}");
-        assertEval("{prod(c(1,2,3,4,5))}");
-        assertEval("{prod(c(1+2i))}");
-        assertEval("{prod(c(1+2i, 2+3i))}");
-        assertEval("{prod(c(1+2i,1+3i,1+45i))}");
-        assertEval("{prod(c(TRUE, TRUE))}");
-        assertEval("{prod(c(TRUE, FALSE))}");
-        assertEval("{prod()}");
-        assertEval("{prod(NULL)}");
-        assertEval("{prod(c())}");
-        assertEval("{prod(c(),c())}");
-        assertEval("{prod(2+3i,c())}");
-        assertEval("{prod(2+3i,42+5i)}");
-        assertEval("{prod(2+3i,42)}");
-        assertEval("{prod(42,2+3i)}");
-        assertEval("{prod('a')}");
-        assertEval("{prod(list())}");
-        assertEval("prod()");
-        assertEval("prod(numeric())");
-        assertEval("prod(complex())");
+        assertEval(template("prod(%0%1)", VALUES, OPTIONS));
         assertEval("{ foo <- function(...) prod(...); foo(); }");
     }
-
-    @Test
-    public void testProdNa() {
-        assertEval("{prod(c(2,4,NA))}");
-        assertEval("{prod(c(2,4,3,NA),TRUE)}");
-        assertEval("{prod(c(1,2,3,4,5,NA),FALSE)}");
-    }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java
index a59ce3191e6d2f43d2de2af1a03be19b9cd09be0..ba33e425f1e16bf35c7a72b5e27b8a409b239a4c 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java
@@ -175,7 +175,10 @@ public class TestBuiltin_range extends TestBase {
 
     @Test
     public void testNaRmAndFiniteWithLogical() {
-        assertEval(template("range(c(T, F, NA, NA, T)%0)", OPTIONAL_ARGS));
+        assertEval("range(c(T, F, NA, NA, T))");
+        assertEval("range(c(T, F, NA, NA, T), na.rm=T)");
+        // GNU R doesn't honor "finite implies na.rm" for logical
+        assertEval(Ignored.ReferenceError, "range(c(T, F, NA, NA, T), finite=T)");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java
index 40ff969ca503f15168ab7c4249af8a2dcf3e4c33..d41b15d4fbd2c0bc8656090556a171e46fab49aa 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java
@@ -20,41 +20,43 @@ public class TestBuiltin_rep_len extends TestBase {
 
     @Test
     public void testRepLen() {
-        assertEval("{ rep_len(1, 2) }");
-        assertEval("{ rep_len(3.14159, 3) }");
-        assertEval("{ rep_len(\"RepeatTest\", 5) }");
-        assertEval("{ rep_len(2+6i, 4) }");
-        assertEval("{ rep_len(TRUE, 2) }");
-        assertEval("{ x<-as.raw(16); rep_len(x, 2) }");
-
-        assertEval("{ rep_len(1:4, 10) }");
-        assertEval("{ rep_len(1:4, 3) }");
-        assertEval("{ rep_len(1:4, 4) }");
-        assertEval("{ rep_len(c(3.1415, 0.8), 1) }");
-        assertEval("{ rep_len(c(2i+3, 4+2i), 4) }");
-        assertEval("{ x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5) }");
+        assertEval("rep_len(1, 2)");
+        assertEval("rep_len(3.14159, 3)");
+        assertEval("rep_len('RepeatTest', 5)");
+        assertEval("rep_len(2+6i, 4)");
+        assertEval("rep_len(TRUE, 2)");
+        assertEval("x<-as.raw(16); rep_len(x, 2)");
+
+        assertEval("rep_len(1:4, 10)");
+        assertEval("rep_len(1:4, 3)");
+        assertEval("rep_len(1:4, 4)");
+        assertEval("rep_len(c(3.1415, 0.8), 1)");
+        assertEval("rep_len(c(2i+3, 4+2i), 4)");
+        assertEval("x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5)");
         // cases with named arguments:
-        assertEval("{rep_len(x=1:2, length.out=4)}");
-        assertEval("{rep_len(length.out=4, x=1:2)}");
-        assertEval("{rep_len(length.out=4, \"text\")}");
-        assertEval("{rep_len(4, x=\"text\")}");
-        assertEval("{x<-\"text\"; length.out<-4; rep_len(x=x, length.out=length.out)}");
-        assertEval("{x<-\"text\"; length.out<-4; rep_len(length.out=length.out, x=x)}");
+        assertEval("rep_len(x=1:2, length.out=4)");
+        assertEval("rep_len(length.out=4, x=1:2)");
+        assertEval("rep_len(length.out=4, 'text')");
+        assertEval("rep_len(4, x='text')");
+        assertEval("x<-'text'; length.out<-4; rep_len(x=x, length.out=length.out)");
+        assertEval("x<-'text'; length.out<-4; rep_len(length.out=length.out, x=x)");
         // test string vector argument
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 7)}");
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 14)}");
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 8)}");
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 0)}");
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 1)}");
-        assertEval("{rep_len(c(\"abcd\", \"efg\"), 2)}");
-
-        assertEval(Output.IgnoreErrorContext, "{ rep_len(function() 42, 7) }");
-        assertEval("{ rep_len(7, \"7\") }");
-        assertEval("{ rep_len(7, integer()) }");
-        assertEval("{ rep_len(7, NA) }");
-        assertEval("{ rep_len(7, NULL) }");
-        assertEval("{ rep_len(7, c(7, 42)) }");
+        assertEval("rep_len(c('abcd', 'efg'), 7)");
+        assertEval("rep_len(c('abcd', 'efg'), 14)");
+        assertEval("rep_len(c('abcd', 'efg'), 8)");
+        assertEval("rep_len(c('abcd', 'efg'), 0)");
+        assertEval("rep_len(c('abcd', 'efg'), 1)");
+        assertEval("rep_len(c('abcd', 'efg'), 2)");
+
+        assertEval(Output.IgnoreErrorContext, "rep_len(function() 42, 7)");
+        assertEval("rep_len(7, '7')");
+        assertEval("rep_len(7, integer())");
+        assertEval("rep_len(7, NA)");
+        assertEval("rep_len(7, NULL)");
+        assertEval("rep_len(7, c(7, 42))");
 
         assertEval("rep_len(1L, 4L)");
+        assertEval("rep_len(c(a=1,b=4), 4)");
+        assertEval("rep_len(expression(1,4,'foo'), 7)");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowMeans.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowMeans.java
index d5c271e0c13ed4803940b4b100f82be141e3a978..b441e70b3f599494d4689fe2d0cad6d3cb9ae12b 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowMeans.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowMeans.java
@@ -12,7 +12,6 @@ package com.oracle.truffle.r.test.builtins;
 
 import org.junit.Test;
 
-import com.oracle.truffle.r.test.ArithmeticWhiteList;
 import com.oracle.truffle.r.test.TestBase;
 
 // Checkstyle: stop line length check
@@ -55,15 +54,13 @@ public class TestBuiltin_rowMeans extends TestBase {
         assertEval("{rowMeans(matrix(c(TRUE,FALSE,FALSE,NA),nrow=2,ncol=2), na.rm = TRUE)}");
         assertEval("{rowMeans(matrix(c(TRUE,FALSE,FALSE,NaN),nrow=2,ncol=2), na.rm = FALSE)}");
         assertEval("{rowMeans(matrix(c(TRUE,FALSE,FALSE,NA),nrow=2,ncol=2), na.rm = FALSE)}");
-        assertEval(ArithmeticWhiteList.WHITELIST, "{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = TRUE)}");
+        assertEval("{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = TRUE)}");
+
         // Whichever value(NA or NaN) is first in the row will be returned for that row.
         assertEval("{rowMeans(matrix(c(NA,NaN,NaN,NA),ncol=2,nrow=2))}");
 
         assertEval("{x<-matrix(c(\"1\",\"2\",\"3\",\"4\"),ncol=2);rowMeans(x)}");
-        assertEval(ArithmeticWhiteList.WHITELIST, "{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = FALSE)}");
-        // FIXME GnuR error description slightly better for matrix()
-        // Expected output: Error in matrix(NA, NA, NA) : invalid 'nrow' value (too large or NA)
-        // FastR output: Error: the dims contain missing values
-        assertEval(Ignored.OutputFormatting, "{rowMeans(matrix(NA,NA,NA),TRUE)}");
+        assertEval("{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = FALSE)}");
+        assertEval("{rowMeans(matrix(NA,NA,NA),TRUE)}");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_summary.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_summary.java
index 4005ecd53c17e83c5bade73b380d933bb474080d..8523b9af8cd6fedf523dba2a9cbdd8c67da1f8aa 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_summary.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_summary.java
@@ -20,10 +20,8 @@ public class TestBuiltin_summary extends TestBase {
 
     @Test
     public void testsummary1() {
-        // Little rounding difference 1.4189 vs. 1.419 in FastR
-        assertEval(Ignored.OutputFormatting,
-                        "argv <- structure(list(object = structure(c(4L, 4L, 4L, 4L, 4L,     3L, 4L, 4L, 4L, 4L, 3L, 4L, 3L, 4L, 4L, 4L, 4L, 2L, 4L, 3L,     4L, 4L, 4L, 2L), .Dim = c(6L, 4L), .Dimnames = structure(list(c('25-34',     '35-44', '45-54', '55-64', '65-74', '75+'), c('0-39g/day',     '40-79', '80-119', '120+')), .Names = c('', '')), class = 'table')),     .Names = 'object');" +
-                                        "do.call('summary', argv)");
+        assertEval("argv <- structure(list(object = structure(c(4L, 4L, 4L, 4L, 4L,     3L, 4L, 4L, 4L, 4L, 3L, 4L, 3L, 4L, 4L, 4L, 4L, 2L, 4L, 3L,     4L, 4L, 4L, 2L), .Dim = c(6L, 4L), .Dimnames = structure(list(c('25-34',     '35-44', '45-54', '55-64', '65-74', '75+'), c('0-39g/day',     '40-79', '80-119', '120+')), .Names = c('', '')), class = 'table')),     .Names = 'object');" +
+                        "do.call('summary', argv)");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java
index 4919034187e6c12ae1efef5f0256c975047665a3..be6e824235926015ff454a9860433841958c6413 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java
@@ -306,7 +306,7 @@ public class TestSimpleArithmetic extends TestBase {
     public void testVectorsComplex() {
         assertEval("{ 1:4+c(1,2+2i) }");
         assertEval("{ c(1,2+2i)+1:4 }");
-        assertEval(ArithmeticWhiteList.WHITELIST, "x <- c(NaN, 3+2i); xre <- Re(x); xim <- (0+1i) * Im(x); xre + xim");
+        assertEval("x <- c(NaN, 3+2i); xre <- Re(x); xim <- (0+1i) * Im(x); xre + xim");
     }
 
     @Test
@@ -475,7 +475,7 @@ public class TestSimpleArithmetic extends TestBase {
         assertEval("{ options(matprod = 'blas'); matrix(c(NaN,1,7,2,4,NA), nrow=3) %*% matrix(c(3,1,NA,2,NaN,5,6,7), nrow=2) }");
         // NaN vs. NA issue
         assertEval(Ignored.Unknown, "{ c(1,2,NA,NaN) %*% c(1,3,3,4) }");
-        assertEval(Ignored.Unknown, "{ c(1,2,NaN,NA) %*% c(1,3,3,4) }");
+        assertEval("{ c(1,2,NaN,NA) %*% c(1,3,3,4) }");
         assertEval(Ignored.Unknown, "{ c(1,2,2,3) %*% c(1,3,NA,NaN) }");
         assertEval("{ c(1,2,2,3) %*% c(1,3,NaN,NA) }");
     }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestUtils.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestUtils.java
index 9153421fab121f4303dbb47072995541e188e8bd..5c9cd054bab285c1c5f10deafb462aad5ce8d13a 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestUtils.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestUtils.java
@@ -41,8 +41,7 @@ public class TestUtils extends TestBase {
 
     @Test
     public void testMethods() {
-        // The vector of methods is not sorted alphabetically
-        assertEval(Ignored.ImplementationError, "methods(plot)");
+        assertEval("methods(plot)");
     }
 
     private static final String[] TEST_OCTSIZE_PARAMS = {"1L", "1.0", Integer.toString(Integer.MAX_VALUE), "NA", "NULL"};
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index 7676e3a4aa78314400a28ca79fc7e0cb5628b01d..768ff8b911ffa742dbf5b52e356063cc315be8b1 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -195,6 +195,7 @@ com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.jav
 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/InheritsNode.java,purdue.copyright
 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/IsFactorNode.java,purdue.copyright
+com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/SizeToOctalRawNode.java,gnu_r.core.copyright
 com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g,purdue.copyright
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypedValue.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java,gnu_r.copyright