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 f8d34c719561803502b83654cad520a4bd6ca95c..4c03ebeafe358d7a88cc8456ae5ee198783faad7 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
@@ -36,6 +36,8 @@ import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.TruffleLanguage.ContextReference;
 import com.oracle.truffle.api.dsl.UnsupportedSpecializationException;
 import com.oracle.truffle.api.frame.Frame;
+import com.oracle.truffle.api.frame.FrameSlot;
+import com.oracle.truffle.api.frame.FrameSlotKind;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.TruffleObject;
@@ -76,6 +78,7 @@ import com.oracle.truffle.r.runtime.RParserFactory;
 import com.oracle.truffle.r.runtime.RProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.ReturnException;
 import com.oracle.truffle.r.runtime.RootWithBody;
 import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
@@ -98,12 +101,15 @@ import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 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;
 import com.oracle.truffle.r.runtime.interop.R2Foreign;
 import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen;
 import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
+import com.oracle.truffle.r.runtime.rng.RRNG;
 
 /**
  * The engine for the FastR implementation. Handles parsing and evaluation. There is one instance of
@@ -152,6 +158,7 @@ final class REngine implements Engine, Engine.Timings {
         if (context.getKind() == RContext.ContextKind.SHARE_NOTHING) {
             initializeNonShared();
         }
+        initializeRNG();
     }
 
     private void initializeNonShared() {
@@ -201,6 +208,15 @@ final class REngine implements Engine, Engine.Timings {
         }
     }
 
+    private void initializeRNG() {
+        assert REnvironment.globalEnv() != null;
+        RFunction fun = context.lookupBuiltin(".fastr.set.seed");
+        ActiveBinding dotRandomSeed = new ActiveBinding(RType.Any, fun);
+        Frame frame = REnvironment.globalEnv().getFrame();
+        FrameSlot slot = FrameSlotChangeMonitor.findOrAddFrameSlot(frame.getFrameDescriptor(), RRNG.RANDOM_SEED, FrameSlotKind.Object);
+        FrameSlotChangeMonitor.setActiveBinding(frame, slot, dotRandomSeed, false, null);
+    }
+
     @Override
     public void checkAndRunStartupShutdownFunction(String name, String... args) {
         Object func = REnvironment.globalEnv().findFunction(name);
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_C.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_C.java
index 17325b33650a5e6e338a27d9e0fc71eda1a57871..8b8e778a0eb4ae4ca2fdf599791cf15688f5d483 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_C.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_C.java
@@ -41,12 +41,10 @@ public class JNI_C implements CRFFI {
         @Override
         @TruffleBoundary
         public void execute(NativeCallInfo nativeCallInfo, Object[] args, boolean hasStrings) {
-            synchronized (JNI_C.class) {
-                if (traceEnabled()) {
-                    traceDownCall(nativeCallInfo.name, args);
-                }
-                c(nativeCallInfo.address.asAddress(), args, hasStrings);
+            if (traceEnabled()) {
+                traceDownCall(nativeCallInfo.name, args);
             }
+            c(nativeCallInfo.address.asAddress(), args, hasStrings);
         }
     }
 
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_Call.java
index ee3d5222ab9ef5942554bf0221b1231271614bd5..70ad5c69a4f2269113074d15c04c06c57c013e18 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_Call.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_Call.java
@@ -52,53 +52,51 @@ public class JNI_Call implements CallRFFI {
         @Override
         @TruffleBoundary
         public Object execute(NativeCallInfo nativeCallInfo, Object[] args) {
-            synchronized (JNI_Call.class) {
-                long address = nativeCallInfo.address.asAddress();
-                Object result = null;
-                if (traceEnabled()) {
-                    traceDownCall(nativeCallInfo.name, args);
+            long address = nativeCallInfo.address.asAddress();
+            Object result = null;
+            if (traceEnabled()) {
+                traceDownCall(nativeCallInfo.name, args);
+            }
+            try {
+                switch (args.length) {
+                    case 0:
+                        result = call0(address);
+                        break;
+                    case 1:
+                        result = call1(address, args[0]);
+                        break;
+                    case 2:
+                        result = call2(address, args[0], args[1]);
+                        break;
+                    case 3:
+                        result = call3(address, args[0], args[1], args[2]);
+                        break;
+                    case 4:
+                        result = call4(address, args[0], args[1], args[2], args[3]);
+                        break;
+                    case 5:
+                        result = call5(address, args[0], args[1], args[2], args[3], args[4]);
+                        break;
+                    case 6:
+                        result = call6(address, args[0], args[1], args[2], args[3], args[4], args[5]);
+                        break;
+                    case 7:
+                        result = call7(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
+                        break;
+                    case 8:
+                        result = call8(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
+                        break;
+                    case 9:
+                        result = call9(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
+                        break;
+                    default:
+                        result = call(address, args);
+                        break;
                 }
-                try {
-                    switch (args.length) {
-                        case 0:
-                            result = call0(address);
-                            break;
-                        case 1:
-                            result = call1(address, args[0]);
-                            break;
-                        case 2:
-                            result = call2(address, args[0], args[1]);
-                            break;
-                        case 3:
-                            result = call3(address, args[0], args[1], args[2]);
-                            break;
-                        case 4:
-                            result = call4(address, args[0], args[1], args[2], args[3]);
-                            break;
-                        case 5:
-                            result = call5(address, args[0], args[1], args[2], args[3], args[4]);
-                            break;
-                        case 6:
-                            result = call6(address, args[0], args[1], args[2], args[3], args[4], args[5]);
-                            break;
-                        case 7:
-                            result = call7(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
-                            break;
-                        case 8:
-                            result = call8(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
-                            break;
-                        case 9:
-                            result = call9(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
-                            break;
-                        default:
-                            result = call(address, args);
-                            break;
-                    }
-                    return result;
-                } finally {
-                    if (traceEnabled()) {
-                        traceDownCallReturn(nativeCallInfo.name, result);
-                    }
+                return result;
+            } finally {
+                if (traceEnabled()) {
+                    traceDownCallReturn(nativeCallInfo.name, result);
                 }
             }
         }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java
index e869188edb5536668845518bb77468b88a57c634..c6a44575fbe04e3278328db0b434fb5601f18f72 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java
@@ -44,82 +44,70 @@ public class TruffleNFI_C implements CRFFI {
         @Specialization(guards = "args.length == 0")
         protected void invokeCall0(NativeCallInfo nativeCallInfo, @SuppressWarnings("unused") Object[] args, @SuppressWarnings("unused") boolean hasStrings,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                try {
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", "(): void");
-                    ForeignAccess.sendExecute(executeNode, callFunction);
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                }
+            try {
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", "(): void");
+                ForeignAccess.sendExecute(executeNode, callFunction);
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
             }
         }
 
         @Specialization(guards = "args.length == 1")
         protected void invokeCall1(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") boolean hasStrings,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                try {
-                    Object[] nargs = new Object[args.length];
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
-                    ForeignAccess.sendExecute(executeNode, callFunction, nargs[0]);
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                }
+            try {
+                Object[] nargs = new Object[args.length];
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
+                ForeignAccess.sendExecute(executeNode, callFunction, nargs[0]);
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
             }
         }
 
         @Specialization(guards = "args.length == 2")
         protected void invokeCall2(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") boolean hasStrings,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                try {
-                    Object[] nargs = new Object[args.length];
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
-                    ForeignAccess.sendExecute(executeNode, callFunction, nargs[0], nargs[1]);
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                }
+            try {
+                Object[] nargs = new Object[args.length];
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
+                ForeignAccess.sendExecute(executeNode, callFunction, nargs[0], nargs[1]);
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
             }
         }
 
         @Specialization(guards = "args.length == 3")
         protected void invokeCall3(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") boolean hasStrings,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                try {
-                    Object[] nargs = new Object[args.length];
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
-                    ForeignAccess.sendExecute(executeNode, callFunction, nargs[0], nargs[1], nargs[2]);
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                }
+            try {
+                Object[] nargs = new Object[args.length];
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
+                ForeignAccess.sendExecute(executeNode, callFunction, nargs[0], nargs[1], nargs[2]);
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
             }
         }
 
         @Specialization(guards = "args.length == 4")
         protected void invokeCall4(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") boolean hasStrings,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                try {
-                    Object[] nargs = new Object[args.length];
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
-                    ForeignAccess.sendExecute(executeNode, callFunction, nargs[0], nargs[1], nargs[2], nargs[3]);
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                }
+            try {
+                Object[] nargs = new Object[args.length];
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
+                ForeignAccess.sendExecute(executeNode, callFunction, nargs[0], nargs[1], nargs[2], nargs[3]);
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
             }
         }
 
         @Fallback
         protected void invokeCallN(@SuppressWarnings("unused") NativeCallInfo nativeCallInfo, @SuppressWarnings("unused") Object[] args, @SuppressWarnings("unused") boolean hasStrings) {
-            synchronized (TruffleNFI_Call.class) {
-                throw RInternalError.unimplemented(".C (too many args)");
-            }
+            throw RInternalError.unimplemented(".C (too many args)");
         }
 
         public static Node createExecute(int n) {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
index 4c1547d092df23ed89a23f5a5ca64df3d0070e19..2e474e0ac64cc2758b89e88eb6158a6553e539e5 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
@@ -236,178 +236,160 @@ public class TruffleNFI_Call implements CallRFFI {
         @Specialization(guards = "args.length == 0")
         protected Object invokeCall0(NativeCallInfo nativeCallInfo, Object[] args,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                Object result = null;
-                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-                try {
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", "(): object");
-                    result = ForeignAccess.sendExecute(executeNode, callFunction);
-                    return result;
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                } finally {
-                    prepareReturn(nativeCallInfo.name, result, isNullSetting);
-                }
+            Object result = null;
+            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+            try {
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", "(): object");
+                result = ForeignAccess.sendExecute(executeNode, callFunction);
+                return result;
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
+            } finally {
+                prepareReturn(nativeCallInfo.name, result, isNullSetting);
             }
         }
 
         @Specialization(guards = "args.length == 1")
         protected Object invokeCall1(NativeCallInfo nativeCallInfo, Object[] args,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                Object result = null;
-                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-                try {
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", "(object): object");
-                    result = ForeignAccess.sendExecute(executeNode, callFunction, args[0]);
-                    return result;
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                } finally {
-                    prepareReturn(nativeCallInfo.name, result, isNullSetting);
-                }
+            Object result = null;
+            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+            try {
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", "(object): object");
+                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0]);
+                return result;
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
+            } finally {
+                prepareReturn(nativeCallInfo.name, result, isNullSetting);
             }
         }
 
         @Specialization(guards = "args.length == 2")
         protected Object invokeCall2(NativeCallInfo nativeCallInfo, Object[] args,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                Object result = null;
-                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-                try {
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", "(object, object): object");
-                    result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1]);
-                    return result;
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                } finally {
-                    prepareReturn(nativeCallInfo.name, result, isNullSetting);
-                }
+            Object result = null;
+            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+            try {
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object): object");
+                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1]);
+                return result;
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
+            } finally {
+                prepareReturn(nativeCallInfo.name, result, isNullSetting);
             }
         }
 
         @Specialization(guards = "args.length == 3")
         protected Object invokeCall3(NativeCallInfo nativeCallInfo, Object[] args,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                Object result = null;
-                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-                try {
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object): object");
-                    result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1], args[2]);
-                    return result;
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                } finally {
-                    prepareReturn(nativeCallInfo.name, result, isNullSetting);
-                }
+            Object result = null;
+            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+            try {
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object): object");
+                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1], args[2]);
+                return result;
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
+            } finally {
+                prepareReturn(nativeCallInfo.name, result, isNullSetting);
             }
         }
 
         @Specialization(guards = "args.length == 4")
         protected Object invokeCall4(NativeCallInfo nativeCallInfo, Object[] args,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                Object result = null;
-                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-                try {
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object): object");
-                    result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1], args[2],
-                                    args[3]);
-                    return result;
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                } finally {
-                    prepareReturn(nativeCallInfo.name, result, isNullSetting);
-                }
+            Object result = null;
+            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+            try {
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object): object");
+                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1], args[2],
+                                args[3]);
+                return result;
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
+            } finally {
+                prepareReturn(nativeCallInfo.name, result, isNullSetting);
             }
         }
 
         @Specialization(guards = "args.length == 5")
         protected Object invokeCall5(NativeCallInfo nativeCallInfo, Object[] args,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                Object result = null;
-                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-                try {
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object): object");
-                    result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
-                                    args[2], args[3], args[4]);
-                    return result;
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                } finally {
-                    prepareReturn(nativeCallInfo.name, result, isNullSetting);
-                }
+            Object result = null;
+            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+            try {
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object): object");
+                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
+                                args[2], args[3], args[4]);
+                return result;
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
+            } finally {
+                prepareReturn(nativeCallInfo.name, result, isNullSetting);
             }
         }
 
         @Specialization(guards = "args.length == 6")
         protected Object invokeCall6(NativeCallInfo nativeCallInfo, Object[] args,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                Object result = null;
-                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-                try {
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object, object): object");
-                    result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
-                                    args[2], args[3], args[4], args[5]);
-                    return result;
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                } finally {
-                    prepareReturn(nativeCallInfo.name, result, isNullSetting);
-                }
+            Object result = null;
+            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+            try {
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object, object): object");
+                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
+                                args[2], args[3], args[4], args[5]);
+                return result;
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
+            } finally {
+                prepareReturn(nativeCallInfo.name, result, isNullSetting);
             }
         }
 
         @Specialization(guards = "args.length == 7")
         protected Object invokeCall7(NativeCallInfo nativeCallInfo, Object[] args,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                Object result = null;
-                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-                try {
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object, object, object): object");
-                    result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
-                                    args[2], args[3], args[4], args[5],
-                                    args[6]);
-                    return result;
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                } finally {
-                    prepareReturn(nativeCallInfo.name, result, isNullSetting);
-                }
+            Object result = null;
+            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+            try {
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object, object, object): object");
+                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
+                                args[2], args[3], args[4], args[5],
+                                args[6]);
+                return result;
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
+            } finally {
+                prepareReturn(nativeCallInfo.name, result, isNullSetting);
             }
         }
 
         @Specialization(guards = "args.length == 8")
         protected Object invokeCall8(NativeCallInfo nativeCallInfo, Object[] args,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            synchronized (TruffleNFI_Call.class) {
-                Object result = null;
-                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-                try {
-                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                    nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object, object, object, object): object");
-                    result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
-                                    args[2], args[3], args[4], args[5],
-                                    args[6], args[7]);
-                    return result;
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                } finally {
-                    prepareReturn(nativeCallInfo.name, result, isNullSetting);
-                }
+            Object result = null;
+            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+            try {
+                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object, object, object, object): object");
+                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
+                                args[2], args[3], args[4], args[5],
+                                args[6], args[7]);
+                return result;
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
+            } finally {
+                prepareReturn(nativeCallInfo.name, result, isNullSetting);
             }
         }
 
@@ -425,26 +407,24 @@ public class TruffleNFI_Call implements CallRFFI {
 
         @Override
         public void execute(NativeCallInfo nativeCallInfo, Object[] args) {
-            synchronized (TruffleNFI_Call.class) {
-                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-                try {
-                    switch (args.length) {
-                        case 0:
-                            TruffleObject callVoid0Function = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                            nativeCallInfo.address.asTruffleObject(), "bind", CallVoid0Sig);
-                            ForeignAccess.sendExecute(execute0Node, callVoid0Function);
-                            break;
-                        case 1:
-                            TruffleObject callVoid1Function = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                            nativeCallInfo.address.asTruffleObject(), "bind", CallVoid1Sig);
-                            ForeignAccess.sendExecute(execute1Node, callVoid1Function, args[0]);
-                            break;
-                    }
-                } catch (InteropException ex) {
-                    throw RInternalError.shouldNotReachHere(ex);
-                } finally {
-                    prepareReturn(nativeCallInfo.name, null, isNullSetting);
+            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+            try {
+                switch (args.length) {
+                    case 0:
+                        TruffleObject callVoid0Function = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                        nativeCallInfo.address.asTruffleObject(), "bind", CallVoid0Sig);
+                        ForeignAccess.sendExecute(execute0Node, callVoid0Function);
+                        break;
+                    case 1:
+                        TruffleObject callVoid1Function = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                        nativeCallInfo.address.asTruffleObject(), "bind", CallVoid1Sig);
+                        ForeignAccess.sendExecute(execute1Node, callVoid1Function, args[0]);
+                        break;
                 }
+            } catch (InteropException ex) {
+                throw RInternalError.shouldNotReachHere(ex);
+            } finally {
+                prepareReturn(nativeCallInfo.name, null, isNullSetting);
             }
         }
     }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java
index 75d9d6ee5c0736b70933c19c375dcf9ca5eb5f1a..beb97cd30e1db39d6818bdc9726038447d2d9bd8 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/FastRGridExternalLookup.java
@@ -39,7 +39,6 @@ import com.oracle.truffle.r.nodes.builtin.RInternalCodeBuiltinNode;
 import com.oracle.truffle.r.runtime.RInternalCode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 
@@ -193,6 +192,6 @@ public final class FastRGridExternalLookup {
     }
 
     private static RExternalBuiltinNode getExternalFastRGridBuiltinNode(String name) {
-        return new RInternalCodeBuiltinNode(RContext.getInstance(), "grid", RInternalCode.loadSourceRelativeTo(LInitGrid.class, "fastrGrid.R"), name);
+        return new RInternalCodeBuiltinNode("grid", RInternalCode.loadSourceRelativeTo(LInitGrid.class, "fastrGrid.R"), name);
     }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
index 7e9d9c2c63e33d6457db83931b5fd92591c2e6bf..283a18303f840f13a145e68646bccbb85737f8c6 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
@@ -12,745 +12,901 @@
 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.eq;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 
-import java.util.Arrays;
-
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.api.profiles.LoopConditionProfile;
 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.SetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctionsFactory.SetDimNamesAttributeNodeGen;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.nodes.unary.IsFactorNode;
 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.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.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.nodes.RBaseNode;
-import com.oracle.truffle.r.runtime.ops.na.NACheck;
+import com.oracle.truffle.r.runtime.nmath.RMath;
 
 /*
  * Logic derived from GNU-R, library/stats/src/cov.c
  */
 public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
+    // Checkstyle: stop method name check
 
-    private final boolean isCor;
-
-    public Covcor(boolean isCor) {
-        this.isCor = isCor;
+    private static RuntimeException error(String message) {
+        CompilerDirectives.transferToInterpreter();
+        throw RError.error(RError.SHOW_CALLER, Message.GENERIC, message);
     }
 
-    static {
-        Casts casts = new Casts(Covcor.class);
-        casts.arg(0).mustNotBeMissing().mustBe(nullValue().not(), Message.IS_NULL, "x").asDoubleVector();
-        casts.arg(1).mustNotBeMissing().asDoubleVector();
-        casts.arg(2).asIntegerVector().findFirst().mustBe(eq(4), Message.NYI, "covcor: other method than 4 not implemented.");
-        casts.arg(3).asLogicalVector().findFirst().map(toBoolean());
+    private static double ANS(double[] ans, int ncx, int i, int j) {
+        return ans[i + j * ncx];
     }
 
-    @Specialization
-    public Object call(RAbstractDoubleVector x, @SuppressWarnings("unused") RNull y, int method, boolean iskendall) {
-        return corcov(x.materialize(), null, method, iskendall, this);
+    private static void ANS(double[] ans, int ncx, int i, int j, double value) {
+        ans[i + j * ncx] = value;
     }
 
-    @Specialization
-    public Object call(RAbstractDoubleVector x, RAbstractDoubleVector y, int method, boolean iskendall) {
-        return corcov(x.materialize(), y.materialize(), method, iskendall, this);
+    private static double CLAMP(double X) {
+        return (X >= 1 ? 1 : (X <= -1 ? -1 : X));
     }
 
-    private final NACheck check = NACheck.create();
-
-    private final ConditionProfile noNAXProfile = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile noNAYProfile = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile xCompleteProfile = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile yCompleteProfile = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile bothZeroProfile = ConditionProfile.createBinaryProfile();
-    private final BranchProfile tooManyMissing = BranchProfile.create();
-    private final BranchProfile naInRes = BranchProfile.create();
-    private final BranchProfile error = BranchProfile.create();
-    private final BranchProfile warning = BranchProfile.create();
-
-    @Child private GetDimAttributeNode getDimsNode = GetDimAttributeNode.create();
-
-    private final LoopConditionProfile loopLength = LoopConditionProfile.createCountingProfile();
-
-    public RDoubleVector corcov(RDoubleVector x, RDoubleVector y, @SuppressWarnings("unused") int method, boolean iskendall, RBaseNode invokingNode) throws RError {
-
-        boolean ansmat = getDimsNode.isMatrix(x);
-        int n;
-        int ncx;
-        if (ansmat) {
-            n = nrows(x);
-            ncx = ncols(x);
-        } else {
-            n = x.getLength();
-            ncx = 1;
-        }
+    private static boolean ISNAN(double v) {
+        return Double.isNaN(v);
+    }
 
-        int ncy;
-        if (y == null) {
-            ncy = ncx;
-        } else if (getDimsNode.isMatrix(y)) {
-            if (nrows(y) != n) {
-                error.enter();
-                throw error("incompatible dimensions");
+    /*
+     * Note that "if (kendall)" and "if (cor)" are used inside a double for() loop; which makes the
+     * code better readable -- and is hopefully dealt with by a smartly optimizing compiler
+     */
+
+    /**
+     * Compute Cov(xx[], yy[]) or Cor(.,.) with n = length(xx)
+     */
+    private static void COV_PAIRWISE_BODY(double[] ans, int n, int ncx, int i, int j, double[] x, double[] y, int xx, int yy, boolean[] sd_0, boolean cor, boolean kendall) {
+        double xmean = 0, ymean = 0;
+        int nobs = 0;
+        if (!kendall) {
+            for (int k = 0; k < n; k++) {
+                if (!(ISNAN(x[xx + k]) || ISNAN(y[yy + k]))) {
+                    nobs++;
+                    xmean += x[xx + k];
+                    ymean += y[yy + k];
+                }
             }
-            ncy = ncols(y);
-            ansmat = true;
-        } else {
-            if (y.getLength() != n) {
-                error.enter();
-                throw error("incompatible dimensions");
+        } else /* kendall */
+            for (int k = 0; k < n; k++) {
+                if (!(ISNAN(x[xx + k]) || ISNAN(y[yy + k]))) {
+                    nobs++;
+                }
             }
-            ncy = 1;
-        }
 
-        // TODO adopt full use semantics
+        if (nobs >= 2) {
+            int n1 = -1;
+            double xsd = 0, ysd = 0, sum = 0;
+            if (!kendall) {
+                xmean /= nobs;
+                ymean /= nobs;
+                n1 = nobs - 1;
+            }
+            for (int k = 0; k < n; k++) {
+                if (!(ISNAN(x[xx + k]) || ISNAN(y[yy + k]))) {
+                    if (!kendall) {
+                        double xm = x[xx + k] - xmean;
+                        double ym = y[yy + k] - ymean;
+
+                        sum += xm * ym;
+                        if (cor) {
+                            xsd += xm * xm;
+                            ysd += ym * ym;
+                        }
+                    }
 
-        /* "default: complete" (easier for -Wall) */
-        boolean naFail = false;
-        boolean everything = false;
-        boolean emptyErr = true;
+                    else { /* Kendall's tau */
+                        for (n1 = 0; n1 < k; n1++) {
+                            if (!(ISNAN(x[xx + n1]) || ISNAN(y[yy + n1]))) {
+                                double xm = RMath.sign(x[xx + k] - x[xx + n1]);
+                                double ym = RMath.sign(y[yy + k] - y[yy + n1]);
 
-        // case 4: /* "everything": NAs are propagated */
-        everything = true;
-        emptyErr = false;
+                                sum += xm * ym;
+                                if (cor) {
+                                    xsd += xm * xm;
+                                    ysd += ym * ym;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if (cor) {
+                if (xsd == 0 || ysd == 0) {
+                    sd_0[0] = true;
+                    sum = RRuntime.DOUBLE_NA;
+                } else {
+                    if (!kendall) {
+                        xsd /= n1;
+                        ysd /= n1;
+                        sum /= n1;
+                    }
+                    sum /= (Math.sqrt(xsd) * Math.sqrt(ysd));
+                    sum = CLAMP(sum);
+                }
+            } else if (!kendall) {
+                sum /= n1;
+            }
 
-        if (emptyErr && x.getLength() == 0) {
-            error.enter();
-            throw error("'x' is empty");
+            ANS(ans, ncx, i, j, sum);
+        } else {
+            ANS(ans, ncx, i, j, RRuntime.DOUBLE_NA);
         }
+    }
 
-        double[] answerData = new double[ncx * ncy];
+    private static void cov_pairwise1(int n, int ncx, double[] x, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
+        for (int i = 0; i < ncx; i++) {
+            int xx = i * n;
+            for (int j = 0; j <= i; j++) {
+                int yy = j * n;
 
-        double[] xm = new double[ncx];
-        boolean sd0;
-        if (y == null) {
-            if (everything) {
-                sd0 = covNA1(n, ncx, x, xm, answerData, isCor, iskendall);
-            } else {
-                RIntVector ind = RDataFactory.createIntVector(n);
-                complete1(n, ncx, x, ind, naFail);
-                sd0 = covComplete1(n, ncx, x, xm, ind, answerData, isCor, iskendall);
-            }
-        } else {
-            double[] ym = new double[ncy];
-            if (everything) {
-                sd0 = covNA2(n, ncx, ncy, x, y, xm, ym, answerData, isCor, iskendall);
-            } else {
-                RIntVector ind = RDataFactory.createIntVector(n);
-                complete2(n, ncx, ncy, x, y, ind, naFail);
-                sd0 = covComplete2(n, ncx, ncy, x, y, xm, ym, ind, answerData, isCor, iskendall);
+                COV_PAIRWISE_BODY(ans, n, ncx, i, j, x, x, xx, yy, sd_0, cor, kendall);
+
+                ANS(ans, ncx, j, i, ANS(ans, ncx, i, j));
             }
         }
+    }
 
-        if (sd0) { /* only in cor() */
-            warning.enter();
-            RError.warning(invokingNode, RError.Message.SD_ZERO);
-        }
+    private static void cov_pairwise2(int n, int ncx, int ncy, double[] x, double[] y, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
+        for (int i = 0; i < ncx; i++) {
+            int xx = i * n;
+            for (int j = 0; j < ncy; j++) {
+                int yy = j * n;
 
-        boolean seenNA = false;
-        for (int i = 0; i < answerData.length; i++) {
-            if (RRuntime.isNA(answerData[i])) {
-                naInRes.enter();
-                seenNA = true;
-                break;
+                COV_PAIRWISE_BODY(ans, n, ncx, i, j, x, y, xx, yy, sd_0, cor, kendall);
             }
         }
-
-        RDoubleVector ans = null;
-        if (getDimsNode.isMatrix(x)) {
-            ans = RDataFactory.createDoubleVector(answerData, !seenNA, new int[]{ncx, ncy});
-        } else {
-            ans = RDataFactory.createDoubleVector(answerData, !seenNA);
-        }
-        return ans;
     }
 
-    private int ncols(RDoubleVector x) {
-        assert x.isMatrix();
-        return getDimsNode.getDimensions(x)[1];
-    }
-
-    private int nrows(RDoubleVector x) {
-        assert x.isMatrix();
-        return getDimsNode.getDimensions(x)[0];
-    }
+    /*
+     * method = "complete" or "all.obs" (only difference: na_fail): -------- -------
+     */
 
-    private void complete1(int n, int ncx, RDoubleVector x, RIntVector ind, boolean naFail) {
-        int i;
-        int j;
-        for (i = 0; i < n; i++) {
-            ind.updateDataAt(i, 1, check);
-        }
-        for (j = 0; j < ncx; j++) {
-            // z = &x[j * n];
-            for (i = 0; i < n; i++) {
-                if (Double.isNaN(x.getDataAt(j * n + i))) {
-                    if (naFail) {
-                        throw error("missing observations in cov/cor");
-                    } else {
-                        ind.updateDataAt(i, 0, check);
-                    }
+    /* This uses two passes for better accuracy */
+    private static void MEAN(int n, int ncx, double[] x, double[] xm, boolean[] ind, int nobs) {
+        /* variable means */
+        for (int i = 0; i < ncx; i++) {
+            int xx = i * n;
+            double sum = 0;
+            for (int k = 0; k < n; k++) {
+                if (ind[k]) {
+                    sum += x[xx + k];
                 }
             }
-        }
-    }
-
-    private void complete2(int n, int ncx, int ncy, RDoubleVector x, RDoubleVector y, RIntVector ind, boolean naFail) {
-        int i;
-        int j;
-        for (i = 0; i < n; i++) {
-            ind.updateDataAt(i, 1, check);
-        }
-        for (j = 0; j < ncx; j++) {
-            // z = &x[j * n];
-            for (i = 0; i < n; i++) {
-                if (Double.isNaN(x.getDataAt(j * n + i))) {
-                    if (naFail) {
-                        throw error("missing observations in cov/cor");
-                    } else {
-                        ind.updateDataAt(i, 0, check);
+            double tmp = sum / nobs;
+            if (Double.isFinite(tmp)) {
+                sum = 0;
+                for (int k = 0; k < n; k++) {
+                    if (ind[k]) {
+                        sum += (x[xx + k] - tmp);
                     }
                 }
+                tmp = tmp + sum / nobs;
             }
+            xm[i] = tmp;
         }
+    }
 
-        for (j = 0; j < ncy; j++) {
-            // z = &y[j * n];
-            for (i = 0; i < n; i++) {
-                if (Double.isNaN(y.getDataAt(j * n + i))) {
-                    if (naFail) {
-                        throw error("missing observations in cov/cor");
-                    } else {
-                        ind.updateDataAt(i, 0, check);
+    /* This uses two passes for better accuracy */
+    private static void MEAN_(int n, int ncx, double[] x, double[] xm, boolean[] has_na) {
+        /* variable means (has_na) */
+        for (int i = 0; i < ncx; i++) {
+            double tmp;
+            if (has_na[i]) {
+                tmp = RRuntime.DOUBLE_NA;
+            } else {
+                int xx = i * n;
+                double sum = 0;
+                for (int k = 0; k < n; k++) {
+                    sum += x[xx + k];
+                }
+                tmp = sum / n;
+                if (Double.isFinite(tmp)) {
+                    sum = 0;
+                    for (int k = 0; k < n; k++) {
+                        sum += (x[xx + k] - tmp);
                     }
+                    tmp = tmp + sum / n;
                 }
             }
+            xm[i] = tmp;
         }
     }
 
-    private static boolean covComplete1(int n, int ncx, RDoubleVector x, double[] xm, RIntVector indInput, double[] ans, boolean cor, boolean kendall) {
+    private static void cov_complete1(int n, int ncx, double[] x, double[] xm, boolean[] ind, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
         int n1 = -1;
-        int nobs;
-        boolean isSd0 = false;
 
         /* total number of complete observations */
-        nobs = 0;
+        int nobs = 0;
         for (int k = 0; k < n; k++) {
-            if (indInput.getDataAt(k) != 0) {
+            if (ind[k]) {
                 nobs++;
             }
         }
-        if (nobs <= 1) { /* too many missing */
-            for (int i = 0; i < ans.length; i++) {
-                ans[i] = RRuntime.DOUBLE_NA;
+        if (nobs <= 1) {/* too many missing */
+            for (int i = 0; i < ncx; i++) {
+                for (int j = 0; j < ncx; j++) {
+                    ANS(ans, ncx, i, j, RRuntime.DOUBLE_NA);
+                }
             }
-            return isSd0;
-        }
-
-        RIntVector ind = indInput;
-        if (nobs == ind.getLength()) {
-            // No values of ind are zeroed.
-            ind = null;
+            return;
         }
 
         if (!kendall) {
-            mean(x, xm, ind, n, ncx, nobs);
+            MEAN(n, ncx, x, xm, ind, nobs); /* -> xm[] */
             n1 = nobs - 1;
         }
         for (int i = 0; i < ncx; i++) {
+            int xx = i * n;
+
             if (!kendall) {
                 double xxm = xm[i];
                 for (int j = 0; j <= i; j++) {
+                    int yy = j * n;
                     double yym = xm[j];
-                    double sum = 0.0;
+                    double sum = 0;
                     for (int k = 0; k < n; k++) {
-                        if (ind == null || ind.getDataAt(k) != 0) {
-                            sum += (x.getDataAt(i * n + k) - xxm) * (x.getDataAt(j * n + k) - yym);
+                        if (ind[k]) {
+                            sum += (x[xx + k] - xxm) * (x[yy + k] - yym);
                         }
                     }
-                    double r = sum / n1;
-                    ans[i + j * ncx] = r;
-                    ans[j + i * ncx] = r;
+                    double result = sum / n1;
+                    ANS(ans, ncx, j, i, result);
+                    ANS(ans, ncx, i, j, result);
                 }
             } else { /* Kendall's tau */
-                throw new UnsupportedOperationException("kendall's unsupported");
+                for (int j = 0; j <= i; j++) {
+                    int yy = j * n;
+                    double sum = 0;
+                    for (int k = 0; k < n; k++) {
+                        if (ind[k]) {
+                            for (n1 = 0; n1 < n; n1++) {
+                                if (ind[n1]) {
+                                    sum += RMath.sign(x[xx + k] - x[xx + n1]) * RMath.sign(x[yy + k] - x[yy + n1]);
+                                }
+                            }
+                        }
+                    }
+                    ANS(ans, ncx, j, i, sum);
+                    ANS(ans, ncx, i, j, sum);
+                }
             }
         }
 
         if (cor) {
             for (int i = 0; i < ncx; i++) {
-                xm[i] = Math.sqrt(ans[i + i * ncx]);
+                xm[i] = Math.sqrt(ANS(ans, ncx, i, i));
             }
             for (int i = 0; i < ncx; i++) {
                 for (int j = 0; j < i; j++) {
+                    double result;
                     if (xm[i] == 0 || xm[j] == 0) {
-                        isSd0 = true;
-                        ans[i + j * ncx] = RRuntime.DOUBLE_NA;
-                        ans[j + i * ncx] = RRuntime.DOUBLE_NA;
+                        sd_0[0] = true;
+                        result = RRuntime.DOUBLE_NA;
                     } else {
-                        double sum = ans[i + j * ncx] / (xm[i] * xm[j]);
-                        if (sum > 1.0) {
-                            sum = 1.0;
+                        double current = ANS(ans, ncx, i, j);
+                        if (RRuntime.isNA(current)) {
+                            result = RRuntime.DOUBLE_NA;
+                        } else {
+                            result = CLAMP(current / (xm[i] * xm[j]));
                         }
-                        ans[i + j * ncx] = sum;
-                        ans[j + i * ncx] = sum;
                     }
+                    ANS(ans, ncx, j, i, result);
+                    ANS(ans, ncx, i, j, result);
                 }
-                ans[i + i * ncx] = 1.0;
+                ANS(ans, ncx, i, i, 1);
             }
         }
-
-        return isSd0;
     }
 
-    private static boolean covComplete2(int n, int ncx, int ncy, RDoubleVector x, RDoubleVector y, double[] xm, double[] ym, RIntVector indInput, double[] ans, boolean cor, boolean kendall) {
+    private static void cov_na_1(int n, int ncx, double[] x, double[] xm, boolean[] has_na, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
         int n1 = -1;
-        int nobs;
-        boolean isSd0 = false;
-
-        /* total number of complete observations */
-        nobs = 0;
-        for (int k = 0; k < n; k++) {
-            if (indInput.getDataAt(k) != 0) {
-                nobs++;
-            }
-        }
-        if (nobs <= 1) { /* too many missing */
-            for (int i = 0; i < ans.length; i++) {
-                ans[i] = RRuntime.DOUBLE_NA;
+        if (n <= 1) { /* too many missing */
+            for (int i = 0; i < ncx; i++) {
+                for (int j = 0; j < ncx; j++) {
+                    ANS(ans, ncx, i, j, RRuntime.DOUBLE_NA);
+                }
             }
-            return isSd0;
-        }
-
-        RIntVector ind = indInput;
-        if (nobs == ind.getLength()) {
-            // No values of ind are zeroed.
-            ind = null;
+            return;
         }
 
         if (!kendall) {
-            mean(x, xm, ind, n, ncx, nobs);
-            mean(y, ym, ind, n, ncy, nobs);
-            n1 = nobs - 1;
+            MEAN_(n, ncx, x, xm, has_na);/* -> xm[] */
+            n1 = n - 1;
         }
         for (int i = 0; i < ncx; i++) {
-            if (!kendall) {
-                double xxm = xm[i];
-                for (int j = 0; j < ncy; j++) {
-                    double yym = ym[j];
-                    double sum = 0;
-                    for (int k = 0; k < n; k++) {
-                        if (ind == null || ind.getDataAt(k) != 0) {
-                            sum += (x.getDataAt(i * n + k) - xxm) * (y.getDataAt(j * n + k) - yym);
+            if (has_na[i]) {
+                for (int j = 0; j <= i; j++) {
+                    ANS(ans, ncx, j, i, RRuntime.DOUBLE_NA);
+                    ANS(ans, ncx, i, j, RRuntime.DOUBLE_NA);
+                }
+            } else {
+                int xx = i * n;
+
+                if (!kendall) {
+                    double xxm = xm[i];
+                    for (int j = 0; j <= i; j++) {
+                        if (has_na[j]) {
+                            ANS(ans, ncx, j, i, RRuntime.DOUBLE_NA);
+                            ANS(ans, ncx, i, j, RRuntime.DOUBLE_NA);
+                        } else {
+                            int yy = j * n;
+                            double yym = xm[j];
+                            double sum = 0;
+                            for (int k = 0; k < n; k++) {
+                                sum += (x[xx + k] - xxm) * (x[yy + k] - yym);
+                            }
+                            double result = sum / n1;
+                            ANS(ans, ncx, j, i, result);
+                            ANS(ans, ncx, i, j, result);
+                        }
+                    }
+                } else { /* Kendall's tau */
+                    for (int j = 0; j <= i; j++) {
+                        if (has_na[j]) {
+                            ANS(ans, ncx, j, i, RRuntime.DOUBLE_NA);
+                            ANS(ans, ncx, i, j, RRuntime.DOUBLE_NA);
+                        } else {
+                            int yy = j * n;
+                            double sum = 0;
+                            for (int k = 0; k < n; k++) {
+                                for (n1 = 0; n1 < n; n1++) {
+                                    sum += RMath.sign(x[xx + k] - x[xx + n1]) * RMath.sign(x[yy + k] - x[yy + n1]);
+                                }
+                            }
+                            ANS(ans, ncx, j, i, sum);
+                            ANS(ans, ncx, i, j, sum);
                         }
                     }
-                    ans[i + j * ncx] = (sum / n1);
                 }
-            } else { /* Kendall's tau */
-                throw new UnsupportedOperationException("kendall's unsupported");
             }
         }
 
         if (cor) {
-            covsdev(x, xm, ind, n, ncx, n1, kendall); /* -> xm[.] */
-            covsdev(y, ym, ind, n, ncy, n1, kendall); /* -> ym[.] */
-
             for (int i = 0; i < ncx; i++) {
-                for (int j = 0; j < ncy; j++) {
-                    double divisor = (xm[i] * ym[j]);
-                    if (divisor == 0.0) {
-                        isSd0 = true;
-                        ans[i + j * ncx] = RRuntime.DOUBLE_NA;
-                    } else {
-                        double value = ans[i + j * ncx] / divisor;
-                        if (value > 1) {
-                            value = 1;
+                if (!has_na[i]) {
+                    xm[i] = Math.sqrt(ANS(ans, ncx, i, i));
+                }
+            }
+            for (int i = 0; i < ncx; i++) {
+                if (!has_na[i]) {
+                    for (int j = 0; j < i; j++) {
+                        double result;
+                        if (xm[i] == 0 || xm[j] == 0) {
+                            sd_0[0] = true;
+                            result = RRuntime.DOUBLE_NA;
+                        } else {
+                            double current = ANS(ans, ncx, i, j);
+                            if (RRuntime.isNA(current)) {
+                                result = RRuntime.DOUBLE_NA;
+                            } else {
+                                result = CLAMP(current / (xm[i] * xm[j]));
+                            }
                         }
-                        ans[i + j * ncx] = value;
+                        ANS(ans, ncx, j, i, result);
+                        ANS(ans, ncx, i, j, result);
                     }
                 }
+                ANS(ans, ncx, i, i, 1);
             }
         }
-        return isSd0;
     }
 
-    private static void covsdev(RDoubleVector vector, double[] vectorM, RIntVector ind, int n, int len, int n1, boolean kendall) {
-        for (int i = 0; i < len; i++) {
+    private static void COV_SDEV1(int n, int n1, int nc, double[] array, double[] m, boolean[] ind, boolean kendall) {
+        for (int i = 0; i < nc; i++) { /* Var(X[i]) */
+            int xx = i * n;
             double sum = 0;
             if (!kendall) {
-                double xxm = vectorM[i];
+                double xxm = m[i];
                 for (int k = 0; k < n; k++) {
-                    if (ind == null || ind.getDataAt(k) != 0) {
-                        double value = vector.getDataAt(i * n + k);
-                        sum += (value - xxm) * (value - xxm);
+                    if (ind[k]) {
+                        sum += (array[xx + k] - xxm) * (array[xx + k] - xxm);
                     }
                 }
                 sum /= n1;
             } else { /* Kendall's tau */
-                throw new UnsupportedOperationException("kendall's unsupported");
-            }
-            vectorM[i] = Math.sqrt(sum);
-        }
-    }
-
-    private static void mean(RDoubleVector vector, double[] vectorM, RIntVector ind, int n, int len, int nobs) {
-        /* variable means */
-        for (int i = 0; i < len; i++) {
-            double sum = 0.0;
-            for (int k = 0; k < n; k++) {
-                if (ind == null || ind.getDataAt(k) != 0) {
-                    sum += vector.getDataAt(i * n + k);
-                }
-            }
-            double tmp = sum / nobs;
-            if (!Double.isInfinite(tmp)) {
-                sum = 0.0;
                 for (int k = 0; k < n; k++) {
-                    if (ind == null || ind.getDataAt(k) != 0) {
-                        sum += (vector.getDataAt(i * n + k) - tmp);
+                    if (ind[k]) {
+                        for (int n1_ = 0; n1_ < n; n1_++) {
+                            if (ind[n1_] && array[xx + k] != array[xx + n1_]) {
+                                sum++; /* = sign(. - .)^2 */
+                            }
+                        }
                     }
                 }
-                tmp = tmp + sum / nobs;
-            }
-            vectorM[i] = tmp;
-        }
-    }
-
-    private static boolean[] findNAs(int n, int nc, RDoubleVector v) {
-        boolean[] hasNA = new boolean[nc];
-        double[] data = v.getDataWithoutCopying();
-        for (int j = 0; j < nc; j++) {
-            for (int i = 0; i < n; i++) {
-                if (Double.isNaN(data[j * n + i])) {
-                    hasNA[j] = true;
-                    break;
-                }
             }
+            m[i] = Math.sqrt(sum);
         }
-        return hasNA;
     }
 
-    private boolean covNA1(int n, int ncx, RDoubleVector x, double[] xm, double[] ans, boolean cor, boolean iskendall) {
-        double sum;
-        double xxm;
-        double yym;
+    private static void cov_complete2(int n, int ncx, int ncy, double[] x, double[] y, double[] xm, double[] ym, boolean[] ind, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
         int n1 = -1;
-        boolean sd0 = false;
 
-        double[] xData = x.getDataWithoutCopying();
-        boolean[] hasNAx = findNAs(n, ncx, x);
-
-        if (n <= 1) { /* too many missing */
-            tooManyMissing.enter();
-            Arrays.fill(ans, RRuntime.DOUBLE_NA);
-            return sd0;
+        /* total number of complete observations */
+        int nobs = 0;
+        for (int k = 0; k < n; k++) {
+            if (ind[k]) {
+                nobs++;
+            }
         }
-
-        if (!iskendall) {
-            if (xCompleteProfile.profile(x.isComplete())) {
-                meanNoNA(n, ncx, xData, xm, hasNAx);
-            } else {
-                mean(n, ncx, xData, xm, hasNAx);
+        if (nobs <= 1) {/* too many missing */
+            for (int i = 0; i < ncx; i++) {
+                for (int j = 0; j < ncy; j++) {
+                    ANS(ans, ncx, i, j, RRuntime.DOUBLE_NA);
+                }
             }
-            n1 = n - 1;
+            return;
         }
 
+        if (!kendall) {
+            MEAN(n, ncx, x, xm, ind, nobs);/* -> xm[] */
+            MEAN(n, ncy, y, ym, ind, nobs);/* -> ym[] */
+            n1 = nobs - 1;
+        }
         for (int i = 0; i < ncx; i++) {
-            double[] temp = new double[n];
-            if (noNAXProfile.profile(!hasNAx[i])) {
-                if (!iskendall) {
-                    xxm = xm[i];
-                    for (int j = 0; j <= i; j++) {
-                        double r;
-                        if (noNAXProfile.profile(!hasNAx[j])) {
-                            yym = xm[j];
-                            if (checkNAs(xxm, yym)) {
-                                r = RRuntime.DOUBLE_NA;
-                            } else {
-                                sum = 0.0;
-                                loopLength.profileCounted(n);
-                                for (int k = 0; loopLength.inject(k < n); k++) {
-                                    double u = xData[i * n + k];
-                                    double v = xData[j * n + k];
-                                    temp[k] = (u - xxm) * (v - yym);
-                                }
-                                for (int k = 0; loopLength.inject(k < n); k++) {
-                                    sum += temp[k];
+            int xx = i * n;
+            if (!kendall) {
+                double xxm = xm[i];
+                for (int j = 0; j < ncy; j++) {
+                    int yy = j * n;
+                    double yym = ym[j];
+                    double sum = 0;
+                    for (int k = 0; k < n; k++) {
+                        if (ind[k]) {
+                            sum += (x[xx + k] - xxm) * (y[yy + k] - yym);
+                        }
+                    }
+                    ANS(ans, ncx, i, j, sum / n1);
+                }
+            } else { /* Kendall's tau */
+                for (int j = 0; j < ncy; j++) {
+                    int yy = j * n;
+                    double sum = 0;
+                    for (int k = 0; k < n; k++) {
+                        if (ind[k]) {
+                            for (n1 = 0; n1 < n; n1++) {
+                                if (ind[n1]) {
+                                    sum += RMath.sign(x[xx + k] - x[xx + n1]) * RMath.sign(y[yy + k] - y[yy + n1]);
                                 }
-                                r = checkNAs(sum) ? RRuntime.DOUBLE_NA : sum / n1;
                             }
-                        } else {
-                            r = RRuntime.DOUBLE_NA;
                         }
-                        ans[j + i * ncx] = r;
-                        ans[i + j * ncx] = r;
                     }
-                } else { /* Kendall's tau */
-                    throw new UnsupportedOperationException("kendall's unsupported");
-                }
-            } else {
-                for (int j = 0; j <= i; j++) {
-                    ans[j + i * ncx] = RRuntime.DOUBLE_NA;
-                    ans[i + j * ncx] = RRuntime.DOUBLE_NA;
+                    ANS(ans, ncx, i, j, sum);
                 }
             }
         }
 
         if (cor) {
+
+            COV_SDEV1(n, n1, ncx, x, xm, ind, kendall); /* -> xm[.] */
+            COV_SDEV1(n, n1, ncy, y, ym, ind, kendall); /* -> ym[.] */
+
             for (int i = 0; i < ncx; i++) {
-                if (noNAXProfile.profile(!hasNAx[i])) {
-                    double u = ans[i + i * ncx];
-                    xm[i] = checkNAs(u) ? RRuntime.DOUBLE_NA : Math.sqrt(u);
-                }
-            }
-            for (int i = 0; i < ncx; i++) {
-                if (noNAXProfile.profile(!hasNAx[i])) {
-                    for (int j = 0; j < i; j++) {
-                        if (bothZeroProfile.profile(xm[i] == 0 || xm[j] == 0)) {
-                            sd0 = true;
-                            ans[j + i * ncx] = RRuntime.DOUBLE_NA;
-                            ans[i + j * ncx] = RRuntime.DOUBLE_NA;
+                for (int j = 0; j < ncy; j++) {
+                    double result;
+                    if (xm[i] == 0 || ym[j] == 0) {
+                        sd_0[0] = true;
+                        result = RRuntime.DOUBLE_NA;
+                    } else {
+                        double current = ANS(ans, ncx, i, j);
+                        if (RRuntime.isNA(current)) {
+                            result = RRuntime.DOUBLE_NA;
                         } else {
-                            double u = ans[i + j * ncx];
-                            double v = xm[i];
-                            double w = xm[j];
-                            sum = checkNAs(u, v, w) ? RRuntime.DOUBLE_NA : u / (v * w);
-                            if (sum > 1.0) {
-                                sum = 1.0;
-                            }
-                            ans[j + i * ncx] = sum;
-                            ans[i + j * ncx] = sum;
+                            result = CLAMP(current / (xm[i] * ym[j]));
                         }
                     }
+                    ANS(ans, ncx, i, j, result);
                 }
-                ans[i + i * ncx] = 1.0;
             }
         }
-
-        return sd0;
     }
 
-    private static void meanNoNA(int n, int ncx, double[] x, double[] xm, boolean[] hasNA) {
-        double sum;
-        double tmp;
-        /* variable means (has_na) */
-        for (int i = 0; i < ncx; i++) {
-            if (hasNA[i]) {
-                tmp = RRuntime.DOUBLE_NA;
-            } else {
-                sum = 0.0;
-                for (int k = 0; k < n; k++) {
-                    double u = x[i * n + k];
-                    sum += u;
-                }
-                tmp = sum / n;
-                if (RRuntime.isFinite(tmp)) {
-                    sum = 0.0;
+    private static void COV_SDEV2(int n, int n1, int nc, double[] array, double[] m, boolean[] has_na, boolean kendall) {
+        for (int i = 0; i < nc; i++) {
+            if (!has_na[i]) { /* Var(X[j]) */
+                int xx = i * n;
+                double sum = 0;
+                if (!kendall) {
+                    double xxm = m[i];
                     for (int k = 0; k < n; k++) {
-                        double u = x[i * n + k];
-                        sum += u - tmp;
+                        sum += (array[xx + k] - xxm) * (array[xx + k] - xxm);
                     }
-                    tmp += sum / n;
-                }
-            }
-            xm[i] = tmp;
-        }
-    }
-
-    private void mean(int n, int ncx, double[] x, double[] xm, boolean[] hasNA) {
-        double sum;
-        double tmp;
-        /* variable means (has_na) */
-        for (int i = 0; i < ncx; i++) {
-            if (hasNA[i]) {
-                tmp = RRuntime.DOUBLE_NA;
-            } else {
-                sum = 0.0;
-                for (int k = 0; k < n; k++) {
-                    double u = x[i * n + k];
-                    if (checkNAs(u)) {
-                        sum = RRuntime.DOUBLE_NA;
-                        break;
-                    }
-                    sum += u;
-                }
-                tmp = checkNAs(sum) ? RRuntime.DOUBLE_NA : sum / n;
-                if (RRuntime.isFinite(tmp)) {
-                    sum = 0.0;
+                    sum /= n1;
+                } else { /* Kendall's tau */
                     for (int k = 0; k < n; k++) {
-                        double u = x[i * n + k];
-                        if (checkNAs(u)) {
-                            sum = RRuntime.DOUBLE_NA;
-                            break;
+                        for (int n1_ = 0; n1_ < n; n1_++) {
+                            if (array[xx + k] != array[xx + n1_]) {
+                                sum++; /* = sign(. - .)^2 */
+                            }
                         }
-                        sum += u - tmp;
-                    }
-                    if (checkNAs(sum)) {
-                        tmp = RRuntime.DOUBLE_NA;
-                    } else {
-                        tmp += sum / n;
                     }
                 }
+                m[i] = Math.sqrt(sum);
             }
-            xm[i] = tmp;
         }
     }
 
-    private boolean covNA2(int n, int ncx, int ncy, RDoubleVector x, RDoubleVector y, double[] xm, double[] ym, double[] ans, boolean cor, boolean iskendall) {
-        double sum;
-        double xxm;
-        double yym;
+    private static void cov_na_2(int n, int ncx, int ncy, double[] x, double[] y, double[] xm, double[] ym, boolean[] has_na_x, boolean[] has_na_y, double[] ans, boolean[] sd_0, boolean cor,
+                    boolean kendall) {
         int n1 = -1;
-        boolean sd0 = false;
-
-        double[] xData = x.getDataWithoutCopying();
-        double[] yData = y.getDataWithoutCopying();
-        boolean[] hasNAx = findNAs(n, ncx, x);
-        boolean[] hasNAy = findNAs(n, ncy, y);
-
-        if (n <= 1) { /* too many missing */
-            tooManyMissing.enter();
+        if (n <= 1) {/* too many missing */
             for (int i = 0; i < ncx; i++) {
                 for (int j = 0; j < ncy; j++) {
-                    ans[i + j * ncx] = RRuntime.DOUBLE_NA;
+                    ANS(ans, ncx, i, j, RRuntime.DOUBLE_NA);
                 }
             }
-            return sd0;
+            return;
         }
 
-        if (!iskendall) {
-            if (xCompleteProfile.profile(x.isComplete())) {
-                meanNoNA(n, ncx, xData, xm, hasNAx);
-            } else {
-                mean(n, ncx, xData, xm, hasNAx);
-            }
-            if (yCompleteProfile.profile(y.isComplete())) {
-                meanNoNA(n, ncy, yData, ym, hasNAy);
-            } else {
-                mean(n, ncy, yData, ym, hasNAy);
-            }
+        if (!kendall) {
+            MEAN_(n, ncx, x, xm, has_na_x);/* -> xm[] */
+            MEAN_(n, ncy, y, ym, has_na_y);/* -> ym[] */
             n1 = n - 1;
         }
-
         for (int i = 0; i < ncx; i++) {
-            if (noNAXProfile.profile(!hasNAx[i])) {
-                if (!iskendall) {
-                    xxm = xm[i];
+            if (has_na_x[i]) {
+                for (int j = 0; j < ncy; j++) {
+                    ANS(ans, ncx, i, j, RRuntime.DOUBLE_NA);
+                }
+            } else {
+                int xx = i * n;
+                if (!kendall) {
+                    double xxm = xm[i];
                     for (int j = 0; j < ncy; j++) {
-                        double r;
-                        if (noNAYProfile.profile(!hasNAy[j])) {
-                            yym = ym[j];
-                            if (checkNAs(xxm, yym)) {
-                                r = RRuntime.DOUBLE_NA;
-                            } else {
-                                sum = 0.0;
-                                for (int k = 0; k < n; k++) {
-                                    double u = xData[i * n + k];
-                                    double v = yData[j * n + k];
-                                    sum += (u - xxm) * (v - yym);
-                                }
-                                r = checkNAs(sum) ? RRuntime.DOUBLE_NA : sum / n1;
-                            }
+                        if (has_na_y[j]) {
+                            ANS(ans, ncx, i, j, RRuntime.DOUBLE_NA);
                         } else {
-                            r = RRuntime.DOUBLE_NA;
+                            int yy = j * n;
+                            double yym = ym[j];
+                            double sum = 0;
+                            for (int k = 0; k < n; k++) {
+                                sum += (x[xx + k] - xxm) * (y[yy + k] - yym);
+                            }
+                            ANS(ans, ncx, i, j, sum / n1);
                         }
-                        ans[i + j * ncx] = r;
                     }
                 } else { /* Kendall's tau */
-                    throw new UnsupportedOperationException("kendall's unsupported");
-                }
-            } else {
-                for (int j = 0; j < ncy; j++) {
-                    ans[i + j * ncx] = RRuntime.DOUBLE_NA;
+                    for (int j = 0; j < ncy; j++) {
+                        if (has_na_y[j]) {
+                            ANS(ans, ncx, i, j, RRuntime.DOUBLE_NA);
+                        } else {
+                            int yy = j * n;
+                            double sum = 0;
+                            for (int k = 0; k < n; k++) {
+                                for (n1 = 0; n1 < n; n1++) {
+                                    sum += RMath.sign(x[xx + k] - x[xx + n1]) * RMath.sign(y[yy + k] - y[yy + n1]);
+                                }
+                            }
+                            ANS(ans, ncx, i, j, sum);
+                        }
+                    }
                 }
             }
         }
 
         if (cor) {
-            covsdev(n, n1, ncx, x, hasNAx, xm, iskendall);
-            covsdev(n, n1, ncy, y, hasNAy, ym, iskendall);
+
+            COV_SDEV2(n, n1, ncx, x, xm, has_na_x, kendall); /* -> xm[.] */
+            COV_SDEV2(n, n1, ncy, y, ym, has_na_y, kendall); /* -> ym[.] */
 
             for (int i = 0; i < ncx; i++) {
-                if (noNAXProfile.profile(!hasNAx[i])) {
+                if (!has_na_x[i]) {
                     for (int j = 0; j < ncy; j++) {
-                        if (noNAYProfile.profile(!hasNAy[j])) {
-                            if (xm[i] == 0.0 || ym[j] == 0.0) {
-                                sd0 = true;
-                                ans[i + j * ncx] = RRuntime.DOUBLE_NA;
+                        if (!has_na_y[j]) {
+                            double result;
+                            if (xm[i] == 0 || ym[j] == 0) {
+                                sd_0[0] = true;
+                                result = RRuntime.DOUBLE_NA;
                             } else {
-                                double u = xm[i];
-                                double v = ym[j];
-                                if (checkNAs(u, v)) {
-                                    ans[i + j * ncx] = RRuntime.DOUBLE_NA;
+                                double current = ANS(ans, ncx, i, j);
+                                if (RRuntime.isNA(current)) {
+                                    result = RRuntime.DOUBLE_NA;
                                 } else {
-                                    ans[i + j * ncx] /= u * v;
-                                }
-                                if (ans[i + j * ncx] > 1.0) {
-                                    ans[i + j * ncx] = 1.0;
+                                    result = CLAMP(current / (xm[i] * ym[j]));
                                 }
                             }
+                            ANS(ans, ncx, i, j, result);
                         }
                     }
                 }
             }
         }
+    }
+
+    /*
+     * complete[12]() returns indicator vector ind[] of complete.cases(), or --------------
+     * if(na_fail) signals error if any NA/NaN is encountered
+     */
+
+    /*
+     * This might look slightly inefficient, but it is designed to optimise paging in virtual memory
+     * systems ... (or at least that's my story, and I'm sticking to it.)
+     */
+    private static void NA_LOOP(int n, int z, double[] x, boolean[] ind, boolean na_fail) {
+        for (int i = 0; i < n; i++) {
+            if (ISNAN(x[z + i])) {
+                if (na_fail) {
+                    error("missing observations in cov/cor");
+                } else {
+                    ind[i] = false;
+                }
+            }
+        }
+    }
 
-        return sd0;
+    private static void complete1(int n, int ncx, double[] x, boolean[] ind, boolean na_fail) {
+        for (int i = 0; i < n; i++) {
+            ind[i] = true;
+        }
+        for (int j = 0; j < ncx; j++) {
+            int z = j * n;
+            NA_LOOP(n, z, x, ind, na_fail);
+        }
     }
 
-    private void covsdev(int n, int n1, int ncx, RDoubleVector x, boolean[] hasNA, double[] xm, boolean iskendall) {
-        for (int i = 0; i < ncx; i++) {
-            if (!hasNA[i]) { /* Var(X[j]) */
-                double sum = 0.0;
-                if (!iskendall) {
-                    double xxm = xm[i];
-                    if (checkNAs(xxm)) {
-                        sum = RRuntime.DOUBLE_NA;
-                    } else {
-                        for (int k = 0; k < n; k++) {
-                            double u = x.getDataAt(i * n + k);
-                            double v = x.getDataAt(i * n + k);
-                            if (checkNAs(u, v)) {
-                                sum = RRuntime.DOUBLE_NA;
-                                break;
-                            }
-                            sum += (u - xxm) * (v - xxm);
+    static void complete2(int n, int ncx, int ncy, double[] x, double[] y, boolean[] ind, boolean na_fail) {
+        complete1(n, ncx, x, ind, na_fail);
+
+        for (int j = 0; j < ncy; j++) {
+            int z = j * n;
+            NA_LOOP(n, z, y, ind, na_fail);
+        }
+    }
+
+    static void find_na_1(int n, int ncx, double[] x, boolean[] has_na) {
+        for (int j = 0; j < ncx; j++) {
+            int z = j * n;
+            has_na[j] = false;
+            for (int i = 0; i < n; i++) {
+                if (ISNAN(x[z + i])) {
+                    has_na[j] = true;
+                    break;
+                }
+            }
+        }
+    }
+
+    static void find_na_2(int n, int ncx, int ncy, double[] x, double[] y, boolean[] has_na_x, boolean[] has_na_y) {
+        find_na_1(n, ncx, x, has_na_x);
+        find_na_1(n, ncy, y, has_na_y);
+    }
+
+    /*
+     * co[vr](x, y, use = { 1, 2, 3, 4, 5 } "all.obs", "complete.obs", "pairwise.complete",
+     * "everything", "na.or.complete" kendall = TRUE/FALSE)
+     */
+    public RDoubleVector corcov(RDoubleVector x, RDoubleVector y, int method, boolean kendall) throws RError {
+        int n, ncx, ncy;
+
+        /* Arg.1: x */
+        if (isFactorX.executeIsFactor(x)) {
+            error("'x' is a factor");
+            // maybe only warning: "Calling var(x) on a factor x is deprecated and will become an
+            // error.\n Use something like 'all(duplicated(x)[-1L])' to test for a constant vector."
+        }
+        /* length check of x -- only if(empty_err) --> below */
+        int[] xDims = getDimsXNode.getDimensions(x);
+        boolean ansmat = matrixProfile.profile(GetDimAttributeNode.isMatrix(xDims));
+        if ((ansmat)) {
+            n = xDims[0];
+            ncx = xDims[1];
+        } else {
+            n = x.getLength();
+            ncx = 1;
+        }
+        /* Arg.2: y */
+        if (y == null) {/* y = x : var() */
+            ncy = ncx;
+        } else {
+            if (isFactorY.executeIsFactor(y)) {
+                error("'y' is a factor");
+                // maybe only warning: "Calling var(x) on a factor x is deprecated and will become
+                // an error.\n Use something like 'all(duplicated(x)[-1L])' to test for a constant
+                // vector."
+            }
+            int[] yDims = getDimsYNode.getDimensions(y);
+            if (GetDimAttributeNode.isMatrix(yDims)) {
+                if (yDims[0] != n) {
+                    error("incompatible dimensions");
+                }
+                ncy = yDims[1];
+                ansmat = true;
+            } else {
+                if (y.getLength() != n) {
+                    error("incompatible dimensions");
+                }
+                ncy = 1;
+            }
+        }
+
+        /* "default: complete" */
+        boolean na_fail = false;
+        boolean everything = false;
+        boolean empty_err = true;
+        boolean pair = false;
+        switch (method) {
+            case 1: /* use all : no NAs */
+                na_fail = true;
+                break;
+            case 2: /* complete */
+                /* did na.omit in R */
+                if (x.getLength() == 0) {
+                    error("no complete element pairs");
+                }
+                break;
+            case 3: /* pairwise.complete */
+                pair = true;
+                break;
+            case 4: /* "everything": NAs are propagated */
+                everything = true;
+                empty_err = false;
+                break;
+            case 5: /* "na.or.complete": NAs are propagated */
+                empty_err = false;
+                break;
+            default:
+                error("invalid 'use' (computational method)");
+        }
+        if (empty_err && x.getLength() == 0) {
+            error("'x' is empty");
+        }
+
+        double[] xData = x.getDataWithoutCopying();
+        double[] ans = new double[ncx * ncy];
+        boolean[] sd_0 = new boolean[1];
+
+        evaluate(y, kendall, isCor, n, ncx, ncy, na_fail, everything, empty_err, pair, xData, ans, sd_0);
+
+        if (sd_0[0]) { /* only in cor() */
+            warning(RError.Message.SD_ZERO);
+        }
+
+        boolean seenNA = false;
+        for (int i = 0; i < ans.length; i++) {
+            if (RRuntime.isNA(ans[i])) {
+                naInRes.enter();
+                seenNA = true;
+                break;
+            }
+        }
+
+        if (ansmat) { /* set dimnames() when applicable */
+            RList newDimNames = null;
+            if (y == null) {
+                RList dimNames = getDimsNamesXNode.getDimNames(x);
+                if (dimNames != null) {
+                    Object names = dimNames.getDataAt(1);
+                    if (names != RNull.instance) {
+                        newDimNames = RDataFactory.createList(new Object[]{names, names});
+                    }
+                }
+            } else {
+                RList dimNamesX = getDimsNamesXNode.getDimNames(x);
+                RList dimNamesY = getDimsNamesYNode.getDimNames(y);
+                Object namesX = dimNamesX.getLength() >= 2 ? dimNamesX.getDataAt(1) : RNull.instance;
+                Object namesY = dimNamesY.getLength() >= 2 ? dimNamesY.getDataAt(1) : RNull.instance;
+                if (namesX != RNull.instance || namesY != RNull.instance) {
+                    newDimNames = RDataFactory.createList(new Object[]{namesX, namesY});
+                }
+            }
+            RDoubleVector result = RDataFactory.createDoubleVector(ans, !seenNA, new int[]{ncx, ncy});
+            if (newDimNames != null) {
+                setDimNamesNode.setDimNames(result, newDimNames);
+            }
+            return result;
+        } else {
+            return RDataFactory.createDoubleVector(ans, !seenNA);
+        }
+    }
+
+    @TruffleBoundary
+    private static void evaluate(RDoubleVector y, boolean kendall, boolean cor, int n, int ncx, int ncy, boolean na_fail, boolean everything, boolean empty_err, boolean pair, double[] xData,
+                    double[] ans, boolean[] sd_0) {
+        if (y == null) {
+            if (everything) { /* NA's are propagated */
+                double[] xm = new double[ncx];
+                boolean[] ind = new boolean[ncx];
+                find_na_1(n, ncx, xData, /* --> has_na[] = */ ind);
+                cov_na_1(n, ncx, xData, xm, ind, ans, sd_0, cor, kendall);
+            } else if (!pair) { /* all | complete "var" */
+                double[] xm = new double[ncx];
+                boolean[] ind = new boolean[n];
+                complete1(n, ncx, xData, ind, na_fail);
+                cov_complete1(n, ncx, xData, xm, ind, ans, sd_0, cor, kendall);
+                if (empty_err) {
+                    boolean indany = false;
+                    for (int i = 0; i < n; i++) {
+                        if (ind[i]) {
+                            indany = true;
+                            break;
                         }
                     }
-                    if (!checkNAs(sum)) {
-                        sum /= n1;
+                    if (!indany) {
+                        error("no complete element pairs");
                     }
-                } else { /* Kendall's tau */
-                    throw new UnsupportedOperationException("kendall's unsupported");
                 }
-                xm[i] = checkNAs(sum) ? RRuntime.DOUBLE_NA : Math.sqrt(sum);
+            } else { /* pairwise "var" */
+                cov_pairwise1(n, ncx, xData, ans, sd_0, cor, kendall);
+            }
+        } else { /* Co[vr] (x, y) */
+            double[] yData = y.getDataWithoutCopying();
+            if (everything) {
+                double[] xm = new double[ncx];
+                double[] ym = new double[ncy];
+                boolean[] ind = new boolean[ncx];
+                boolean[] has_na_y = new boolean[ncy];
+                find_na_2(n, ncx, ncy, xData, yData, ind, has_na_y);
+                cov_na_2(n, ncx, ncy, xData, yData, xm, ym, ind, has_na_y, ans, sd_0, cor, kendall);
+            } else if (!pair) { /* all | complete */
+                double[] xm = new double[ncx];
+                double[] ym = new double[ncy];
+                boolean[] ind = new boolean[n];
+                complete2(n, ncx, ncy, xData, yData, ind, na_fail);
+                cov_complete2(n, ncx, ncy, xData, yData, xm, ym, ind, ans, sd_0, cor, kendall);
+                if (empty_err) {
+                    boolean indany = false;
+                    for (int i = 0; i < n; i++) {
+                        if (ind[i]) {
+                            indany = true;
+                            break;
+                        }
+                    }
+                    if (!indany) {
+                        error("no complete element pairs");
+                    }
+                }
+            } else { /* pairwise */
+                cov_pairwise2(n, ncx, ncy, xData, yData, ans, sd_0, cor, kendall);
             }
         }
     }
 
-    private RuntimeException error(String message) {
-        throw error(Message.GENERIC, message);
+    private final boolean isCor;
+
+    public Covcor(boolean isCor) {
+        this.isCor = isCor;
     }
 
-    private boolean checkNAs(double... xs) {
-        for (double x : xs) {
-            check.enable(x);
-            if (check.check(x)) {
-                return true;
-            }
-        }
-        return false;
+    static {
+        Casts casts = new Casts(Covcor.class);
+        casts.arg(0).mustNotBeMissing().mustBe(nullValue().not(), Message.IS_NULL, "x").asDoubleVector();
+        casts.arg(1).mustNotBeMissing().asDoubleVector();
+        casts.arg(2).asIntegerVector().findFirst();
+        casts.arg(3).asLogicalVector().findFirst().map(toBoolean());
     }
 
-    private boolean checkNAs(double x) {
-        check.enable(x);
-        return check.check(x);
+    @Specialization
+    public Object call(RAbstractDoubleVector x, @SuppressWarnings("unused") RNull y, int method, boolean iskendall) {
+        return corcov(x.materialize(), null, method, iskendall);
     }
+
+    @Specialization
+    public Object call(RAbstractDoubleVector x, RAbstractDoubleVector y, int method, boolean iskendall) {
+        return corcov(x.materialize(), y.materialize(), method, iskendall);
+    }
+
+    private final BranchProfile naInRes = BranchProfile.create();
+    private final ConditionProfile matrixProfile = ConditionProfile.createBinaryProfile();
+
+    @Child private GetDimAttributeNode getDimsXNode = GetDimAttributeNode.create();
+    @Child private GetDimAttributeNode getDimsYNode = GetDimAttributeNode.create();
+    @Child private GetDimNamesAttributeNode getDimsNamesXNode = GetDimNamesAttributeNode.create();
+    @Child private GetDimNamesAttributeNode getDimsNamesYNode = GetDimNamesAttributeNode.create();
+    @Child private SetDimNamesAttributeNode setDimNamesNode = SetDimNamesAttributeNodeGen.create();
+    @Child private IsFactorNode isFactorX = new IsFactorNode();
+    @Child private IsFactorNode isFactorY = new IsFactorNode();
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
index 0b7bea50bf7e33cc7c76a4dfb782b1d26091f899..39146e8235b4014f1139a75ad00cb489a2347732 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
@@ -10,7 +10,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asIntegerVector;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asIntegerVectorClosure;
 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.numericValue;
@@ -18,7 +18,6 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
@@ -56,7 +55,7 @@ public abstract class APerm extends RBuiltinNode.Arg3 {
     static {
         Casts casts = new Casts(APerm.class);
         casts.arg("a").mustNotBeNull(RError.Message.FIRST_ARG_MUST_BE_ARRAY);
-        casts.arg("perm").allowNull().mustBe(numericValue().or(stringValue()).or(complexValue())).mapIf(numericValue().or(complexValue()), asIntegerVector());
+        casts.arg("perm").allowNull().mustBe(numericValue().or(stringValue()).or(complexValue())).mapIf(numericValue().or(complexValue()), asIntegerVectorClosure());
         casts.arg("resize").mustBe(numericValue().or(logicalValue()), Message.INVALID_LOGICAL, "resize").asLogicalVector().findFirst();
     }
 
@@ -129,7 +128,7 @@ public abstract class APerm extends RBuiltinNode.Arg3 {
         for (int i = 0; i < result.getLength(); i++) {
             int pos = toPos(applyPermute(posV, perm, true), dim);
             result.transferElementSameType(i, vector, pos);
-            posV = incArray(posV, pDim);
+            incArray(posV, pDim);
         }
 
         RList dimNames = getDimNamesNode.getDimNames(vector);
@@ -219,7 +218,6 @@ public abstract class APerm extends RBuiltinNode.Arg3 {
     /**
      * Apply permute to an equal sized array.
      */
-    @TruffleBoundary
     private static int[] applyPermute(int[] a, int[] perm, boolean reverse) {
         int[] newA = a.clone();
         if (reverse) {
@@ -235,25 +233,21 @@ public abstract class APerm extends RBuiltinNode.Arg3 {
     }
 
     /**
-     * Increment a stride array.
+     * Increment a stride array. Note: First input array may be modified.
      */
-    @TruffleBoundary
-    private static int[] incArray(int[] a, int[] dim) {
-        int[] newA = a.clone();
-        for (int i = 0; i < newA.length; i++) {
-            newA[i]++;
-            if (newA[i] < dim[i]) {
+    private static void incArray(int[] a, int[] dim) {
+        for (int i = 0; i < a.length; i++) {
+            a[i]++;
+            if (a[i] < dim[i]) {
                 break;
             }
-            newA[i] = 0;
+            a[i] = 0;
         }
-        return newA;
     }
 
     /**
      * Stride array to a linear position.
      */
-    @TruffleBoundary
     private static int toPos(int[] a, int[] dim) {
         int pos = a[0];
         for (int i = 1; i < a.length; i++) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
index 50d0689a9aa446411dd26e17617ca41b4df9d3af..22761219ac9546f0177dac0fba74038d96a6fbb7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
@@ -633,6 +633,7 @@ public class BasePackage extends RBuiltinPackage {
         add(Rank.class, RankNodeGen::create);
         add(RNGFunctions.RNGkind.class, RNGFunctionsFactory.RNGkindNodeGen::create);
         add(RNGFunctions.SetSeed.class, RNGFunctionsFactory.SetSeedNodeGen::create);
+        add(RNGFunctions.FastRSetSeed.class, RNGFunctionsFactory.FastRSetSeedNodeGen::create);
         add(RVersion.class, RVersionNodeGen::create);
         add(RawFunctions.CharToRaw.class, RawFunctionsFactory.CharToRawNodeGen::create);
         add(RawFunctions.RawToChar.class, RawFunctionsFactory.RawToCharNodeGen::create);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java
index 146b768b00d6e5e06d36ed4f3d07fb6438f9ec89..0d8a7a3ed9f02a2c78dd0abb9b43c22a6bd485c0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java
@@ -33,15 +33,20 @@ import static com.oracle.truffle.r.runtime.RError.Message.UNIMPLEMENTED_TYPE_IN_
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.MODIFIES_STATE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
+import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
+import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.rng.RRNG;
 
 public class RNGFunctions {
@@ -97,6 +102,48 @@ public class RNGFunctions {
         }
     }
 
+    @RBuiltin(name = ".fastr.set.seed", visibility = OFF, kind = PRIMITIVE, parameterNames = {"data"}, behavior = MODIFIES_STATE)
+    public abstract static class FastRSetSeed extends RBuiltinNode.Arg1 {
+
+        static {
+            Casts.noCasts(FastRSetSeed.class);
+        }
+
+        @Specialization
+        @TruffleBoundary
+        protected RNull setSeed(RAbstractIntVector data) {
+            int[] arr = new int[data.getLength()];
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = data.getDataAt(i);
+            }
+            RContext.getInstance().stateRNG.currentSeeds = arr;
+            return RNull.instance;
+        }
+
+        protected boolean isSetOperation(Object param) {
+            return !(param instanceof RMissing);
+        }
+
+        @Specialization(guards = {"isSetOperation(data)"})
+        @TruffleBoundary
+        protected RNull setSeed(Object data) {
+            RContext.getInstance().stateRNG.currentSeeds = data;
+            return RNull.instance;
+        }
+
+        @Specialization
+        @TruffleBoundary
+        protected Object getSeed(@SuppressWarnings("unused") RMissing data) {
+            Object seeds = RContext.getInstance().stateRNG.currentSeeds;
+            if (seeds instanceof int[]) {
+                int[] seedsArr = (int[]) seeds;
+                return RDataFactory.createIntVector(seedsArr, RDataFactory.INCOMPLETE_VECTOR);
+            }
+            assert seeds != null;
+            return seeds;
+        }
+    }
+
     private static final class CastsHelper {
         public static void kindInteger(Casts casts, String name, Message error, Object... messageArgs) {
             casts.arg(name).mapNull(constant(RRNG.NO_KIND_CHANGE)).mustBe(numericValue(), error, messageArgs).asIntegerVector().findFirst();
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 abad492f9edd0a6c2fb3d83f0a84797ae82fcc5d..6bfbaee4764141396cf2a3c124e30af2bb92d6ab 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
@@ -22,7 +22,6 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Fallback;
 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.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNodeGen;
@@ -32,12 +31,18 @@ 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.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.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.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
@@ -54,7 +59,6 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 public abstract class Transpose extends RBuiltinNode.Arg1 {
 
     private final BranchProfile hasDimNamesProfile = BranchProfile.create();
-    private final ConditionProfile isMatrixProfile = ConditionProfile.createBinaryProfile();
 
     private final VectorLengthProfile lengthProfile = VectorLengthProfile.create();
     private final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
@@ -66,6 +70,7 @@ public abstract class Transpose extends RBuiltinNode.Arg1 {
     @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
     @Child private GetNamesAttributeNode getAxisNamesNode = GetNamesAttributeNode.create();
     @Child private GetDimAttributeNode getDimNode;
+    @Child private ReuseNonSharedNode reuseNonShared = ReuseNonSharedNode.create();
 
     static {
         Casts.noCasts(Transpose.class);
@@ -78,22 +83,20 @@ public abstract class Transpose extends RBuiltinNode.Arg1 {
         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 <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;
-        if (isMatrixProfile.profile(vector.isMatrix())) {
-            if (getDimNode == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                getDimNode = insert(GetDimAttributeNode.create());
-            }
-            int[] dims = getDimNode.getDimensions(vector);
-            firstDim = dims[0];
-            secondDim = dims[1];
-        } else {
-            firstDim = length;
-            secondDim = 1;
-        }
+        assert vector.isMatrix();
+        int[] dims = getDimensions(vector);
+        firstDim = dims[0];
+        secondDim = dims[1];
         RBaseNode.reportWork(this, length);
 
         A array = createArray.apply(length);
@@ -110,36 +113,144 @@ public abstract class Transpose extends RBuiltinNode.Arg1 {
         copyRegAttributes.execute(vector, r);
         // set new dimensions
         int[] newDim = new int[]{secondDim, firstDim};
-        putDimensions.execute(initAttributes.execute(r), RDataFactory.createIntVector(newDim, RDataFactory.COMPLETE_VECTOR));
-        // set new dim names
-        RList dimNames = getDimNamesNode.getDimNames(vector);
-        if (dimNames != null) {
-            hasDimNamesProfile.enter();
-            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);
-            putDimNames.execute(r.getAttributes(), newDimNames);
-        }
+        putNewDimensions(vector, r, newDim);
         return r;
     }
 
-    @Specialization
+    protected RVector<?> transposeSquareMatrixInPlace(RVector<?> vector, Swap swapper) {
+        int length = lengthProfile.profile(vector.getLength());
+        assert vector.isMatrix();
+        int[] dims = getDimensions(vector);
+        assert dims.length == 2;
+        assert dims[0] == dims[1];
+        int dim = dims[0];
+        RBaseNode.reportWork(this, length);
+
+        loopProfile.profileCounted(length);
+        for (int i = 0; loopProfile.inject(i < dim); i++) {
+            for (int j = 0; j < i; j++) {
+                swapper.swap(i * dim + j, j * dim + i);
+            }
+        }
+        // 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());
+        }
+        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 false;
+    }
+
+    @Specialization(guards = "isSquare(x)")
+    protected RVector<?> transposeSquare(RAbstractIntVector x) {
+        RIntVector reused = (RIntVector) reuseNonShared.execute(x).materialize();
+        int[] store = reused.getDataWithoutCopying();
+        return transposeSquareMatrixInPlace(reused, (i, j) -> {
+            int tmp = store[i];
+            store[i] = store[j];
+            store[j] = tmp;
+        });
+    }
+
+    @Specialization(guards = "isSquare(x)")
+    protected RVector<?> transposeSquare(RAbstractLogicalVector x) {
+        RLogicalVector reused = (RLogicalVector) reuseNonShared.execute(x).materialize();
+        byte[] store = reused.getDataWithoutCopying();
+        return transposeSquareMatrixInPlace(reused, (i, j) -> {
+            byte tmp = store[i];
+            store[i] = store[j];
+            store[j] = tmp;
+        });
+    }
+
+    @Specialization(guards = "isSquare(x)")
+    protected RVector<?> transposeSquare(RAbstractDoubleVector x) {
+        RDoubleVector reused = (RDoubleVector) reuseNonShared.execute(x).materialize();
+        double[] store = reused.getDataWithoutCopying();
+        return transposeSquareMatrixInPlace(reused, (i, j) -> {
+            double tmp = store[i];
+            store[i] = store[j];
+            store[j] = tmp;
+        });
+    }
+
+    @Specialization(guards = "isSquare(x)")
+    protected RVector<?> transposeSquare(RAbstractComplexVector x) {
+        RComplexVector reused = (RComplexVector) reuseNonShared.execute(x).materialize();
+        double[] store = reused.getDataWithoutCopying();
+        return transposeSquareMatrixInPlace(reused, (i, j) -> {
+            double tmpReal = store[i * 2];
+            double tmpImg = store[i * 2 + 1];
+            store[i * 2] = store[j * 2];
+            store[i * 2 + 1] = store[j * 2 + 1];
+            store[j * 2] = tmpReal;
+            store[j * 2 + 1] = tmpImg;
+        });
+    }
+
+    @Specialization(guards = "isSquare(x)")
+    protected RVector<?> transposeSquare(RAbstractStringVector x) {
+        RStringVector reused = (RStringVector) reuseNonShared.execute(x).materialize();
+        String[] store = reused.getDataWithoutCopying();
+        return transposeSquareMatrixInPlace(reused, (i, j) -> {
+            String tmp = store[i];
+            store[i] = store[j];
+            store[j] = tmp;
+        });
+    }
+
+    @Specialization(guards = "isSquare(x)")
+    protected RVector<?> transposeSquare(RAbstractListVector x) {
+        RList reused = (RList) reuseNonShared.execute(x).materialize();
+        Object[] store = reused.getDataWithoutCopying();
+        return transposeSquareMatrixInPlace(reused, (i, j) -> {
+            Object tmp = store[i];
+            store[i] = store[j];
+            store[j] = tmp;
+        });
+    }
+
+    @Specialization(guards = "isSquare(x)")
+    protected RVector<?> transposeSquare(RAbstractRawVector x) {
+        RRawVector reused = (RRawVector) reuseNonShared.execute(x).materialize();
+        byte[] store = reused.getDataWithoutCopying();
+        return transposeSquareMatrixInPlace(reused, (i, j) -> {
+            byte tmp = store[i];
+            store[i] = store[j];
+            store[j] = tmp;
+        });
+    }
+
+    @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
+    @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
+    @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
+    @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);
@@ -148,21 +259,48 @@ public abstract class Transpose extends RBuiltinNode.Arg1 {
         }, RDataFactory::createComplexVector);
     }
 
-    @Specialization
+    @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
+    @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
+    @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(guards = "!x.isMatrix()")
+    protected RVector<?> transpose(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) {
+        putDimensions.execute(initAttributes.execute(dest), RDataFactory.createIntVector(newDim, RDataFactory.COMPLETE_VECTOR));
+        putNewDimNames(source, dest);
+    }
+
+    private void putNewDimNames(RAbstractVector source, RVector<?> dest) {
+        // set new dim names
+        RList dimNames = getDimNamesNode.getDimNames(source);
+        if (dimNames != null) {
+            hasDimNamesProfile.enter();
+            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);
+            putDimNames.execute(dest.getAttributes(), newDimNames);
+        }
+    }
+
     @Fallback
     protected RVector<?> transpose(@SuppressWarnings("unused") Object x) {
         throw error(Message.ARGUMENT_NOT_MATRIX);
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 2eb33a9b1299a8e003ef3c6a189b701c63599768..5960ab3be7d4a1c7c74fe33c98b62aaaadeebfec 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
@@ -62,12 +62,12 @@ import com.oracle.truffle.r.library.tools.ToolsTextFactory.DoTabExpandNodeGen;
 import com.oracle.truffle.r.library.utils.CountFieldsNodeGen;
 import com.oracle.truffle.r.library.utils.Crc64NodeGen;
 import com.oracle.truffle.r.library.utils.DownloadNodeGen;
-import com.oracle.truffle.r.library.utils.UnzipNodeGen;
 import com.oracle.truffle.r.library.utils.MenuNodeGen;
 import com.oracle.truffle.r.library.utils.ObjectSizeNodeGen;
 import com.oracle.truffle.r.library.utils.RprofNodeGen;
 import com.oracle.truffle.r.library.utils.RprofmemNodeGen;
 import com.oracle.truffle.r.library.utils.TypeConvertNodeGen;
+import com.oracle.truffle.r.library.utils.UnzipNodeGen;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RInternalCodeBuiltinNode;
 import com.oracle.truffle.r.nodes.objects.GetPrimNameNodeGen;
@@ -581,7 +581,7 @@ public class CallAndExternalFunctions {
                     return getExternalModelBuiltinNode("updateform");
 
                 case "Cdqrls":
-                    return new RInternalCodeBuiltinNode(RContext.getInstance(), "stats", RInternalCode.loadSourceRelativeTo(RandFunctionsNodes.class, "lm.R"), "Cdqrls");
+                    return new RInternalCodeBuiltinNode("stats", RInternalCode.loadSourceRelativeTo(RandFunctionsNodes.class, "lm.R"), "Cdqrls");
 
                 case "dnorm":
                     return StatsFunctionsNodes.Function3_1Node.create(new DNorm());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java
index 40e7c89190b120ecd29164dbe0d3adeb38019c92..881a395fcde021c36f781208e3960553207e47c7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java
@@ -39,7 +39,6 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalCode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -173,7 +172,7 @@ abstract class LookupAdapter extends RBuiltinNode.Arg3 implements Lookup {
     }
 
     protected static RExternalBuiltinNode getExternalModelBuiltinNode(String name) {
-        return new RInternalCodeBuiltinNode(RContext.getInstance(), "stats", RInternalCode.loadSourceRelativeTo(RandFunctionsNodes.class, "model.R"), name);
+        return new RInternalCodeBuiltinNode("stats", RInternalCode.loadSourceRelativeTo(RandFunctionsNodes.class, "model.R"), name);
     }
 
     protected static final int CallNST = DLL.NativeSymbolType.Call.ordinal();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
index 1fec8cd3b23c6b2290daafc56f8784015f74b0b5..08dc511069deb09535a9407207f0a7d224cb8414 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
@@ -140,16 +140,26 @@ public class FastRContext {
             EvalThread[] threads = new EvalThread[length];
             int[] data = new int[length];
             int[] multiSlotIndices = new int[length];
+
+            // first, create context infos
+            ChildContextInfo[] childContextInfos = new ChildContextInfo[length];
             for (int i = 0; i < length; i++) {
-                ChildContextInfo info = createContextInfo(contextKind);
-                threads[i] = new EvalThread(RContext.getInstance().threads, info, RSource.fromTextInternalInvisible(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL),
-                                FastROptions.SpawnUsesPolyglot.getBooleanValue());
-                data[i] = info.getId();
-                multiSlotIndices[i] = info.getMultiSlotInd();
+                childContextInfos[i] = createContextInfo(contextKind);
+                data[i] = childContextInfos[i].getId();
+                multiSlotIndices[i] = childContextInfos[i].getMultiSlotInd();
             }
+
+            // convert shared slots to multi slots
             if (contextKind == ContextKind.SHARE_ALL) {
                 REnvironment.convertSearchpathToMultiSlot(multiSlotIndices);
             }
+
+            // create eval threads which may already set values to shared slots
+            for (int i = 0; i < length; i++) {
+                threads[i] = new EvalThread(RContext.getInstance().threads, childContextInfos[i],
+                                RSource.fromTextInternalInvisible(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL),
+                                FastROptions.SpawnUsesPolyglot.getBooleanValue());
+            }
             for (int i = 0; i < length; i++) {
                 threads[i].start();
             }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java
index e699b28a722a88eee6ce7197b16fa856e64056bb..25dd64ff7977d1cae004fd2689f1500d9070ecc8 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java
@@ -165,12 +165,14 @@ abstract class BaseWriteVariableNode extends WriteVariableNode {
      * @param value The value to set.
      * @param frameSlot The frame slot of the value.
      * @param invalidateProfile The invalidation profile.
+     * @param mode
+     * @param storedObjectProfile
      */
-    protected static Object handleActiveBinding(VirtualFrame execFrame, Frame lookupFrame, Object value, FrameSlot frameSlot, BranchProfile invalidateProfile,
-                    ConditionProfile isActiveBindingProfile) {
+    protected Object handleActiveBinding(VirtualFrame execFrame, Frame lookupFrame, Object value, FrameSlot frameSlot, BranchProfile invalidateProfile,
+                    ConditionProfile isActiveBindingProfile, ValueProfile storedObjectProfile, Mode mode) {
         Object object;
         try {
-            object = lookupFrame.getObject(frameSlot);
+            object = FrameSlotChangeMonitor.getObject(frameSlot, lookupFrame);
         } catch (FrameSlotTypeException e) {
             object = null;
         }
@@ -178,7 +180,8 @@ abstract class BaseWriteVariableNode extends WriteVariableNode {
         if (isActiveBindingProfile.profile(object != null && ActiveBinding.isActiveBinding(object))) {
             return ((ActiveBinding) object).writeValue(value);
         } else {
-            FrameSlotChangeMonitor.setObjectAndInvalidate(lookupFrame, frameSlot, value, false, invalidateProfile);
+            Object newValue = shareObjectValue(lookupFrame, frameSlot, storedObjectProfile.profile(value), mode, false);
+            FrameSlotChangeMonitor.setObjectAndInvalidate(lookupFrame, frameSlot, newValue, false, invalidateProfile);
         }
         return value;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java
index 86d28f126c57d23da16604efa3726315ee20d2fd..58f07b278db0aeecb981f7d3c5d9772d348343d0 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java
@@ -102,7 +102,7 @@ public abstract class WriteLocalFrameVariableNode extends BaseWriteVariableNode
             FrameSlotChangeMonitor.setObjectAndInvalidate(frame, frameSlot, newValue, false, invalidateProfile);
         } else {
             // it's a local variable lookup; so use 'frame' for both, executing and looking up
-            return handleActiveBinding(frame, frame, value, frameSlot, invalidateProfile, isActiveBindingProfile);
+            return handleActiveBinding(frame, frame, value, frameSlot, invalidateProfile, isActiveBindingProfile, storedObjectProfile, mode);
         }
         return value;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperFrameVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperFrameVariableNode.java
index a389e83a421b23979dea86644709a63e9e5aa1a1..90f278cc2dd0b4fed1799c3b25bbf719138274c3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperFrameVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperFrameVariableNode.java
@@ -111,7 +111,7 @@ abstract class WriteSuperFrameVariableNode extends BaseWriteVariableNode {
                 Object newValue = shareObjectValue(profiledFrame, frameSlot, storedObjectProfile.profile(value), mode, true);
                 FrameSlotChangeMonitor.setObjectAndInvalidate(profiledFrame, frameSlot, newValue, true, invalidateProfile);
             } else {
-                handleActiveBinding(frame, profiledFrame, value, frameSlot, invalidateProfile, isActiveBindingProfile);
+                handleActiveBinding(frame, profiledFrame, value, frameSlot, invalidateProfile, isActiveBindingProfile, storedObjectProfile, mode);
             }
         }
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
index 5b9aa4568a6e5ed0f5ea01ef1c78fa11fbe08479..3db82a9b2c9413691c66c98adcb2397232c94c56 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
@@ -575,18 +575,17 @@ public final class ReadVariableNode extends RBaseNode {
         LookupResult lookup = FrameSlotChangeMonitor.lookup(variableFrame, identifier);
         if (lookup != null) {
             try {
-                if (lookup.getValue() instanceof RPromise) {
-                    evalPromiseSlowPathWithName(identifierAsString, frame, (RPromise) lookup.getValue());
+                Object value = lookup.getValue();
+                if (value instanceof RPromise) {
+                    evalPromiseSlowPathWithName(identifierAsString, frame, (RPromise) value);
                 }
-                if (lookup != null) {
-                    if (lookup instanceof FrameAndSlotLookupResult) {
-                        if (checkTypeSlowPath(frame, lookup.getValue())) {
-                            return new FrameAndSlotLookupLevel((FrameAndSlotLookupResult) lookup);
-                        }
-                    } else {
-                        if (lookup.getValue() == null || checkTypeSlowPath(frame, lookup.getValue())) {
-                            return new LookupLevel(lookup);
-                        }
+                if (lookup instanceof FrameAndSlotLookupResult) {
+                    if (checkTypeSlowPath(frame, value)) {
+                        return new FrameAndSlotLookupLevel((FrameAndSlotLookupResult) lookup);
+                    }
+                } else {
+                    if (value == null || checkTypeSlowPath(frame, value)) {
+                        return new LookupLevel(lookup);
                     }
                 }
             } catch (InvalidAssumptionException e) {
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 db90dae6c50d38ff99d11dd4e0073fa4f1846018..71a7e7c7183b7deb12ec8bcccd4e06d9167c3026 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
@@ -243,7 +243,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
         }
 
         if (!isList() && value instanceof RAbstractVector) {
-            value = ((RAbstractVector) value).castSafe(castType, valueIsNA);
+            value = ((RAbstractVector) value).castSafe(castType, valueIsNA, false);
         }
 
         vector = share(vector, value);
@@ -352,7 +352,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
         if (castType == RType.List) {
             return CastListNodeGen.create(true, false, true);
         } else {
-            return CastTypeNode.createCast(castType, true, true, true);
+            return CastTypeNode.createCast(castType, true, true, true, false);
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
index 65e0a251a686ca0150292f619be37dd2f3af7466..144f9715275a59198d1cb573a887ef75bcf9c106 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
@@ -63,7 +63,12 @@ public abstract class CastTypeNode extends RBaseNode {
 
     @TruffleBoundary
     public static CastNode createCast(RType type) {
-        return createCast(type, false, false, false);
+        return createCast(type, false, false, false, false);
+    }
+
+    @TruffleBoundary
+    public static CastNode createCast(RType type, boolean reuseNonShared) {
+        return createCast(type, false, false, false, reuseNonShared);
     }
 
     public static CastTypeNode create() {
@@ -71,16 +76,16 @@ public abstract class CastTypeNode extends RBaseNode {
     }
 
     @TruffleBoundary
-    public static CastNode createCast(RType type, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+    public static CastNode createCast(RType type, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean reuseNonShared) {
         switch (type) {
             case Character:
                 return CastStringNodeGen.create(preserveNames, preserveDimensions, preserveAttributes);
             case Complex:
                 return CastComplexNodeGen.create(preserveNames, preserveDimensions, preserveAttributes);
             case Double:
-                return CastDoubleNodeGen.create(preserveNames, preserveDimensions, preserveAttributes);
+                return CastDoubleNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, false, reuseNonShared);
             case Integer:
-                return CastIntegerNodeGen.create(preserveNames, preserveDimensions, preserveAttributes);
+                return CastIntegerNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, false, reuseNonShared);
             case Logical:
                 return CastLogicalNodeGen.create(preserveNames, preserveDimensions, preserveAttributes);
             case Raw:
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java
index 70f34a3d31d1afd35087958cefe70a8de97c20a1..d22c10086a9be1b3f9388fb1bce0ac9bc72c2122 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java
@@ -332,8 +332,16 @@ public final class CastBuilder {
             return new CoercionStep<>(RType.Integer, true);
         }
 
+        public static <T> PipelineStep<T, RAbstractIntVector> asIntegerVectorClosure() {
+            return new CoercionStep<>(RType.Integer, true, false, false, false, true, true);
+        }
+
         public static <T> PipelineStep<T, RAbstractIntVector> asIntegerVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-            return new CoercionStep<>(RType.Integer, true, preserveNames, preserveDimensions, preserveAttributes, true);
+            return new CoercionStep<>(RType.Integer, true, preserveNames, preserveDimensions, preserveAttributes, true, false);
+        }
+
+        public static <T> PipelineStep<T, RAbstractIntVector> asIntegerVectorClosure(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+            return new CoercionStep<>(RType.Integer, true, preserveNames, preserveDimensions, preserveAttributes, true, true);
         }
 
         public static <T> PipelineStep<T, Double> asDouble() {
@@ -344,10 +352,18 @@ public final class CastBuilder {
             return new CoercionStep<>(RType.Double, true);
         }
 
+        public static <T> PipelineStep<T, RAbstractDoubleVector> asDoubleVectorClosure() {
+            return new CoercionStep<>(RType.Double, true, false, false, false, true, true);
+        }
+
         public static <T> PipelineStep<T, RAbstractDoubleVector> asDoubleVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
             return new CoercionStep<>(RType.Double, true, preserveNames, preserveDimensions, preserveAttributes);
         }
 
+        public static <T> PipelineStep<T, RAbstractDoubleVector> asDoubleVectorClosure(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+            return new CoercionStep<>(RType.Double, true, preserveNames, preserveDimensions, preserveAttributes, true, true);
+        }
+
         public static <T> PipelineStep<T, String> asString() {
             return new CoercionStep<>(RType.Character, false);
         }
@@ -377,7 +393,7 @@ public final class CastBuilder {
         }
 
         public static <T> PipelineStep<T, RAbstractLogicalVector> asLogicalVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-            return new CoercionStep<>(RType.Logical, true, preserveNames, preserveDimensions, preserveAttributes, false);
+            return new CoercionStep<>(RType.Logical, true, preserveNames, preserveDimensions, preserveAttributes, false, false);
         }
 
         public static PipelineStep<Byte, Boolean> asBoolean() {
@@ -389,7 +405,7 @@ public final class CastBuilder {
         }
 
         public static <T> PipelineStep<T, RAbstractVector> asVector(boolean preserveNonVector) {
-            return new CoercionStep<>(RType.Any, true, false, false, false, preserveNonVector);
+            return new CoercionStep<>(RType.Any, true, false, false, false, preserveNonVector, false);
         }
 
         /**
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java
index 05e91851108907a73d5716dc0e76df049bb96fa4..d742c32b3c49adf12a1751084d89d2ea0bdb08ad 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java
@@ -22,8 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.builtin;
 
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.r.nodes.function.CallMatcherNode;
@@ -40,20 +38,17 @@ import com.oracle.truffle.r.runtime.data.RFunction;
  */
 public final class RInternalCodeBuiltinNode extends RExternalBuiltinNode {
 
-    private final RContext context;
     private final String basePackage;
     private final Source code;
     private final String functionName;
 
     @Child private CallMatcherNode call = CallMatcherNode.create(true);
-    @CompilationFinal private RFunction function;
 
     static {
         Casts.noCasts(RInternalCodeBuiltinNode.class);
     }
 
-    public RInternalCodeBuiltinNode(RContext context, String basePackage, Source code, String functionName) {
-        this.context = context;
+    public RInternalCodeBuiltinNode(String basePackage, Source code, String functionName) {
         this.basePackage = basePackage;
         this.code = code;
         this.functionName = functionName;
@@ -66,15 +61,13 @@ public final class RInternalCodeBuiltinNode extends RExternalBuiltinNode {
 
     @Override
     public Object call(VirtualFrame frame, RArgsValuesAndNames actualArgs) {
+        RInternalCode internalCode = RInternalCode.lookup(RContext.getInstance(), basePackage, code);
+        RFunction function = internalCode.lookupFunction(functionName);
         if (function == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            RInternalCode internalCode = RInternalCode.lookup(context, basePackage, code);
-            this.function = internalCode.lookupFunction(functionName);
-            if (this.function == null) {
-                throw RInternalError.shouldNotReachHere("Could not load RInternalCodeBuiltin function '" + functionName + "'.");
-            }
+            throw RInternalError.shouldNotReachHere("Could not load RInternalCodeBuiltin function '" + functionName + "'.");
         }
 
         return call.execute(frame, actualArgs.getSignature(), actualArgs.getArguments(), function, functionName, null);
     }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineStep.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineStep.java
index 7f4776692ec9714a69e551a85df015bd8896763d..4e9bdc24d38dd198fe16a92a601791aa425af6d8 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineStep.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineStep.java
@@ -176,21 +176,28 @@ public abstract class PipelineStep<T, R> {
          */
         public final boolean vectorCoercion;
 
+        /**
+         * Allows the cast node to create and use wrappers for vectors. Only use if you know the
+         * vector to be casted won't escape and preferably if the vector is just used read-only.
+         */
+        public final boolean useClosure;
+
         public CoercionStep(RType type, boolean vectorCoercion) {
-            this(type, vectorCoercion, false, false, false, true);
+            this(type, vectorCoercion, false, false, false, true, false);
         }
 
         public CoercionStep(RType type, boolean vectorCoercion, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-            this(type, vectorCoercion, preserveNames, preserveDimensions, preserveAttributes, true);
+            this(type, vectorCoercion, preserveNames, preserveDimensions, preserveAttributes, true, false);
         }
 
-        public CoercionStep(RType type, boolean vectorCoercion, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean preserveNonVector) {
+        public CoercionStep(RType type, boolean vectorCoercion, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean preserveNonVector, boolean useClosure) {
             this.type = type;
             this.vectorCoercion = vectorCoercion;
             this.preserveNames = preserveNames;
             this.preserveAttributes = preserveAttributes;
             this.preserveDimensions = preserveDimensions;
             this.preserveNonVector = preserveNonVector;
+            this.useClosure = useClosure;
         }
 
         public RType getType() {
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 12aaa0ec1f3df2f353fbc0bc633110f87b42698f..e0c252dfd5387ebc560c2f338682add035352804 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
@@ -226,11 +226,11 @@ public final class PipelineToCastNode {
             RType type = step.getType();
             switch (type) {
                 case Integer:
-                    return step.vectorCoercion ? CastIntegerNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes)
-                                    : CastIntegerBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes);
+                    return step.vectorCoercion ? CastIntegerNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, false, step.useClosure)
+                                    : CastIntegerBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, false, step.useClosure);
                 case Double:
-                    return step.vectorCoercion ? CastDoubleNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes)
-                                    : CastDoubleBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes);
+                    return step.vectorCoercion ? CastDoubleNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, false, step.useClosure)
+                                    : CastDoubleBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, false, step.useClosure);
                 case Character:
                     return step.vectorCoercion ? CastStringNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes)
                                     : CastStringBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java
index c66079bf6e6e723802b7c99c7355f7918945afdb..0773eb292340d60d60a681cadc752f56aeca219a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java
@@ -159,6 +159,20 @@ public class InitialPhaseBuilder<T> extends ArgCastBuilder<T, InitialPhaseBuilde
         return asIntegerVector(false, false, false);
     }
 
+    public CoercedPhaseBuilder<RAbstractIntVector, Integer> asIntegerVectorClosure(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        pipelineBuilder().appendAsVectorClosure(RType.Integer, preserveNames, preserveDimensions, preserveAttributes);
+        return new CoercedPhaseBuilder<>(pipelineBuilder(), Integer.class);
+    }
+
+    public CoercedPhaseBuilder<RAbstractIntVector, Integer> asIntegerVectorClosure() {
+        return asIntegerVectorClosure(false, false, false);
+    }
+
+    public CoercedPhaseBuilder<RAbstractDoubleVector, Double> asDoubleVectorClosure(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        pipelineBuilder().appendAsVectorClosure(RType.Double, preserveNames, preserveDimensions, preserveAttributes);
+        return new CoercedPhaseBuilder<>(pipelineBuilder(), Double.class);
+    }
+
     public CoercedPhaseBuilder<RAbstractDoubleVector, Double> asDoubleVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
         pipelineBuilder().appendAsVector(RType.Double, preserveNames, preserveDimensions, preserveAttributes);
         return new CoercedPhaseBuilder<>(pipelineBuilder(), Double.class);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java
index 56374865240205f24e9b8a7a99656277ed34a29e..c40a4f293f33174ced113f85aa4b89a345390bc3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java
@@ -76,12 +76,17 @@ public final class PipelineBuilder {
     }
 
     public void appendAsVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean preserveNonVector) {
-        append(new CoercionStep<>(RType.Any, true, preserveNames, preserveDimensions, preserveAttributes, preserveNonVector));
+        append(new CoercionStep<>(RType.Any, true, preserveNames, preserveDimensions, preserveAttributes, preserveNonVector, false));
     }
 
     public void appendAsVector(RType type, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
         assert type == RType.Integer || type == RType.Double || type == RType.Complex || type == RType.Character || type == RType.Logical || type == RType.Raw;
-        append(new CoercionStep<>(type, true, preserveNames, preserveDimensions, preserveAttributes, true));
+        append(new CoercionStep<>(type, true, preserveNames, preserveDimensions, preserveAttributes, true, false));
+    }
+
+    public void appendAsVectorClosure(RType type, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        assert type == RType.Integer || type == RType.Double || type == RType.Complex || type == RType.Character || type == RType.Logical || type == RType.Raw;
+        append(new CoercionStep<>(type, true, preserveNames, preserveDimensions, preserveAttributes, true, true));
     }
 
     public void appendNotNA(Object naReplacement, Message message, Object[] messageArgs) {
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 009a71466344b12089f6fe90ff57ad6707b7c615..164d40610dfc4da9704996e4c9fdb816c29071a2 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
@@ -127,8 +127,8 @@ public final class BinaryMapNode extends RBaseNode {
         RAbstractVector left = leftClass.cast(originalLeft);
         RAbstractVector right = rightClass.cast(originalRight);
 
-        RAbstractVector leftCast = left.castSafe(argumentType, leftIsNAProfile);
-        RAbstractVector rightCast = right.castSafe(argumentType, rightIsNAProfile);
+        RAbstractVector leftCast = left.castSafe(argumentType, leftIsNAProfile, false);
+        RAbstractVector rightCast = right.castSafe(argumentType, rightIsNAProfile, false);
 
         assert leftCast != null;
         assert rightCast != null;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
index d94c36c1dc1816afdcf4ff0f4ebcca750a72ee7c..8216976903f773de772b3b7bea546ad3d34e26cd 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
@@ -28,6 +28,7 @@ import com.oracle.truffle.api.dsl.Fallback;
 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.api.profiles.ValueProfile;
 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;
@@ -42,8 +43,8 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 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.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 public abstract class CastBaseNode extends CastNode {
@@ -52,6 +53,8 @@ public abstract class CastBaseNode extends CastNode {
     private final ConditionProfile hasDimNamesProfile = ConditionProfile.createBinaryProfile();
     private final NullProfile hasDimensionsProfile = NullProfile.create();
     private final NullProfile hasNamesProfile = NullProfile.create();
+    private final ValueProfile reuseClassProfile;
+
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
     @Child private GetDimAttributeNode getDimNode;
     @Child private SetDimNamesAttributeNode setDimNamesNode;
@@ -61,6 +64,9 @@ public abstract class CastBaseNode extends CastNode {
     private final boolean preserveDimensions;
     private final boolean preserveAttributes;
 
+    /** {@code true} if a cast should wrap the input in a closure. */
+    private final boolean useClosure;
+
     /**
      * GnuR provides several, sometimes incompatible, ways to coerce given value to given type. This
      * flag tells the cast node that it should behave in a way compatible with functions exposed by
@@ -73,6 +79,10 @@ public abstract class CastBaseNode extends CastNode {
     }
 
     protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        this(preserveNames, preserveDimensions, preserveAttributes, forRFFI, false);
+    }
+
+    protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI, boolean useClosure) {
         this.preserveNames = preserveNames;
         this.preserveDimensions = preserveDimensions;
         this.preserveAttributes = preserveAttributes;
@@ -80,6 +90,8 @@ public abstract class CastBaseNode extends CastNode {
         if (preserveDimensions) {
             getDimNamesNode = GetDimNamesAttributeNode.create();
         }
+        this.useClosure = useClosure;
+        reuseClassProfile = useClosure ? ValueProfile.createClassProfile() : null;
     }
 
     public final boolean preserveNames() {
@@ -90,10 +102,18 @@ public abstract class CastBaseNode extends CastNode {
         return preserveDimensions;
     }
 
-    public final boolean preserveAttributes() {
+    public final boolean preserveRegAttributes() {
         return preserveAttributes;
     }
 
+    public final boolean preserveAttributes() {
+        return preserveAttributes || preserveNames || preserveDimensions;
+    }
+
+    public final boolean reuseNonShared() {
+        return useClosure;
+    }
+
     protected abstract RType getTargetType();
 
     protected RError throwCannotCoerceListError(String type) {
@@ -121,7 +141,7 @@ public abstract class CastBaseNode extends CastNode {
         }
     }
 
-    protected void preserveDimensionNames(RAbstractContainer operand, RVector<?> ret) {
+    protected void preserveDimensionNames(RAbstractContainer operand, RAbstractContainer ret) {
         if (preserveDimensions()) {
             RList dimNames = getDimNamesNode.getDimNames(operand);
             if (hasDimNamesProfile.profile(dimNames != null)) {
@@ -161,4 +181,13 @@ public abstract class CastBaseNode extends CastNode {
         }
         return RNull.instance;
     }
+
+    protected boolean useClosure() {
+        return useClosure;
+    }
+
+    protected RAbstractVector castWithReuse(RType targetType, RAbstractVector v, ConditionProfile naProfile) {
+        assert useClosure();
+        return reuseClassProfile.profile(v.castSafe(targetType, naProfile, preserveAttributes()));
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
index 88151421902d9518fbfeb23035b5ca4e27bcce3e..6ffad041e4fb8487ba00969848c3f334541226bc 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
@@ -76,7 +76,7 @@ public abstract class CastComplexNode extends CastBaseNode {
     private Object castComplexRecursive(Object o) {
         if (recursiveCastComplex == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastComplex = insert(CastComplexNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
+            recursiveCastComplex = insert(CastComplexNodeGen.create(preserveNames(), preserveDimensions(), preserveRegAttributes()));
         }
         return recursiveCastComplex.executeComplex(o);
     }
@@ -151,7 +151,7 @@ public abstract class CastComplexNode extends CastBaseNode {
         }
         RComplexVector ret = RDataFactory.createComplexVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -204,7 +204,7 @@ public abstract class CastComplexNode extends CastBaseNode {
         }
         RComplexVector ret = RDataFactory.createComplexVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -258,7 +258,7 @@ public abstract class CastComplexNode extends CastBaseNode {
             }
         }
         RComplexVector ret = RDataFactory.createComplexVector(result, !seenNA, getPreservedDimensions(list), getPreservedNames(list));
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(list);
         }
         return ret;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java
index 9abeb67a8dbd105abcaf074d9907ab0aae07ff15..15a9514d39ce31cb0f683a2a18472e2e6b626c5b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java
@@ -44,8 +44,8 @@ public abstract class CastDoubleBaseNode extends CastBaseNode {
         super(preserveNames, preserveDimensions, preserveAttributes);
     }
 
-    protected CastDoubleBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
-        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
+    protected CastDoubleBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI, boolean useClosure) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI, useClosure);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java
index f0e17bb98d59f24aaf75f02466000cf858f55606..142974974969bfdce18caf7c210511097739755e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java
@@ -31,20 +31,22 @@ import com.oracle.truffle.api.dsl.Specialization;
 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.api.profiles.ValueProfile;
 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.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RDoubleSequence;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 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.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.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
 import com.oracle.truffle.r.runtime.interop.ForeignArray2RNodeGen;
@@ -52,12 +54,12 @@ import com.oracle.truffle.r.runtime.interop.ForeignArray2RNodeGen;
 @ImportStatic(RRuntime.class)
 public abstract class CastDoubleNode extends CastDoubleBaseNode {
 
-    protected CastDoubleNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
-        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
+    protected CastDoubleNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI, boolean withReuse) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI, withReuse);
     }
 
     protected CastDoubleNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        super(preserveNames, preserveDimensions, preserveAttributes, false, false);
     }
 
     @Child private CastDoubleNode recursiveCastDouble;
@@ -65,7 +67,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
     private Object castDoubleRecursive(Object o) {
         if (recursiveCastDouble == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastDouble = insert(CastDoubleNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
+            recursiveCastDouble = insert(CastDoubleNodeGen.create(preserveNames(), preserveDimensions(), preserveRegAttributes(), false, reuseNonShared()));
         }
         return recursiveCastDouble.executeDouble(o);
     }
@@ -73,7 +75,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
     private RDoubleVector vectorCopy(RAbstractContainer operand, double[] data, boolean isComplete) {
         RDoubleVector ret = RDataFactory.createDoubleVector(data, isComplete, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -92,15 +94,35 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
     }
 
     @Specialization
-    protected RDoubleVector doIntVector(RAbstractIntVector operand) {
+    protected RAbstractDoubleVector doIntVector(RAbstractIntVector x,
+                    @Cached("createClassProfile()") ValueProfile operandTypeProfile) {
+        RAbstractIntVector operand = operandTypeProfile.profile(x);
+        if (useClosure()) {
+            return (RAbstractDoubleVector) castWithReuse(RType.Double, operand, naProfile.getConditionProfile());
+        }
         return createResultVector(operand, index -> naCheck.convertIntToDouble(operand.getDataAt(index)));
     }
 
     @Specialization
-    protected RDoubleVector doLogicalVectorDims(RAbstractLogicalVector operand) {
+    protected RAbstractDoubleVector doLogicalVector(RAbstractLogicalVector x,
+                    @Cached("createClassProfile()") ValueProfile operandTypeProfile) {
+        RAbstractLogicalVector operand = operandTypeProfile.profile(x);
+        if (useClosure()) {
+            return (RAbstractDoubleVector) castWithReuse(RType.Double, operand, naProfile.getConditionProfile());
+        }
         return createResultVector(operand, index -> naCheck.convertLogicalToDouble(operand.getDataAt(index)));
     }
 
+    @Specialization
+    protected RAbstractDoubleVector doRawVector(RAbstractRawVector x,
+                    @Cached("createClassProfile()") ValueProfile operandTypeProfile) {
+        RAbstractRawVector operand = operandTypeProfile.profile(x);
+        if (useClosure()) {
+            return (RAbstractDoubleVector) castWithReuse(RType.Double, operand, naProfile.getConditionProfile());
+        }
+        return createResultVector(operand, index -> RRuntime.raw2double(operand.getDataAt(index)));
+    }
+
     @Specialization
     protected RDoubleVector doStringVector(RStringVector operand,
                     @Cached("createBinaryProfile()") ConditionProfile emptyStringProfile,
@@ -132,7 +154,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
         }
         RDoubleVector ret = RDataFactory.createDoubleVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -157,18 +179,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
     }
 
     @Specialization
-    protected RDoubleVector doRawVector(RRawVector operand) {
-        return createResultVector(operand, index -> RRuntime.raw2double(operand.getDataAt(index)));
-    }
-
-    @Specialization
-    protected RDoubleVector doDoubleVector(RDoubleVector operand) {
-        return operand;
-    }
-
-    @Specialization
-    protected RDoubleSequence doDoubleVector(RDoubleSequence operand) {
-        // sequence does not have attributes - nothing to copy or drop
+    protected RAbstractDoubleVector doDoubleVector(RAbstractDoubleVector operand) {
         return operand;
     }
 
@@ -206,7 +217,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
             }
         }
         RDoubleVector ret = RDataFactory.createDoubleVector(result, !seenNA, getPreservedDimensions(list), getPreservedNames(list));
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(list);
         }
         return ret;
@@ -229,15 +240,19 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
     }
 
     public static CastDoubleNode create() {
-        return CastDoubleNodeGen.create(true, true, true);
+        return CastDoubleNodeGen.create(true, true, true, false, false);
+    }
+
+    public static CastDoubleNode createWithReuse() {
+        return CastDoubleNodeGen.create(true, true, true, false, true);
     }
 
     public static CastDoubleNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        return CastDoubleNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+        return CastDoubleNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true, false);
     }
 
     public static CastDoubleNode createNonPreserving() {
-        return CastDoubleNodeGen.create(false, false, false);
+        return CastDoubleNodeGen.create(false, false, false, false, false);
     }
 
     protected ForeignArray2R createForeignArray2RNode() {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java
index dc79c02b5f39ffc9223f8325157dececc441c961..f2239927848c6102bf34bd31802ae2bd9f7656e6 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java
@@ -41,12 +41,12 @@ public abstract class CastIntegerBaseNode extends CastBaseNode {
 
     @Child private CastIntegerNode recursiveCastInteger;
 
-    protected CastIntegerBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
-        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
+    protected CastIntegerBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI, boolean useClosure) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI, useClosure);
     }
 
     protected CastIntegerBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        super(preserveNames, preserveDimensions, preserveAttributes, false, false);
     }
 
     @Override
@@ -57,7 +57,7 @@ public abstract class CastIntegerBaseNode extends CastBaseNode {
     protected Object castIntegerRecursive(Object o) {
         if (recursiveCastInteger == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastInteger = insert(CastIntegerNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
+            recursiveCastInteger = insert(CastIntegerNodeGen.create(preserveNames(), preserveDimensions(), preserveRegAttributes(), false, reuseNonShared()));
         }
         return recursiveCastInteger.executeInt(o);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java
index aff2149c234a85ef32c501a5c04ebbd60f18964f..b937b63904c6c33163604e8d7008802d65a44041 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java
@@ -28,8 +28,10 @@ import com.oracle.truffle.api.dsl.Specialization;
 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.api.profiles.ValueProfile;
 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.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -56,12 +58,12 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
 
     private final BranchProfile warningBranch = BranchProfile.create();
 
-    protected CastIntegerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
-        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
+    protected CastIntegerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI, boolean useClosure) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI, useClosure);
     }
 
     protected CastIntegerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        super(preserveNames, preserveDimensions, preserveAttributes, false, false);
     }
 
     public abstract Object executeInt(int o);
@@ -86,7 +88,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
     private RIntVector vectorCopy(RAbstractVector operand, int[] idata, boolean isComplete) {
         RIntVector ret = RDataFactory.createIntVector(idata, isComplete, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -160,18 +162,32 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
     }
 
     @Specialization
-    public RIntVector doLogicalVector(RAbstractLogicalVector operand) {
+    public RAbstractIntVector doLogicalVector(RAbstractLogicalVector x,
+                    @Cached("createClassProfile()") ValueProfile operandTypeProfile) {
+        RAbstractLogicalVector operand = operandTypeProfile.profile(x);
+        if (useClosure()) {
+            return (RAbstractIntVector) castWithReuse(RType.Integer, operand, naProfile.getConditionProfile());
+        }
         return createResultVector(operand, index -> naCheck.convertLogicalToInt(operand.getDataAt(index)));
     }
 
     @Specialization
-    protected RIntVector doDoubleVector(RAbstractDoubleVector operand) {
-        naCheck.enable(operand);
+    protected RAbstractIntVector doDoubleVector(RAbstractDoubleVector x,
+                    @Cached("createClassProfile()") ValueProfile operandTypeProfile) {
+        RAbstractDoubleVector operand = operandTypeProfile.profile(x);
+        if (useClosure()) {
+            return (RAbstractIntVector) castWithReuse(RType.Integer, operand, naProfile.getConditionProfile());
+        }
         return vectorCopy(operand, naCheck.convertDoubleVectorToIntData(operand), naCheck.neverSeenNA());
     }
 
     @Specialization
-    protected RIntVector doRawVector(RAbstractRawVector operand) {
+    protected RAbstractIntVector doRawVector(RAbstractRawVector x,
+                    @Cached("createClassProfile()") ValueProfile operandTypeProfile) {
+        RAbstractRawVector operand = operandTypeProfile.profile(x);
+        if (useClosure()) {
+            return (RAbstractIntVector) castWithReuse(RType.Integer, operand, naProfile.getConditionProfile());
+        }
         return createResultVector(operand, index -> RRuntime.raw2int(operand.getDataAt(index)));
     }
 
@@ -209,7 +225,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
             }
         }
         RIntVector ret = RDataFactory.createIntVector(result, !seenNA, getPreservedDimensions(list), getPreservedNames(list));
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(list);
         }
         return ret;
@@ -242,15 +258,19 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
     }
 
     public static CastIntegerNode create() {
-        return CastIntegerNodeGen.create(true, true, true);
+        return CastIntegerNodeGen.create(true, true, true, false, false);
+    }
+
+    public static CastIntegerNode createWithReuse() {
+        return CastIntegerNodeGen.create(true, true, true, false, true);
     }
 
     public static CastIntegerNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        return CastIntegerNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+        return CastIntegerNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true, false);
     }
 
     public static CastIntegerNode createNonPreserving() {
-        return CastIntegerNodeGen.create(false, false, false);
+        return CastIntegerNodeGen.create(false, false, false, false, false);
     }
 
     protected ForeignArray2R createForeignArray2RNode() {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
index a569b25f638246f6848612d73d5f7a973779927e..72b6158aa0612f0ee0b8e4538a46d27534daaf22 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
@@ -96,7 +96,7 @@ public abstract class CastListNode extends CastBaseNode {
         }
         RList ret = RDataFactory.createList(data, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
index 9080f05e09a9f6421d18f00831fee0b042d63316..823521698e1a50cd5f95e8f73db19f7fc1962a65 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
@@ -67,7 +67,7 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
     protected Object castLogicalRecursive(Object o) {
         if (recursiveCastLogical == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastLogical = insert(CastLogicalNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
+            recursiveCastLogical = insert(CastLogicalNodeGen.create(preserveNames(), preserveDimensions(), preserveRegAttributes()));
         }
         return recursiveCastLogical.execute(o);
     }
@@ -93,7 +93,7 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
     private RLogicalVector vectorCopy(RAbstractVector operand, byte[] bdata, boolean isComplete) {
         RLogicalVector ret = RDataFactory.createLogicalVector(bdata, isComplete, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -182,7 +182,7 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
             }
         }
         RLogicalVector ret = RDataFactory.createLogicalVector(result, !seenNA, getPreservedDimensions(list), getPreservedNames(list));
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(list);
         }
         return ret;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
index c66438279a68fe416dead3725adc170253c3d9ac..44b0149e20f5b7a5f4ccdaa3dc216fadb01a3d16 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
@@ -69,7 +69,7 @@ public abstract class CastRawNode extends CastBaseNode {
     protected Object castRawRecursive(Object o) {
         if (recursiveCastRaw == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastRaw = insert(CastRawNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
+            recursiveCastRaw = insert(CastRawNodeGen.create(preserveNames(), preserveDimensions(), preserveRegAttributes()));
         }
         return recursiveCastRaw.executeRaw(o);
     }
@@ -157,7 +157,7 @@ public abstract class CastRawNode extends CastBaseNode {
     private RRawVector vectorCopy(RAbstractVector operand, byte[] bdata) {
         RRawVector ret = RDataFactory.createRawVector(bdata, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -306,7 +306,7 @@ public abstract class CastRawNode extends CastBaseNode {
             data[i] = ((RRaw) castRawRecursive(value.getDataAt(i))).getValue();
         }
         RRawVector result = RDataFactory.createRawVector(data, getPreservedDimensions(value), getPreservedNames(value));
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             result.copyRegAttributesFrom(value);
         }
         return result;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java
index 1f413ee259640ac3c92cebc25bf33a3190a21733..ebec5af6e485d4e7016ec3162bad1b624eaaeb59 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java
@@ -64,7 +64,7 @@ public abstract class CastStringNode extends CastStringBaseNode {
     private RStringVector vectorCopy(RAbstractContainer operand, String[] data) {
         RStringVector ret = RDataFactory.createStringVector(data, operand.isComplete(), getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (preserveAttributes()) {
+        if (preserveRegAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -133,7 +133,7 @@ public abstract class CastStringNode extends CastStringBaseNode {
     private Object castStringRecursive(Object o) {
         if (recursiveCastString == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastString = insert(CastStringNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
+            recursiveCastString = insert(CastStringNodeGen.create(preserveNames(), preserveDimensions(), preserveRegAttributes()));
         }
         return recursiveCastString.executeString(o);
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalCode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalCode.java
index 2a29784e9d0ce13e72fedcfe15f6ef086edab9b0..90d023e31c62ba4bf10880c1224d146134ad2096 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalCode.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalCode.java
@@ -72,6 +72,7 @@ public final class RInternalCode {
         }
     }
 
+    @TruffleBoundary
     public synchronized RFunction lookupFunction(String name) {
         REnvironment env = this.evaluatedEnvironment;
         if (env == null) {
@@ -83,6 +84,7 @@ public final class RInternalCode {
         return fun;
     }
 
+    @TruffleBoundary
     public static RInternalCode lookup(RContext context, String basePackage, Source source) {
         ContextStateImpl state = context.stateInternalCode;
         RInternalCode code = state.get(source);
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 e928ee140a045b2c9bc89268f8e28fe1964c11b2..af6a3028bc427305beaf140ce954cc6adc365b8d 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
@@ -52,7 +52,7 @@ public final class RComplex extends RScalarVector implements RAbstractComplexVec
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Complex:
                 return this;
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 5e7b39ec4557d4a3b697acabcdb3d287f08a7a4e..f8c0488a44e0c579aa393c39f7e671c8471297b4 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
@@ -64,14 +64,14 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Complex:
                 return this;
             case Character:
-                return RClosures.createToStringVector(this);
+                return RClosures.createToStringVector(this, keepAttributes);
             case List:
-                return RClosures.createToListVector(this);
+                return RClosures.createToListVector(this, keepAttributes);
             default:
                 return null;
         }
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 1a034e6bf2826b734c754652aeed229adb94dc5d..6a66889e9cdeacff4129c7ab932ead664ee736bb 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
@@ -53,7 +53,7 @@ public final class RDouble extends RScalarVector implements RAbstractDoubleVecto
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Integer:
                 return this;
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 2cf039de0743c86ed84b3f189fd24d5a9522dc78..a94cce37d00277922034d1d28749b204d1ebf17c 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
@@ -70,19 +70,19 @@ public final class RDoubleSequence extends RSequence implements RAbstractDoubleV
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         // TODO might be possible to implement some of these without closures
         switch (type) {
             case Integer:
-                return RClosures.createToIntVector(this);
+                return RClosures.createToIntVector(this, keepAttributes);
             case Double:
                 return this;
             case Complex:
-                return RClosures.createToComplexVector(this);
+                return RClosures.createToComplexVector(this, keepAttributes);
             case Character:
-                return RClosures.createToStringVector(this);
+                return RClosures.createToStringVector(this, keepAttributes);
             case List:
-                return RClosures.createToListVector(this);
+                return RClosures.createToListVector(this, keepAttributes);
             default:
                 return null;
         }
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 e4eace8649f0ecd70396b1798ab2db31860fe6db..52366b1ae86c5a4e41c6927140452ebbe52043c8 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
@@ -48,18 +48,18 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Integer:
-                return RClosures.createToIntVector(this);
+                return RClosures.createToIntVector(this, keepAttributes);
             case Double:
                 return this;
             case Complex:
-                return RClosures.createToComplexVector(this);
+                return RClosures.createToComplexVector(this, keepAttributes);
             case Character:
-                return RClosures.createToStringVector(this);
+                return RClosures.createToStringVector(this, keepAttributes);
             case List:
-                return RClosures.createToListVector(this);
+                return RClosures.createToListVector(this, keepAttributes);
             default:
                 return null;
         }
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 a5aea4b6f6ca4347adebbbf7248a22d8d0c3dc83..402dc97ac493f9fb5c52e46240f1c83a041e45ae 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
@@ -48,18 +48,18 @@ public final class RIntSequence extends RSequence implements RAbstractIntVector
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Integer:
                 return this;
             case Double:
                 return RDataFactory.createDoubleSequence(getStart(), getStride(), getLength());
             case Complex:
-                return RClosures.createToComplexVector(this);
+                return RClosures.createToComplexVector(this, keepAttributes);
             case Character:
-                return RClosures.createToStringVector(this);
+                return RClosures.createToStringVector(this, keepAttributes);
             case List:
-                return RClosures.createToListVector(this);
+                return RClosures.createToListVector(this, keepAttributes);
             default:
                 return null;
         }
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 8fa15af2a36250faf14c7d2bd464ece0d2be187c..d95bb428e4a28c9fed63b1a57ae8527276bf708f 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
@@ -48,18 +48,18 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Integer:
                 return this;
             case Double:
-                return RClosures.createToDoubleVector(this);
+                return RClosures.createToDoubleVector(this, keepAttributes);
             case Complex:
-                return RClosures.createToComplexVector(this);
+                return RClosures.createToComplexVector(this, keepAttributes);
             case Character:
-                return RClosures.createToStringVector(this);
+                return RClosures.createToStringVector(this, keepAttributes);
             case List:
-                return RClosures.createToListVector(this);
+                return RClosures.createToListVector(this, keepAttributes);
             default:
                 return null;
         }
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 3a618e1ff53c4c1f638f1543806c1e276cc4829d..eb0ea1f399ffd83e2dd88f286e7ec133c0467735 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
@@ -62,7 +62,7 @@ public final class RInteger extends RScalarVector implements RAbstractIntVector
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Integer:
                 return this;
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 b0a64de5abacb4d56adc4cb4dd8111e27687eb0e..7fade92f1bed1c2e7ebb42f3232d09a46e5c6184 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
@@ -55,7 +55,7 @@ public final class RLogical extends RScalarVector implements RAbstractLogicalVec
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Logical:
                 return this;
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 3a1a9ebb4f4cbaaa1541878964a135926363ebcf..3bde20df8e776d6571b91dd07dee09db4b6c2988 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
@@ -48,20 +48,20 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Logical:
                 return this;
             case Integer:
-                return RClosures.createToIntVector(this);
+                return RClosures.createToIntVector(this, keepAttributes);
             case Double:
-                return RClosures.createToDoubleVector(this);
+                return RClosures.createToDoubleVector(this, keepAttributes);
             case Complex:
-                return RClosures.createToComplexVector(this);
+                return RClosures.createToComplexVector(this, keepAttributes);
             case Character:
-                return RClosures.createToStringVector(this);
+                return RClosures.createToStringVector(this, keepAttributes);
             case List:
-                return RClosures.createToListVector(this);
+                return RClosures.createToListVector(this, keepAttributes);
             default:
                 return null;
         }
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 0c55726d53efdf18f95c15a6b20d7f417302a930..b88afcc338f6d90911ef2b781574012345ee81fb 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
@@ -45,7 +45,7 @@ public final class RRaw extends RScalarVector implements RAbstractRawVector {
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Raw:
                 return this;
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 85c9947b3c887b134cd18a779929d3fa630e9e36..26252b7da5746b0efdfd06af7ed539a09ff6c070 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
@@ -48,18 +48,18 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Raw:
                 return this;
             case Integer:
-                return RClosures.createToIntVector(this);
+                return RClosures.createToIntVector(this, keepAttributes);
             case Double:
-                return RClosures.createToDoubleVector(this);
+                return RClosures.createToDoubleVector(this, keepAttributes);
             case Complex:
-                return RClosures.createToComplexVector(this);
+                return RClosures.createToComplexVector(this, keepAttributes);
             case Character:
-                return RClosures.createToStringVector(this);
+                return RClosures.createToStringVector(this, keepAttributes);
             default:
                 return null;
         }
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 48e050c17b68e3dafd469bbb20dea8e73cc5e2be..1ea23adc66f510252e67c8aa0696a03e7e9d2993 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
@@ -57,7 +57,7 @@ public final class RScalarList extends RScalarVector implements RAbstractListVec
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case List:
                 return this;
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 98b4b5653f6f931907b8fb5b23b83b26ad582e82..abf51a343f797352297a0a94155670ef897b5d5b 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
@@ -48,7 +48,7 @@ public final class RString extends RScalarVector implements RAbstractStringVecto
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Character:
                 return this;
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 712b3deb8dc0cb22f6c21155f4b7fd08e5253fe6..38fdbb99181b237ae911db36a6074201c5ed22c3 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
@@ -49,12 +49,12 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
             case Character:
                 return this;
             case List:
-                return RClosures.createToListVector(this);
+                return RClosures.createToListVector(this, keepAttributes);
             default:
                 return null;
         }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java
index 91dddf4b5fe7e541eeaaafa46cffb8c54bd08338..1cc4294efa9d58eb83760855b4e1a146a83c62dd 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java
@@ -43,133 +43,197 @@ public class RClosures {
 
     // Logical to ...
 
-    public static RAbstractIntVector createToIntVector(RLogicalVector vector) {
-        return new RLogicalToIntVectorClosure(vector);
+    public static RAbstractIntVector createToIntVector(RLogicalVector vector, boolean keepAttributes) {
+        return new RLogicalToIntVectorClosure(vector, keepAttributes);
     }
 
-    public static RAbstractDoubleVector createToDoubleVector(RLogicalVector vector) {
-        return new RLogicalToDoubleVectorClosure(vector);
+    public static RAbstractDoubleVector createToDoubleVector(RLogicalVector vector, boolean keepAttributes) {
+        return new RLogicalToDoubleVectorClosure(vector, keepAttributes);
     }
 
-    public static RAbstractComplexVector createToComplexVector(RLogicalVector vector) {
-        return new RLogicalToComplexVectorClosure(vector);
+    public static RAbstractComplexVector createToComplexVector(RLogicalVector vector, boolean keepAttributes) {
+        return new RLogicalToComplexVectorClosure(vector, keepAttributes);
     }
 
-    public static RAbstractStringVector createToStringVector(RLogicalVector vector) {
-        return new RLogicalToStringVectorClosure(vector);
+    public static RAbstractStringVector createToStringVector(RLogicalVector vector, boolean keepAttributes) {
+        return new RLogicalToStringVectorClosure(vector, keepAttributes);
     }
 
-    public static RAbstractListVector createToListVector(RLogicalVector vector) {
-        return new RLogicalToListVectorClosure(vector);
+    public static RAbstractListVector createToListVector(RLogicalVector vector, boolean keepAttributes) {
+        return new RLogicalToListVectorClosure(vector, keepAttributes);
     }
 
     // Int to ...
 
-    public static RAbstractComplexVector createToComplexVector(RIntSequence vector) {
-        return new RIntSequenceToComplexVectorClosure(vector);
+    public static RAbstractComplexVector createToComplexVector(RIntSequence vector, boolean keepAttributes) {
+        return new RIntSequenceToComplexVectorClosure(vector, keepAttributes);
     }
 
-    public static RAbstractStringVector createToStringVector(RIntSequence vector) {
-        return new RIntSequenceToStringVectorClosure(vector);
+    public static RAbstractStringVector createToStringVector(RIntSequence vector, boolean keepAttributes) {
+        return new RIntSequenceToStringVectorClosure(vector, keepAttributes);
     }
 
-    public static RAbstractListVector createToListVector(RIntSequence vector) {
-        return new RIntSequenceToListVectorClosure(vector);
+    public static RAbstractListVector createToListVector(RIntSequence vector, boolean keepAttributes) {
+        return new RIntSequenceToListVectorClosure(vector, keepAttributes);
     }
 
-    public static RAbstractDoubleVector createToDoubleVector(RIntVector vector) {
-        return new RIntToDoubleVectorClosure(vector);
+    public static RAbstractDoubleVector createToDoubleVector(RIntVector vector, boolean keepAttributes) {
+        return new RIntToDoubleVectorClosure(vector, keepAttributes);
     }
 
-    public static RAbstractComplexVector createToComplexVector(RIntVector vector) {
-        return new RIntToComplexVectorClosure(vector);
+    public static RAbstractComplexVector createToComplexVector(RIntVector vector, boolean keepAttributes) {
+        return new RIntToComplexVectorClosure(vector, keepAttributes);
     }
 
-    public static RAbstractStringVector createToStringVector(RIntVector vector) {
-        return new RIntToStringVectorClosure(vector);
+    public static RAbstractStringVector createToStringVector(RIntVector vector, boolean keepAttributes) {
+        return new RIntToStringVectorClosure(vector, keepAttributes);
     }
 
-    public static RAbstractListVector createToListVector(RIntVector vector) {
-        return new RIntToListVectorClosure(vector);
+    public static RAbstractListVector createToListVector(RIntVector vector, boolean keepAttributes) {
+        return new RIntToListVectorClosure(vector, keepAttributes);
     }
 
     // Double to ...
 
     public static RAbstractComplexVector createToComplexVector(RDoubleSequence vector) {
-        return new RDoubleSequenceToComplexVectorClosure(vector);
+        return new RDoubleSequenceToComplexVectorClosure(vector, false);
+    }
+
+    public static RAbstractComplexVector createToComplexVector(RDoubleSequence vector, boolean keepAttributes) {
+        return new RDoubleSequenceToComplexVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractStringVector createToStringVector(RDoubleSequence vector) {
-        return new RDoubleSequenceToStringVectorClosure(vector);
+        return new RDoubleSequenceToStringVectorClosure(vector, false);
+    }
+
+    public static RAbstractStringVector createToStringVector(RDoubleSequence vector, boolean keepAttributes) {
+        return new RDoubleSequenceToStringVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractIntVector createToIntVector(RDoubleSequence vector) {
-        return new RDoubleSequenceToIntVectorClosure(vector);
+        return new RDoubleSequenceToIntVectorClosure(vector, false);
+    }
+
+    public static RAbstractIntVector createToIntVector(RDoubleSequence vector, boolean keepAttributes) {
+        return new RDoubleSequenceToIntVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractListVector createToListVector(RDoubleSequence vector) {
-        return new RDoubleSequenceToListVectorClosure(vector);
+        return new RDoubleSequenceToListVectorClosure(vector, false);
+    }
+
+    public static RAbstractListVector createToListVector(RDoubleSequence vector, boolean keepAttributes) {
+        return new RDoubleSequenceToListVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractComplexVector createToComplexVector(RDoubleVector vector) {
-        return new RDoubleToComplexVectorClosure(vector);
+        return new RDoubleToComplexVectorClosure(vector, false);
+    }
+
+    public static RAbstractComplexVector createToComplexVector(RDoubleVector vector, boolean keepAttributes) {
+        return new RDoubleToComplexVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractStringVector createToStringVector(RDoubleVector vector) {
-        return new RDoubleToStringVectorClosure(vector);
+        return new RDoubleToStringVectorClosure(vector, false);
+    }
+
+    public static RAbstractStringVector createToStringVector(RDoubleVector vector, boolean keepAttributes) {
+        return new RDoubleToStringVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractIntVector createToIntVector(RDoubleVector vector) {
-        return new RDoubleToIntVectorClosure(vector);
+        return new RDoubleToIntVectorClosure(vector, false);
+    }
+
+    public static RAbstractIntVector createToIntVector(RDoubleVector vector, boolean keepAttributes) {
+        return new RDoubleToIntVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractListVector createToListVector(RDoubleVector vector) {
-        return new RDoubleToListVectorClosure(vector);
+        return new RDoubleToListVectorClosure(vector, false);
+    }
+
+    public static RAbstractListVector createToListVector(RDoubleVector vector, boolean keepAttributes) {
+        return new RDoubleToListVectorClosure(vector, keepAttributes);
     }
 
     // Raw to ...
 
     public static RAbstractIntVector createToIntVector(RRawVector vector) {
-        return new RRawToIntVectorClosure(vector);
+        return new RRawToIntVectorClosure(vector, false);
+    }
+
+    public static RAbstractIntVector createToIntVector(RRawVector vector, boolean keepAttributes) {
+        return new RRawToIntVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractDoubleVector createToDoubleVector(RRawVector vector) {
-        return new RRawToDoubleVectorClosure(vector);
+        return new RRawToDoubleVectorClosure(vector, false);
+    }
+
+    public static RAbstractDoubleVector createToDoubleVector(RRawVector vector, boolean keepAttributes) {
+        return new RRawToDoubleVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractComplexVector createToComplexVector(RRawVector vector) {
-        return new RRawToComplexVectorClosure(vector);
+        return new RRawToComplexVectorClosure(vector, false);
+    }
+
+    public static RAbstractComplexVector createToComplexVector(RRawVector vector, boolean keepAttributes) {
+        return new RRawToComplexVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractStringVector createToStringVector(RRawVector vector) {
-        return new RRawToStringVectorClosure(vector);
+        return new RRawToStringVectorClosure(vector, false);
+    }
+
+    public static RAbstractStringVector createToStringVector(RRawVector vector, boolean keepAttributes) {
+        return new RRawToStringVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractListVector createToListVector(RRawVector vector) {
-        return new RRawToListVectorClosure(vector);
+        return new RRawToListVectorClosure(vector, false);
+    }
+
+    public static RAbstractListVector createToListVector(RRawVector vector, boolean keepAttributes) {
+        return new RRawToListVectorClosure(vector, keepAttributes);
     }
 
     // Complex to ...
 
     public static RAbstractStringVector createToStringVector(RComplexVector vector) {
-        return new RComplexToStringVectorClosure(vector);
+        return new RComplexToStringVectorClosure(vector, false);
+    }
+
+    public static RAbstractStringVector createToStringVector(RComplexVector vector, boolean keepAttributes) {
+        return new RComplexToStringVectorClosure(vector, keepAttributes);
     }
 
     public static RAbstractListVector createToListVector(RComplexVector vector) {
-        return new RComplexToListVectorClosure(vector);
+        return new RComplexToListVectorClosure(vector, false);
+    }
+
+    public static RAbstractListVector createToListVector(RComplexVector vector, boolean keepAttributes) {
+        return new RComplexToListVectorClosure(vector, keepAttributes);
     }
 
     // Character to ...
 
-    public static RAbstractListVector createToListVector(RStringVector vector) {
-        return new RStringToListVectorClosure(vector);
+    public static RAbstractListVector createToListVector(RStringVector vector, boolean keepAttributes) {
+        return new RStringToListVectorClosure(vector, keepAttributes);
     }
 
     // Factor to vector
 
     public static RAbstractVector createFactorToVector(RAbstractIntVector factor, boolean withNames, RAbstractVector levels) {
+        return createFactorToVector(factor, withNames, levels, false);
+    }
+
+    public static RAbstractVector createFactorToVector(RAbstractIntVector factor, boolean withNames, RAbstractVector levels, boolean keepAttributes) {
         if (levels instanceof RAbstractStringVector) {
-            return new RFactorToStringVectorClosure(factor, (RAbstractStringVector) levels, withNames);
+            return new RFactorToStringVectorClosure(factor, (RAbstractStringVector) levels, withNames, keepAttributes);
         } else {
             throw RError.error(RError.SHOW_CALLER, Message.MALFORMED_FACTOR);
         }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToComplexVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToComplexVectorClosure.java
index 5cad98744466bd4b3cbba1d60dd3105eca592304..3932e3c982f38996b40e23e04baf91063b7f6c74 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToComplexVectorClosure.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToComplexVectorClosure.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.data.closures;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
@@ -37,6 +38,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 
 abstract class RToComplexVectorClosure extends RToVectorClosure implements RAbstractComplexVector {
 
+    protected RToComplexVectorClosure(boolean keepAttributes) {
+        super(keepAttributes);
+    }
+
     @Override
     public final RVector<?> createEmptySameType(int newLength, boolean newIsComplete) {
         return RDataFactory.createComplexVector(new double[newLength << 1], newIsComplete);
@@ -52,12 +57,24 @@ abstract class RToComplexVectorClosure extends RToVectorClosure implements RAbst
             result[index] = data.getRealPart();
             result[index + 1] = data.getImaginaryPart();
         }
-        return RDataFactory.createComplexVector(result, getVector().isComplete());
+        RComplexVector materialized = RDataFactory.createComplexVector(result, getVector().isComplete());
+        copyAttributes(materialized);
+        return materialized;
+    }
+
+    @TruffleBoundary
+    private void copyAttributes(RComplexVector materialized) {
+        if (keepAttributes) {
+            materialized.initAttributes(getVector().getAttributes());
+        }
     }
 
     @Override
-    public final RComplexVector copyWithNewDimensions(int[] newDimensions) {
-        return materialize().copyWithNewDimensions(newDimensions);
+    public final RAbstractComplexVector copyWithNewDimensions(int[] newDimensions) {
+        if (keepAttributes) {
+            return materialize().copyWithNewDimensions(newDimensions);
+        }
+        return this;
     }
 }
 
@@ -65,7 +82,8 @@ final class RLogicalToComplexVectorClosure extends RToComplexVectorClosure imple
 
     private final RLogicalVector vector;
 
-    RLogicalToComplexVectorClosure(RLogicalVector vector) {
+    RLogicalToComplexVectorClosure(RLogicalVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -85,7 +103,8 @@ final class RIntToComplexVectorClosure extends RToComplexVectorClosure implement
 
     private final RIntVector vector;
 
-    RIntToComplexVectorClosure(RIntVector vector) {
+    RIntToComplexVectorClosure(RIntVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -105,7 +124,8 @@ final class RIntSequenceToComplexVectorClosure extends RToComplexVectorClosure i
 
     private final RIntSequence vector;
 
-    RIntSequenceToComplexVectorClosure(RIntSequence vector) {
+    RIntSequenceToComplexVectorClosure(RIntSequence vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -125,7 +145,8 @@ final class RDoubleToComplexVectorClosure extends RToComplexVectorClosure implem
 
     private final RDoubleVector vector;
 
-    RDoubleToComplexVectorClosure(RDoubleVector vector) {
+    RDoubleToComplexVectorClosure(RDoubleVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -145,7 +166,8 @@ final class RDoubleSequenceToComplexVectorClosure extends RToComplexVectorClosur
 
     private final RDoubleSequence vector;
 
-    RDoubleSequenceToComplexVectorClosure(RDoubleSequence vector) {
+    RDoubleSequenceToComplexVectorClosure(RDoubleSequence vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -165,7 +187,8 @@ final class RRawToComplexVectorClosure extends RToComplexVectorClosure implement
 
     private final RRawVector vector;
 
-    RRawToComplexVectorClosure(RRawVector vector) {
+    RRawToComplexVectorClosure(RRawVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToDoubleVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToDoubleVectorClosure.java
index 435498a961450703b5a71b82ba97343a63c8e0a5..79a57bf9fb9f29b3870406259ebeba2f9302e7ef 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToDoubleVectorClosure.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToDoubleVectorClosure.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.data.closures;
 
+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.RDoubleVector;
@@ -34,6 +35,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 
 abstract class RToDoubleVectorClosure extends RToVectorClosure implements RAbstractDoubleVector {
 
+    protected RToDoubleVectorClosure(boolean keepAttributes) {
+        super(keepAttributes);
+    }
+
     @Override
     public final RVector<?> createEmptySameType(int newLength, boolean newIsComplete) {
         return RDataFactory.createDoubleVector(new double[newLength], newIsComplete);
@@ -47,12 +52,24 @@ abstract class RToDoubleVectorClosure extends RToVectorClosure implements RAbstr
             double data = getDataAt(i);
             result[i] = data;
         }
-        return RDataFactory.createDoubleVector(result, getVector().isComplete());
+        RDoubleVector materialized = RDataFactory.createDoubleVector(result, getVector().isComplete());
+        copyAttributes(materialized);
+        return materialized;
+    }
+
+    @TruffleBoundary
+    private void copyAttributes(RDoubleVector materialized) {
+        if (keepAttributes) {
+            materialized.initAttributes(getVector().getAttributes());
+        }
     }
 
     @Override
-    public final RDoubleVector copyWithNewDimensions(int[] newDimensions) {
-        return materialize().copyWithNewDimensions(newDimensions);
+    public final RAbstractDoubleVector copyWithNewDimensions(int[] newDimensions) {
+        if (keepAttributes) {
+            return materialize().copyWithNewDimensions(newDimensions);
+        }
+        return this;
     }
 }
 
@@ -60,7 +77,8 @@ final class RLogicalToDoubleVectorClosure extends RToDoubleVectorClosure impleme
 
     private final RLogicalVector vector;
 
-    RLogicalToDoubleVectorClosure(RLogicalVector vector) {
+    RLogicalToDoubleVectorClosure(RLogicalVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -83,7 +101,8 @@ final class RIntToDoubleVectorClosure extends RToDoubleVectorClosure implements
 
     private final RIntVector vector;
 
-    RIntToDoubleVectorClosure(RIntVector vector) {
+    RIntToDoubleVectorClosure(RIntVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -106,7 +125,8 @@ final class RIntSequenceToDoubleVectorClosure extends RToDoubleVectorClosure imp
 
     private final RIntSequence vector;
 
-    RIntSequenceToDoubleVectorClosure(RIntSequence vector) {
+    RIntSequenceToDoubleVectorClosure(RIntSequence vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -129,7 +149,8 @@ final class RRawToDoubleVectorClosure extends RToDoubleVectorClosure implements
 
     private final RRawVector vector;
 
-    RRawToDoubleVectorClosure(RRawVector vector) {
+    RRawToDoubleVectorClosure(RRawVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToIntVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToIntVectorClosure.java
index 187b1260e7fcfd8951a4f6ec9346a295471144a3..6c925729975a0d1b883decff1924b03548041c2a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToIntVectorClosure.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToIntVectorClosure.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.data.closures;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RComplex;
@@ -37,6 +38,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 abstract class RToIntVectorClosure extends RToVectorClosure implements RAbstractIntVector {
 
+    protected RToIntVectorClosure(boolean keepAttributes) {
+        super(keepAttributes);
+    }
+
     @Override
     public final RVector<?> createEmptySameType(int newLength, boolean newIsComplete) {
         return RDataFactory.createIntVector(new int[newLength], newIsComplete);
@@ -50,12 +55,24 @@ abstract class RToIntVectorClosure extends RToVectorClosure implements RAbstract
             int data = getDataAt(i);
             result[i] = data;
         }
-        return RDataFactory.createIntVector(result, getVector().isComplete());
+        RIntVector materialized = RDataFactory.createIntVector(result, getVector().isComplete());
+        copyAttributes(materialized);
+        return materialized;
+    }
+
+    @TruffleBoundary
+    private void copyAttributes(RIntVector materialized) {
+        if (keepAttributes) {
+            materialized.copyAttributesFrom(getVector());
+        }
     }
 
     @Override
-    public final RIntVector copyWithNewDimensions(int[] newDimensions) {
-        return materialize().copyWithNewDimensions(newDimensions);
+    public final RAbstractIntVector copyWithNewDimensions(int[] newDimensions) {
+        if (keepAttributes) {
+            return materialize().copyWithNewDimensions(newDimensions);
+        }
+        return this;
     }
 }
 
@@ -63,7 +80,8 @@ final class RLogicalToIntVectorClosure extends RToIntVectorClosure implements RA
 
     private final RLogicalVector vector;
 
-    RLogicalToIntVectorClosure(RLogicalVector vector) {
+    RLogicalToIntVectorClosure(RLogicalVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -85,8 +103,10 @@ final class RLogicalToIntVectorClosure extends RToIntVectorClosure implements RA
 final class RDoubleToIntVectorClosure extends RToIntVectorClosure implements RAbstractIntVector {
 
     private final RDoubleVector vector;
+    private boolean naReported;
 
-    RDoubleToIntVectorClosure(RDoubleVector vector) {
+    RDoubleToIntVectorClosure(RDoubleVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -103,7 +123,10 @@ final class RDoubleToIntVectorClosure extends RToIntVectorClosure implements RAb
         }
         int result = (int) value;
         if (result == Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
-            RError.warning(RError.SHOW_CALLER2, RError.Message.NA_INTRODUCED_COERCION);
+            if (!naReported) {
+                RError.warning(RError.SHOW_CALLER2, RError.Message.NA_INTRODUCED_COERCION);
+                naReported = true;
+            }
             return RRuntime.INT_NA;
         }
         return result;
@@ -113,8 +136,10 @@ final class RDoubleToIntVectorClosure extends RToIntVectorClosure implements RAb
 final class RDoubleSequenceToIntVectorClosure extends RToIntVectorClosure implements RAbstractIntVector {
 
     private final RDoubleSequence vector;
+    private boolean naReported;
 
-    RDoubleSequenceToIntVectorClosure(RDoubleSequence vector) {
+    RDoubleSequenceToIntVectorClosure(RDoubleSequence vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -131,7 +156,10 @@ final class RDoubleSequenceToIntVectorClosure extends RToIntVectorClosure implem
         }
         int result = (int) value;
         if (result == Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
-            RError.warning(RError.SHOW_CALLER2, RError.Message.NA_INTRODUCED_COERCION);
+            if (!naReported) {
+                RError.warning(RError.SHOW_CALLER2, RError.Message.NA_INTRODUCED_COERCION);
+                naReported = true;
+            }
             return RRuntime.INT_NA;
         }
         return result;
@@ -145,7 +173,8 @@ final class RComplexToIntVectorClosure extends RToIntVectorClosure implements RA
 
     private final RComplexVector vector;
 
-    RComplexToIntVectorClosure(RComplexVector vector) {
+    RComplexToIntVectorClosure(RComplexVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -169,7 +198,8 @@ final class RRawToIntVectorClosure extends RToIntVectorClosure implements RAbstr
 
     private final RRawVector vector;
 
-    RRawToIntVectorClosure(RRawVector vector) {
+    RRawToIntVectorClosure(RRawVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToListVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToListVectorClosure.java
index 8a03a34c89bb72bc9b4f3e8ecf5b98c502ab0ace..f6ef8f334c63b9c3fde8cf8f676d23d21fb9352f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToListVectorClosure.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToListVectorClosure.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.data.closures;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -40,6 +41,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 abstract class RToListVectorClosure extends RToVectorClosure implements RAbstractListVector {
 
+    protected RToListVectorClosure(boolean keepAttributes) {
+        super(keepAttributes);
+    }
+
     @Override
     public Object getDataAtAsObject(int index) {
         return getDataAt(index);
@@ -53,12 +58,24 @@ abstract class RToListVectorClosure extends RToVectorClosure implements RAbstrac
             Object data = getDataAt(i);
             result[i] = data;
         }
-        return RDataFactory.createList(result);
+        RList materialized = RDataFactory.createList(result);
+        copyAttributes(materialized);
+        return materialized;
+    }
+
+    @TruffleBoundary
+    private void copyAttributes(RList materialized) {
+        if (keepAttributes) {
+            materialized.copyAttributesFrom(getVector());
+        }
     }
 
     @Override
     public RAbstractVector copyWithNewDimensions(int[] newDimensions) {
-        return materialize().copyWithNewDimensions(newDimensions);
+        if (!keepAttributes) {
+            return materialize().copyWithNewDimensions(newDimensions);
+        }
+        return this;
     }
 
     @Override
@@ -71,7 +88,8 @@ final class RLogicalToListVectorClosure extends RToListVectorClosure {
 
     private final RLogicalVector vector;
 
-    RLogicalToListVectorClosure(RLogicalVector vector) {
+    RLogicalToListVectorClosure(RLogicalVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -90,7 +108,8 @@ final class RIntToListVectorClosure extends RToListVectorClosure {
 
     private final RIntVector vector;
 
-    RIntToListVectorClosure(RIntVector vector) {
+    RIntToListVectorClosure(RIntVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -109,7 +128,8 @@ final class RIntSequenceToListVectorClosure extends RToListVectorClosure {
 
     private final RIntSequence vector;
 
-    RIntSequenceToListVectorClosure(RIntSequence vector) {
+    RIntSequenceToListVectorClosure(RIntSequence vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -128,7 +148,8 @@ final class RDoubleToListVectorClosure extends RToListVectorClosure {
 
     private final RDoubleVector vector;
 
-    RDoubleToListVectorClosure(RDoubleVector vector) {
+    RDoubleToListVectorClosure(RDoubleVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -147,7 +168,8 @@ final class RDoubleSequenceToListVectorClosure extends RToListVectorClosure {
 
     private final RDoubleSequence vector;
 
-    RDoubleSequenceToListVectorClosure(RDoubleSequence vector) {
+    RDoubleSequenceToListVectorClosure(RDoubleSequence vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -166,7 +188,8 @@ final class RComplexToListVectorClosure extends RToListVectorClosure {
 
     private final RComplexVector vector;
 
-    RComplexToListVectorClosure(RComplexVector vector) {
+    RComplexToListVectorClosure(RComplexVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -185,7 +208,8 @@ final class RStringToListVectorClosure extends RToListVectorClosure {
 
     private final RStringVector vector;
 
-    RStringToListVectorClosure(RStringVector vector) {
+    RStringToListVectorClosure(RStringVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -204,7 +228,8 @@ final class RRawToListVectorClosure extends RToListVectorClosure {
 
     private final RRawVector vector;
 
-    RRawToListVectorClosure(RRawVector vector) {
+    RRawToListVectorClosure(RRawVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToStringVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToStringVectorClosure.java
index e9a127adbd78625542c2c120db0d0964957c899e..904f0fa5bf53ca92e785bc1fc93564f2bf519a25 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToStringVectorClosure.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToStringVectorClosure.java
@@ -44,6 +44,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 abstract class RToStringVectorClosure extends RToVectorClosure implements RAbstractStringVector {
 
+    protected RToStringVectorClosure(boolean keepAttributes) {
+        super(keepAttributes);
+    }
+
     @Override
     public final RVector<?> createEmptySameType(int newLength, boolean newIsComplete) {
         return RDataFactory.createStringVector(new String[newLength], newIsComplete);
@@ -57,22 +61,24 @@ abstract class RToStringVectorClosure extends RToVectorClosure implements RAbstr
             String data = getDataAt(i);
             result[i] = data;
         }
-        return RDataFactory.createStringVector(result, getVector().isComplete(), getDimensionsMaterialized(), getNamesMaterialized());
+        RStringVector materialized = RDataFactory.createStringVector(result, getVector().isComplete());
+        copyAttributes(materialized);
+        return materialized;
     }
 
     @TruffleBoundary
-    private int[] getDimensionsMaterialized() {
-        return getDimensions();
-    }
-
-    @TruffleBoundary
-    private RStringVector getNamesMaterialized() {
-        return getNames();
+    private void copyAttributes(RStringVector materialized) {
+        if (keepAttributes) {
+            materialized.copyAttributesFrom(getVector());
+        }
     }
 
     @Override
-    public final RStringVector copyWithNewDimensions(int[] newDimensions) {
-        return materialize().copyWithNewDimensions(newDimensions);
+    public final RAbstractStringVector copyWithNewDimensions(int[] newDimensions) {
+        if (!keepAttributes) {
+            return materialize().copyWithNewDimensions(newDimensions);
+        }
+        return this;
     }
 }
 
@@ -80,7 +86,8 @@ final class RLogicalToStringVectorClosure extends RToStringVectorClosure {
 
     private final RLogicalVector vector;
 
-    RLogicalToStringVectorClosure(RLogicalVector vector) {
+    RLogicalToStringVectorClosure(RLogicalVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -104,7 +111,8 @@ final class RIntToStringVectorClosure extends RToStringVectorClosure {
 
     private final RIntVector vector;
 
-    RIntToStringVectorClosure(RIntVector vector) {
+    RIntToStringVectorClosure(RIntVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -127,7 +135,8 @@ final class RIntSequenceToStringVectorClosure extends RToStringVectorClosure {
 
     private final RIntSequence vector;
 
-    RIntSequenceToStringVectorClosure(RIntSequence vector) {
+    RIntSequenceToStringVectorClosure(RIntSequence vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -150,7 +159,8 @@ final class RDoubleToStringVectorClosure extends RToStringVectorClosure {
 
     private final RDoubleVector vector;
 
-    RDoubleToStringVectorClosure(RDoubleVector vector) {
+    RDoubleToStringVectorClosure(RDoubleVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -174,7 +184,8 @@ final class RDoubleSequenceToStringVectorClosure extends RToStringVectorClosure
 
     private final RDoubleSequence vector;
 
-    RDoubleSequenceToStringVectorClosure(RDoubleSequence vector) {
+    RDoubleSequenceToStringVectorClosure(RDoubleSequence vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -198,7 +209,8 @@ final class RComplexToStringVectorClosure extends RToStringVectorClosure {
 
     private final RComplexVector vector;
 
-    RComplexToStringVectorClosure(RComplexVector vector) {
+    RComplexToStringVectorClosure(RComplexVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -221,7 +233,8 @@ final class RRawToStringVectorClosure extends RToStringVectorClosure {
 
     private final RRawVector vector;
 
-    RRawToStringVectorClosure(RRawVector vector) {
+    RRawToStringVectorClosure(RRawVector vector, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
     }
 
@@ -245,7 +258,8 @@ final class RFactorToStringVectorClosure extends RToStringVectorClosure {
     private final RAbstractStringVector levels;
     private final boolean withNames;
 
-    RFactorToStringVectorClosure(RAbstractIntVector vector, RAbstractStringVector levels, boolean withNames) {
+    RFactorToStringVectorClosure(RAbstractIntVector vector, RAbstractStringVector levels, boolean withNames, boolean keepAttributes) {
+        super(keepAttributes);
         this.vector = vector;
         this.levels = levels;
         this.withNames = withNames;
@@ -257,7 +271,7 @@ final class RFactorToStringVectorClosure extends RToStringVectorClosure {
     }
 
     @Override
-    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, @SuppressWarnings("hiding") boolean keepAttributes) {
         switch (type) {
             case Character:
                 return this;
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 9d00bf9472669b9f2513206cfe1f9856c987bbe6..2f0146bee3eb5b7fc9c887c825786dfca23454fe 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
@@ -23,7 +23,8 @@
 package com.oracle.truffle.r.runtime.data.closures;
 
 import com.oracle.truffle.api.object.DynamicObject;
-import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
@@ -33,6 +34,13 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 abstract class RToVectorClosure implements RAbstractVector {
 
+    /** If {@code true}, attributes should be preserved when materializing. */
+    protected final boolean keepAttributes;
+
+    protected RToVectorClosure(boolean keepAttributes) {
+        this.keepAttributes = keepAttributes;
+    }
+
     public abstract RAbstractVector getVector();
 
     @Override
@@ -122,22 +130,22 @@ abstract class RToVectorClosure implements RAbstractVector {
 
     @Override
     public final RAbstractVector copy() {
-        throw RInternalError.shouldNotReachHere();
+        return materialize().copy();
     }
 
     @Override
     public final RVector<?> copyResized(int size, boolean fillNA) {
-        throw RInternalError.shouldNotReachHere();
+        return materialize().copyResized(size, fillNA);
     }
 
     @Override
     public final RVector<?> copyResizedWithDimensions(int[] newDimensions, boolean fillNA) {
-        throw RInternalError.shouldNotReachHere();
+        return materialize().copyResizedWithDimensions(newDimensions, fillNA);
     }
 
     @Override
     public final RAbstractVector copyDropAttributes() {
-        throw RInternalError.shouldNotReachHere();
+        return materialize().copyDropAttributes();
     }
 
     @Override
@@ -169,4 +177,11 @@ abstract class RToVectorClosure implements RAbstractVector {
     public boolean isS4() {
         return false;
     }
+
+    @Override
+    public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttrs) {
+        // Closures are trimmed to use a concrete type in order to avoid polymorphism. Therefore,
+        // first materialize and then cast and do not create a closure over a closure.
+        return materialize().castSafe(type, isNAProfile, keepAttrs);
+    }
 }
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 2d16b9fbeaaadc411d77f097171a685915f6d079..71f6d47c49f979d040449e7f9f0384763c502cab 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
@@ -68,9 +68,27 @@ public interface RAbstractVector extends RAbstractContainer {
      * implementation may decide to just wrap the original vector with a closure. This method is
      * optimized for invocation with a compile-time constant {@link RType}.
      *
+     * @see #castSafe(RType, ConditionProfile, boolean)
+     */
+    default RAbstractVector castSafe(RType type, ConditionProfile isNAProfile) {
+        return castSafe(type, isNAProfile, false);
+    }
+
+    /**
+     * 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
+     * implementation may decide to just wrap the original vector with a closure. This method is
+     * optimized for invocation with a compile-time constant {@link RType}.
+     *
+     * @param type
+     * @param isNAProfile
+     * @param keepAttributes If {@code true}, the cast itself will keep the attributes. This is,
+     *            however, a rather slow operation and you should set this to {@code false} and use
+     *            nodes for copying attributes if possible.
+     *
      * @see RType#getPrecedence()
      */
-    default RAbstractVector castSafe(RType type, @SuppressWarnings("unused") ConditionProfile isNAProfile) {
+    default RAbstractVector castSafe(RType type, @SuppressWarnings("unused") ConditionProfile isNAProfile, @SuppressWarnings("unused") boolean keepAttributes) {
         if (type == getRType()) {
             return this;
         } else {
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 dcb01ee548ac70950daf8f94469abd7aa8adf2c2..eb109fbe93ed659235e053747d6d184eed4293d6 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
@@ -930,7 +930,8 @@ public abstract class REnvironment extends RAttributeStorage {
         slots = namespacesFrame.getFrameDescriptor().getSlots().toArray(slots);
         for (int i = 0; i < slots.length; i++) {
             REnvironment namespaceEnv = (REnvironment) FrameSlotChangeMonitor.getValue(slots[i], namespacesFrame);
-            if (namespaceEnv != Base.baseNamespaceEnv()) {
+            // Could be 'null' due to multi slot data and an error during package loading
+            if (namespaceEnv != Base.baseNamespaceEnv() && namespaceEnv != null) {
                 // base namespace frame redirects all accesses to base frame and this would
                 // result in processing the slots twice
                 fun.apply(namespaceEnv.getFrame(), true);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java
index 47d82e72ec4d51d22f415a1e825236a9454ed16c..20c8cd97be5cb81f6d65261874828e7dc7d321cc 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java
@@ -853,6 +853,10 @@ public final class FrameSlotChangeMonitor {
 
     public static void setObjectAndInvalidate(Frame frame, FrameSlot frameSlot, Object newValue, boolean isNonLocal, BranchProfile invalidateProfile) {
         assert !ActiveBinding.isActiveBinding(newValue);
+        setAndInvalidate(frame, frameSlot, newValue, isNonLocal, invalidateProfile);
+    }
+
+    private static void setAndInvalidate(Frame frame, FrameSlot frameSlot, Object newValue, boolean isNonLocal, BranchProfile invalidateProfile) {
         FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
         if (FastROptions.SharedContexts.getBooleanValue() && info.possibleMultiSlot() && !RContext.isSingle()) {
             info.setMultiSlot(frame, frameSlot, newValue);
@@ -877,12 +881,7 @@ public final class FrameSlotChangeMonitor {
     }
 
     public static void setActiveBinding(Frame frame, FrameSlot frameSlot, ActiveBinding newValue, boolean isNonLocal, BranchProfile invalidateProfile) {
-        frame.setObject(frameSlot, newValue);
-        FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
-        if (info.needsInvalidation()) {
-            info.setValue(newValue, frameSlot);
-        }
-        checkAndInvalidate(frame, frameSlot, isNonLocal, invalidateProfile);
+        setAndInvalidate(frame, frameSlot, newValue, isNonLocal, invalidateProfile);
         getContainsNoActiveBindingAssumption(frame.getFrameDescriptor()).invalidate();
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RMath.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RMath.java
index 22dadebc92a20f82539d9fb72d3a4dd438ae4672..5db1157cc3a5b0c284dab5db488af80a56d9b158 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RMath.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RMath.java
@@ -34,6 +34,13 @@ import com.oracle.truffle.r.runtime.nmath.RMathError.MLError;
  */
 public final class RMath {
 
+    public static double sign(double x) {
+        if (Double.isNaN(x)) {
+            return x;
+        }
+        return ((x > 0) ? 1 : ((x == 0) ? 0 : -1));
+    }
+
     public static boolean mlValid(double d) {
         return !Double.isNaN(d);
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NAProfile.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NAProfile.java
index 9369eff3db4e8c5cdcd68a02b152227caed1b70d..084aec76db8bdbee914f6ec4a35ae48b8657ff8f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NAProfile.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NAProfile.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
@@ -58,6 +58,10 @@ public final class NAProfile {
         return profile.profile(RRuntime.isNA(value));
     }
 
+    public ConditionProfile getConditionProfile() {
+        return profile;
+    }
+
     public void ifNa(double value, Runnable runnable) {
         if (isNA(value)) {
             runnable.run();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
index eecc1c27b5f9536182fffd46fdddde09a55d3c1b..954b4408215496c42ecfb13cedfdc609bcdd657f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
@@ -18,13 +18,10 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
-import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.rng.mm.MarsagliaMulticarry;
 import com.oracle.truffle.r.runtime.rng.mt.MersenneTwister;
@@ -100,7 +97,7 @@ public class RRNG {
     public static final Integer SAME_SEED = null;
     private static final Kind DEFAULT_KIND = Kind.MERSENNE_TWISTER;
     private static final NormKind DEFAULT_NORM_KIND = NormKind.INVERSION;
-    private static final String RANDOM_SEED = ".Random.seed";
+    public static final String RANDOM_SEED = ".Random.seed";
     private static final double UINT_MAX = (double) Integer.MAX_VALUE * 2;
 
     public static final class ContextStateImpl implements RContext.ContextState {
@@ -108,6 +105,13 @@ public class RRNG {
         private final RandomNumberGenerator[] allGenerators;
         private NormKind currentNormKind;
 
+        /**
+         * Stores the current RNG seed. The type is Object because the user may assign an arbitrary
+         * value to variable {@value RRNG#RANDOM_SEED}. Allowed types are therefore any R value or
+         * an {@code int[]}.
+         */
+        public Object currentSeeds = RMissing.instance;
+
         private ContextStateImpl() {
             this.currentNormKind = DEFAULT_NORM_KIND;
             this.allGenerators = new RandomNumberGenerator[Kind.VALUES.length];
@@ -282,11 +286,7 @@ public class RRNG {
 
     @TruffleBoundary
     private static Object getDotRandomSeed() {
-        Object seed = REnvironment.globalEnv().get(RANDOM_SEED);
-        if (seed instanceof RPromise) {
-            seed = RContext.getRRuntimeASTAccess().forcePromise(RANDOM_SEED, seed);
-        }
-        return seed;
+        return RContext.getInstance().stateRNG.currentSeeds;
     }
 
     /**
@@ -327,14 +327,20 @@ public class RRNG {
         } else if (seeds instanceof RIntVector) {
             RIntVector seedsVec = (RIntVector) seeds;
             tmp = seedsVec.getLength() == 0 ? RRuntime.INT_NA : seedsVec.getDataAt(0);
+        } else if (seeds instanceof int[]) {
+            int[] seedsArr = (int[]) seeds;
+            tmp = seedsArr.length == 0 ? RRuntime.INT_NA : seedsArr[0];
         } else {
-            assert seeds != RMissing.instance;
             assert seeds instanceof RTypedValue;
-            RError.warning(RError.NO_CALLER, RError.Message.SEED_TYPE, ((RTypedValue) seeds).getRType().getName());
+            // allow RMissing to indicate that ".Random.seed" has not been initialized yet
+            if (seeds != RMissing.instance) {
+                RError.warning(RError.NO_CALLER, RError.Message.SEED_TYPE, ((RTypedValue) seeds).getRType().getName());
+            }
             handleInvalidSeed();
             return;
         }
         if (tmp == RRuntime.INT_NA || tmp < 0 || tmp > 1000) {
+            assert seeds != RMissing.instance;
             String type = seeds instanceof RTypedValue ? ((RTypedValue) seeds).getRType().getName() : "unknown";
             RError.warning(RError.NO_CALLER, RError.Message.SEED_TYPE, type);
             handleInvalidSeed();
@@ -386,6 +392,12 @@ public class RRNG {
                     // no change of the .Random.seed variable
                     return;
                 }
+            } else if (seedsObj instanceof int[]) {
+                seeds = (int[]) seedsObj;
+                if (seeds == currentGenerator().getSeeds()) {
+                    // no change of the .Random.seed variable
+                    return;
+                }
             } else {
                 // seedsObj is not valid, which should have been reported and fixed in getRNGKind
                 return;
@@ -410,7 +422,6 @@ public class RRNG {
     public static void putRNGState() {
         int[] seeds = currentGenerator().getSeeds();
         seeds[0] = currentKind().ordinal() + 100 * currentNormKind().ordinal();
-        RIntVector vector = RDataFactory.createIntVector(seeds, RDataFactory.INCOMPLETE_VECTOR);
-        REnvironment.globalEnv().safePut(RANDOM_SEED, vector.makeSharedPermanent());
+        RContext.getInstance().stateRNG.currentSeeds = seeds;
     }
 }
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 dc5be133758935e9793c7928f2c44168ad2c843e..35e626cff237e38f505e8f81d7783ab4d59a2614 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
@@ -1,6 +1,6 @@
 ##com.oracle.truffle.r.test.S4.TestR5.testAllocation#
-#env0 <- new.env(); setRefClass('Foo17R5', where = env0); ls(topenv(parent.frame()), all.names = T); ls(env0, all.names = T)
-[1] "env0"
+#env0 <- new.env(); setRefClass('Foo17R5', where = env0); grep('Foo17R5', ls(topenv(parent.frame()), all.names = T), value = TRUE); ls(env0, all.names = T)
+character(0)
 [1] ".__C__Foo17R5"          ".__global__"            ".requireCachedGenerics"
 
 ##com.oracle.truffle.r.test.S4.TestR5.testAllocation#
@@ -31,8 +31,8 @@ In methods::initRefFields(.Object, classDef, selfEnv, list(...)) :
   unnamed arguments to $new() must be objects from a reference class; got an object of class “numeric”
 
 ##com.oracle.truffle.r.test.S4.TestR5.testAllocation#
-#{ setRefClass('Foo16R5'); ls(topenv(parent.frame()), all.names = T) }
-[1] ".__C__Foo16R5"          ".__global__"            ".requireCachedGenerics"
+#{ setRefClass('Foo16R5'); grep('Foo16R5', ls(topenv(parent.frame()), all.names = T), value = TRUE) }
+[1] ".__C__Foo16R5"
 
 ##com.oracle.truffle.r.test.S4.TestR5.testAttributes#
 #{ clazz <- setRefClass('Foo13R5'); clazz$methods() }
@@ -6928,6 +6928,12 @@ NAs introduced by coercion
 #{ as.integer(c(1.0,2.5,3.9)) }
 [1] 1 2 3
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_asinteger.testAsInteger#
+#{ as.integer(c(100, -1e-13, Inf, -Inf, NaN, 3.14159265358979, NA)) }
+[1] 100   0  NA  NA  NA   3  NA
+Warning message:
+NAs introduced by coercion to integer range
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_asinteger.testAsInteger#Output.IgnoreWarningContext#
 #{ as.integer(c(3+3i, 4+4i)) }
 [1] 3 4
@@ -69567,6 +69573,86 @@ Error in t.default(new.env()) : argument is not a matrix
 b 1
 c 2
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeNonSquare#
+#{ m <- matrix(1:8, 2, 4) ; t(m) }
+     [,1] [,2]
+[1,]    1    2
+[2,]    3    4
+[3,]    5    6
+[4,]    7    8
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeNonSquare#
+#{ m <- matrix(as.raw(c(1:8)), 2, 4); t(m) }
+     [,1] [,2]
+[1,]   01   02
+[2,]   03   04
+[3,]   05   06
+[4,]   07   08
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeNonSquare#
+#{ m <- matrix(c('1', '2', '3', '4', '5', '6', '7', '8'), 2, 4); t(m) }
+     [,1] [,2]
+[1,] "1"  "2"
+[2,] "3"  "4"
+[3,] "5"  "6"
+[4,] "7"  "8"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeNonSquare#
+#{ m <- matrix(c(T, F, F, F, T, F, F, T), 2, 4); t(m) }
+      [,1]  [,2]
+[1,]  TRUE FALSE
+[2,] FALSE FALSE
+[3,]  TRUE FALSE
+[4,] FALSE  TRUE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeNonSquare#
+#{ m <- matrix(list(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8), 2, 4); t(m) }
+     [,1] [,2]
+[1,] 1    2
+[2,] 3    4
+[3,] 5    6
+[4,] 7    8
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeNonSquare#
+#{ m <- matrix(seq(0.1,0.8,0.1), 2, 4) ; t(m) }
+     [,1] [,2]
+[1,]  0.1  0.2
+[2,]  0.3  0.4
+[3,]  0.5  0.6
+[4,]  0.7  0.8
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeSquare#
+#{ m <- matrix(1:64, 8, 8) ; sum(m * t(m)) }
+[1] 72976
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeSquare#
+#{ m <- matrix(as.raw(c(1,2,3,4)), 2, 2); t(m) }
+     [,1] [,2]
+[1,]   01   02
+[2,]   03   04
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeSquare#
+#{ m <- matrix(c('1', '2', '3', '4'), 2, 2); t(m) }
+     [,1] [,2]
+[1,] "1"  "2"
+[2,] "3"  "4"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeSquare#
+#{ m <- matrix(c(T, T, F, F), 2, 2); t(m) }
+      [,1]  [,2]
+[1,]  TRUE  TRUE
+[2,] FALSE FALSE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeSquare#
+#{ m <- matrix(list(a=1,b=2,c=3,d=4), 2, 2); t(m) }
+     [,1] [,2]
+[1,] 1    2
+[2,] 3    4
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTransposeSquare#
+#{ m <- matrix(seq(0.01,0.64,0.01), 8, 8) ; sum(m * t(m)) }
+[1] 7.2976
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testt1#
 #argv <- structure(list(x = c(-2.13777446721376, 1.17045456767922,     5.85180137819007)), .Names = 'x');do.call('t', argv)
           [,1]     [,2]     [,3]
@@ -75123,6 +75209,10 @@ imaginary parts discarded in coercion
 #{ as.vector(list(1,2,3), mode="integer") }
 [1] 1 2 3
 
+##com.oracle.truffle.r.test.builtins.TestMiscBuiltins.testCasts#
+#{ env <- new.env(); env$x<-7; env$.y<-42; length(as.list(env, all.names=TRUE)) }
+[1] 2
+
 ##com.oracle.truffle.r.test.builtins.TestMiscBuiltins.testCasts#
 #{ k <- as.list(3:6) ; l <- as.list(1) ; list(k,l) }
 [[1]]
@@ -75261,10 +75351,6 @@ $x
 [1] 7
 
 
-##com.oracle.truffle.r.test.builtins.TestMiscBuiltins.testCasts#
-#{ x<-7; .y<-42; length(as.list(environment(), all.names=TRUE)) }
-[1] 2
-
 ##com.oracle.truffle.r.test.builtins.TestMiscBuiltins.testCasts#
 #{ x<-7; as.list(environment()) }
 $x
@@ -148043,6 +148129,330 @@ Error: argument 'files' must be character
 Error in stats::complete.cases(data.frame(col1 = c(1, 2, NA), col2 = c(1,  :
   not all arguments have the same length
 
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='a', method='k')
+[1] -0.5477226
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='a', method='p')
+[1] -0.6024641
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='a', method='s')
+[1] -0.6324555
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='c', method='k')
+[1] -0.5477226
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='c', method='p')
+[1] -0.6024641
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='c', method='s')
+[1] -0.6324555
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='e', method='k')
+[1] -0.5477226
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='e', method='p')
+[1] -0.6024641
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='e', method='s')
+[1] -0.6324555
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='n', method='k')
+[1] -0.5477226
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='n', method='p')
+[1] -0.6024641
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='n', method='s')
+[1] -0.6324555
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='p', method='k')
+[1] -0.5477226
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='p', method='p')
+[1] -0.6024641
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(1:4, c(1,7,1,-4), use='p', method='s')
+[1] -0.6324555
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='a', method='k')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.7953134 -0.7681311 -0.7428125
+cyl  -0.7953134  1.0000000  0.8144263  0.7851865
+disp -0.7681311  0.8144263  1.0000000  0.6659987
+hp   -0.7428125  0.7851865  0.6659987  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='a', method='p')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.8521620 -0.8475514 -0.7761684
+cyl  -0.8521620  1.0000000  0.9020329  0.8324475
+disp -0.8475514  0.9020329  1.0000000  0.7909486
+hp   -0.7761684  0.8324475  0.7909486  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='a', method='s')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.9108013 -0.9088824 -0.8946646
+cyl  -0.9108013  1.0000000  0.9276516  0.9017909
+disp -0.9088824  0.9276516  1.0000000  0.8510426
+hp   -0.8946646  0.9017909  0.8510426  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='c', method='k')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.7953134 -0.7681311 -0.7428125
+cyl  -0.7953134  1.0000000  0.8144263  0.7851865
+disp -0.7681311  0.8144263  1.0000000  0.6659987
+hp   -0.7428125  0.7851865  0.6659987  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='c', method='p')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.8521620 -0.8475514 -0.7761684
+cyl  -0.8521620  1.0000000  0.9020329  0.8324475
+disp -0.8475514  0.9020329  1.0000000  0.7909486
+hp   -0.7761684  0.8324475  0.7909486  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='c', method='s')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.9108013 -0.9088824 -0.8946646
+cyl  -0.9108013  1.0000000  0.9276516  0.9017909
+disp -0.9088824  0.9276516  1.0000000  0.8510426
+hp   -0.8946646  0.9017909  0.8510426  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='e', method='k')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.7953134 -0.7681311 -0.7428125
+cyl  -0.7953134  1.0000000  0.8144263  0.7851865
+disp -0.7681311  0.8144263  1.0000000  0.6659987
+hp   -0.7428125  0.7851865  0.6659987  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='e', method='p')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.8521620 -0.8475514 -0.7761684
+cyl  -0.8521620  1.0000000  0.9020329  0.8324475
+disp -0.8475514  0.9020329  1.0000000  0.7909486
+hp   -0.7761684  0.8324475  0.7909486  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='e', method='s')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.9108013 -0.9088824 -0.8946646
+cyl  -0.9108013  1.0000000  0.9276516  0.9017909
+disp -0.9088824  0.9276516  1.0000000  0.8510426
+hp   -0.8946646  0.9017909  0.8510426  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='n', method='k')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.7953134 -0.7681311 -0.7428125
+cyl  -0.7953134  1.0000000  0.8144263  0.7851865
+disp -0.7681311  0.8144263  1.0000000  0.6659987
+hp   -0.7428125  0.7851865  0.6659987  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='n', method='p')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.8521620 -0.8475514 -0.7761684
+cyl  -0.8521620  1.0000000  0.9020329  0.8324475
+disp -0.8475514  0.9020329  1.0000000  0.7909486
+hp   -0.7761684  0.8324475  0.7909486  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='n', method='s')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.9108013 -0.9088824 -0.8946646
+cyl  -0.9108013  1.0000000  0.9276516  0.9017909
+disp -0.9088824  0.9276516  1.0000000  0.8510426
+hp   -0.8946646  0.9017909  0.8510426  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='p', method='k')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.7953134 -0.7681311 -0.7428125
+cyl  -0.7953134  1.0000000  0.8144263  0.7851865
+disp -0.7681311  0.8144263  1.0000000  0.6659987
+hp   -0.7428125  0.7851865  0.6659987  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='p', method='p')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.8521620 -0.8475514 -0.7761684
+cyl  -0.8521620  1.0000000  0.9020329  0.8324475
+disp -0.8475514  0.9020329  1.0000000  0.7909486
+hp   -0.7761684  0.8324475  0.7909486  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cor(mtcars[,1:4], use='p', method='s')
+            mpg        cyl       disp         hp
+mpg   1.0000000 -0.9108013 -0.9088824 -0.8946646
+cyl  -0.9108013  1.0000000  0.9276516  0.9017909
+disp -0.9088824  0.9276516  1.0000000  0.8510426
+hp   -0.8946646  0.9017909  0.8510426  1.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='a', method='k')
+[1] -6
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='a', method='p')
+[1] -3.5
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='a', method='s')
+[1] -1
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='c', method='k')
+[1] -6
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='c', method='p')
+[1] -3.5
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='c', method='s')
+[1] -1
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='e', method='k')
+[1] -6
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='e', method='p')
+[1] -3.5
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='e', method='s')
+[1] -1
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='n', method='k')
+[1] -6
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='n', method='p')
+[1] -3.5
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(1:4, c(1,7,1,-4), use='n', method='s')
+[1] -1
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='a', method='k')
+      mpg  cyl disp   hp
+mpg   978 -638 -752 -722
+cyl  -638  658  654  626
+disp -752  654  980  648
+hp   -722  626  648  966
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='a', method='p')
+             mpg        cyl       disp        hp
+mpg    36.324103  -9.172379  -633.0972 -320.7321
+cyl    -9.172379   3.189516   199.6603  101.9315
+disp -633.097208 199.660282 15360.7998 6721.1587
+hp   -320.732056 101.931452  6721.1587 4700.8669
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='a', method='s')
+           mpg       cyl      disp        hp
+mpg   87.88710 -74.54032 -79.87903 -78.56452
+cyl  -74.54032  76.20968  75.91935  73.74194
+disp -79.87903  75.91935  87.88710  74.73387
+hp   -78.56452  73.74194  74.73387  87.74194
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='c', method='k')
+      mpg  cyl disp   hp
+mpg   978 -638 -752 -722
+cyl  -638  658  654  626
+disp -752  654  980  648
+hp   -722  626  648  966
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='c', method='p')
+             mpg        cyl       disp        hp
+mpg    36.324103  -9.172379  -633.0972 -320.7321
+cyl    -9.172379   3.189516   199.6603  101.9315
+disp -633.097208 199.660282 15360.7998 6721.1587
+hp   -320.732056 101.931452  6721.1587 4700.8669
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='c', method='s')
+           mpg       cyl      disp        hp
+mpg   87.88710 -74.54032 -79.87903 -78.56452
+cyl  -74.54032  76.20968  75.91935  73.74194
+disp -79.87903  75.91935  87.88710  74.73387
+hp   -78.56452  73.74194  74.73387  87.74194
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='e', method='k')
+      mpg  cyl disp   hp
+mpg   978 -638 -752 -722
+cyl  -638  658  654  626
+disp -752  654  980  648
+hp   -722  626  648  966
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='e', method='p')
+             mpg        cyl       disp        hp
+mpg    36.324103  -9.172379  -633.0972 -320.7321
+cyl    -9.172379   3.189516   199.6603  101.9315
+disp -633.097208 199.660282 15360.7998 6721.1587
+hp   -320.732056 101.931452  6721.1587 4700.8669
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='e', method='s')
+           mpg       cyl      disp        hp
+mpg   87.88710 -74.54032 -79.87903 -78.56452
+cyl  -74.54032  76.20968  75.91935  73.74194
+disp -79.87903  75.91935  87.88710  74.73387
+hp   -78.56452  73.74194  74.73387  87.74194
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='n', method='k')
+      mpg  cyl disp   hp
+mpg   978 -638 -752 -722
+cyl  -638  658  654  626
+disp -752  654  980  648
+hp   -722  626  648  966
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='n', method='p')
+             mpg        cyl       disp        hp
+mpg    36.324103  -9.172379  -633.0972 -320.7321
+cyl    -9.172379   3.189516   199.6603  101.9315
+disp -633.097208 199.660282 15360.7998 6721.1587
+hp   -320.732056 101.931452  6721.1587 4700.8669
+
+##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCombinations#
+#cov(mtcars[,1:4], use='n', method='s')
+           mpg       cyl      disp        hp
+mpg   87.88710 -74.54032 -79.87903 -78.56452
+cyl  -74.54032  76.20968  75.91935  73.74194
+disp -79.87903  75.91935  87.88710  74.73387
+hp   -78.56452  73.74194  74.73387  87.74194
+
 ##com.oracle.truffle.r.test.library.stats.TestExternal_covcor.testCovcor#
 #.Call(stats:::C_cov, 1:5, 1:5, 4, FALSE)
 [1] 2.5
@@ -156014,7 +156424,7 @@ non-integer value 12345678909876543212L qualified with L; using numeric value
 [619]  -346017954 -1916029881 -1735526436  1461823277   580724746  -622095869
 [625]  -686746776   705745481
 
-##com.oracle.truffle.r.test.rng.TestRRNG.testDirectSeedAssignment#Output.IgnoreWarningContext#
+##com.oracle.truffle.r.test.rng.TestRRNG.testDirectSeedAssignment#Output.IgnoreWarningContext#Output.MayIgnoreWarningContext#
 #.Random.seed <- c(401, 1, 2); invisible(runif(3))
 Warning message:
 In runif(3) :
@@ -156024,7 +156434,7 @@ In runif(3) :
 #.Random.seed <- c(401L, 1L, 2L); runif(3)
 [1] 0.5641106 0.2932388 0.6696743
 
-##com.oracle.truffle.r.test.rng.TestRRNG.testDirectSeedAssignment#Output.IgnoreWarningContext#
+##com.oracle.truffle.r.test.rng.TestRRNG.testDirectSeedAssignment#Output.IgnoreWarningContext#Output.MayIgnoreWarningContext#
 #.Random.seed <- c(999, 1, 2); invisible(runif(3))
 Warning message:
 In runif(3) :
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestR5.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestR5.java
index 650fb03db0860ee18a8e074044891c0b9b4e0fd1..e263c2eaa1b6fd3eaf8f67315d8dd993f3691f35 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestR5.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestR5.java
@@ -49,8 +49,8 @@ public class TestR5 extends TestBase {
         assertEval("{ DummyClass2 <- setRefClass('DummyClass2'); obj <- DummyClass2$new(); is(obj, 'refObject') }");
         assertEval("{ fooClass <- setRefClass('Foo6R5', fields = list( a = 'numeric')); fooClass$new(a = 1) }");
         assertEval("{ fooClass <- setRefClass('Foo7R5', fields = list( a = 'numeric')); fooClass$new(1) }");
-        assertEval("{ setRefClass('Foo16R5'); ls(topenv(parent.frame()), all.names = T) }");
-        assertEval("env0 <- new.env(); setRefClass('Foo17R5', where = env0); ls(topenv(parent.frame()), all.names = T); ls(env0, all.names = T)");
+        assertEval("{ setRefClass('Foo16R5'); grep('Foo16R5', ls(topenv(parent.frame()), all.names = T), value = TRUE) }");
+        assertEval("env0 <- new.env(); setRefClass('Foo17R5', where = env0); grep('Foo17R5', ls(topenv(parent.frame()), all.names = T), value = TRUE); ls(env0, all.names = T)");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asinteger.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asinteger.java
index 19aeddb65d4d96a5da38c47f76af20880fac9004..a50e12c6b81ab1ec737b653fa8a9dbb25323af97 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asinteger.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asinteger.java
@@ -147,5 +147,6 @@ public class TestBuiltin_asinteger extends TestBase {
         assertEval("{ as.integer(as.character(NA)) }");
         assertEval("{ as.integer(\"1\", as.character(NA)) }");
         assertEval("{ as.integer.cls <- function(x) 42; as.integer(structure(c(1,2), class='cls')); }");
+        assertEval("{ as.integer(c(100, -1e-13, Inf, -Inf, NaN, 3.14159265358979, NA)) }");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.java
index b4640e1d0567158ad6dba2e8ccfc5be46df9f85a..ca5b37d80674154befc4b2ec214dc4a11909ea31 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.java
@@ -48,4 +48,26 @@ public class TestBuiltin_t extends TestBase {
         assertEval("t(as.raw(c(1,2,3,4)))");
         assertEval("t(matrix(1:6, 3, 2, dimnames=list(x=c(\"x1\",\"x2\",\"x3\"),y=c(\"y1\",\"y2\"))))");
     }
+
+    @Test
+    public void testTransposeSquare() {
+        // test square matrices
+        assertEval("{ m <- matrix(1:64, 8, 8) ; sum(m * t(m)) }");
+        assertEval("{ m <- matrix(seq(0.01,0.64,0.01), 8, 8) ; sum(m * t(m)) }");
+        assertEval("{ m <- matrix(c(T, T, F, F), 2, 2); t(m) }");
+        assertEval("{ m <- matrix(c('1', '2', '3', '4'), 2, 2); t(m) }");
+        assertEval("{ m <- matrix(as.raw(c(1,2,3,4)), 2, 2); t(m) }");
+        assertEval("{ m <- matrix(list(a=1,b=2,c=3,d=4), 2, 2); t(m) }");
+    }
+
+    @Test
+    public void testTransposeNonSquare() {
+        // test square matrices
+        assertEval("{ m <- matrix(1:8, 2, 4) ; t(m) }");
+        assertEval("{ m <- matrix(seq(0.1,0.8,0.1), 2, 4) ; t(m) }");
+        assertEval("{ m <- matrix(c(T, F, F, F, T, F, F, T), 2, 4); t(m) }");
+        assertEval("{ m <- matrix(c('1', '2', '3', '4', '5', '6', '7', '8'), 2, 4); t(m) }");
+        assertEval("{ m <- matrix(as.raw(c(1:8)), 2, 4); t(m) }");
+        assertEval("{ m <- matrix(list(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8), 2, 4); t(m) }");
+    }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestMiscBuiltins.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestMiscBuiltins.java
index a298e3af601c7bf86a6088d86fa9236510b0457b..d2da41043eeffeee9a0cb48b3914c734195706a9 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestMiscBuiltins.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestMiscBuiltins.java
@@ -90,7 +90,7 @@ public class TestMiscBuiltins extends TestBase {
         assertEval("{ x<-7; as.list(environment()) }");
         assertEval("{ x<-7; .y<-42; as.list(environment()) }");
         // not sorted so can't compare list print
-        assertEval("{ x<-7; .y<-42; length(as.list(environment(), all.names=TRUE)) }");
+        assertEval("{ env <- new.env(); env$x<-7; env$.y<-42; length(as.list(env, all.names=TRUE)) }");
         assertEval("{ x<-7; f<-function() x<<-42; f_copy<-as.list(environment())[[\"f\"]]; f_copy(); x }");
 
         // as.matrix
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_covcor.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_covcor.java
index 5f548a2355f67085dc227c71caed04103bece6e7..fe08b63966fe6a4eac773b268a55517cbedc9367 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_covcor.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_covcor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -40,4 +40,15 @@ public class TestExternal_covcor extends TestBase {
         assertEval(".Call(stats:::C_cov, NULL, 1:5, 4, FALSE)");
         assertEval(".Call(stats:::C_cov, 1:3, 1:5, 4, FALSE)");
     }
+
+    @Test
+    public void testCombinations() {
+        String[] useCor = new String[]{"e", "a", "c", "n", "p"};
+        String[] useCov = new String[]{"e", "a", "c", "n"};
+        String[] methods = new String[]{"p", "k", "s"};
+        assertEval(template("cor(mtcars[,1:4], use='%0', method='%1')", useCor, methods));
+        assertEval(template("cor(1:4, c(1,7,1,-4), use='%0', method='%1')", useCor, methods));
+        assertEval(template("cov(mtcars[,1:4], use='%0', method='%1')", useCov, methods));
+        assertEval(template("cov(1:4, c(1,7,1,-4), use='%0', method='%1')", useCov, methods));
+    }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rng/TestRRNG.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rng/TestRRNG.java
index b578868551d8e969ee14175f6d268f234077b164..dc4faf27a83efd6bd9e3d5fb6a04a696f129ae6c 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rng/TestRRNG.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rng/TestRRNG.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -32,9 +32,9 @@ public class TestRRNG extends TestBase {
         // changes generator to MarsagliaMulticarry and sets its 2 seeds
         assertEval(".Random.seed <- c(401L, 1L, 2L); runif(3)");
         // wrong values: not integer
-        assertEval(Output.IgnoreWarningContext, ".Random.seed <- c(401, 1, 2); invisible(runif(3))");
+        assertEval(Output.IgnoreWarningContext, Output.MayIgnoreWarningContext, ".Random.seed <- c(401, 1, 2); invisible(runif(3))");
         // wrong values: wrong generator number
-        assertEval(Output.IgnoreWarningContext, ".Random.seed <- c(999, 1, 2); invisible(runif(3))");
+        assertEval(Output.IgnoreWarningContext, Output.MayIgnoreWarningContext, ".Random.seed <- c(999, 1, 2); invisible(runif(3))");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
index a419f8ff22805537f4df67539b1f2b4e7cfd2fb4..fb0161aacfad939b1c3475d327fdcde757e78a67 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
@@ -488,7 +488,7 @@ public class FastRDebugTest {
                 assertEquals(line, currentLine);
                 final String currentCode = suspendedEvent.getSourceSection().getCode().trim();
                 assertEquals(code, currentCode);
-                compareScope(line, code, false, true, expectedFrame);
+                compareScope(line, code, false, false, expectedFrame);
             } catch (RuntimeException | Error e) {
 
                 final DebugStackFrame frame = suspendedEvent.getTopStackFrame();