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 62a3e4bb2b873db16ebc06b620aced31690a5563..5ff5d597cf36b3956e332061d0db965f6e28ce95 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
@@ -51,13 +51,15 @@ import com.oracle.truffle.r.nodes.RASTBuilder;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinPackages;
-import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNode;
+import com.oracle.truffle.r.nodes.builtin.base.printer.ValuePrinterNode;
 import com.oracle.truffle.r.nodes.control.BreakException;
 import com.oracle.truffle.r.nodes.control.NextException;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
+import com.oracle.truffle.r.nodes.function.CallMatcherNode.CallMatcherGenericNode;
 import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation;
-import com.oracle.truffle.r.runtime.JumpToTopLevelException;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.FastROptions;
+import com.oracle.truffle.r.runtime.JumpToTopLevelException;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RError;
@@ -66,8 +68,8 @@ import com.oracle.truffle.r.runtime.RInternalError;
 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.RStartParams.SA_TYPE;
 import com.oracle.truffle.r.runtime.RSource;
+import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE;
 import com.oracle.truffle.r.runtime.ReturnException;
 import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
 import com.oracle.truffle.r.runtime.ThreadTimings;
@@ -76,6 +78,7 @@ import com.oracle.truffle.r.runtime.Utils.DebugExitException;
 import com.oracle.truffle.r.runtime.VirtualEvalFrame;
 import com.oracle.truffle.r.runtime.context.Engine;
 import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -84,6 +87,7 @@ 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.RShareable;
+import com.oracle.truffle.r.runtime.data.RStringVector;
 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;
@@ -381,7 +385,7 @@ final class REngine implements Engine, Engine.Timings {
 
     @Override
     @TruffleBoundary
-    public Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, Object... args) {
+    public Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, RStringVector names, Object... args) {
         assert frame == null || caller != null;
         MaterializedFrame actualFrame = frame;
         if (actualFrame == null) {
@@ -393,7 +397,17 @@ final class REngine implements Engine, Engine.Timings {
                 actualFrame = current.materialize();
             }
         }
-        Object[] rArgs = RArguments.create(func, caller == null ? RArguments.getCall(actualFrame) : caller, actualFrame, args, null);
+        RArgsValuesAndNames reorderedArgs = CallMatcherGenericNode.reorderArguments(args, func,
+                        names == null ? ArgumentsSignature.empty(args.length) : ArgumentsSignature.get(names.getDataWithoutCopying()), false,
+                        RError.NO_CALLER);
+        Object[] newArgs = reorderedArgs.getArguments();
+        for (int i = 0; i < newArgs.length; i++) {
+            Object arg = newArgs[i];
+            if (arg instanceof RPromise) {
+                newArgs[i] = PromiseHelperNode.evaluateSlowPath(null, (RPromise) arg);
+            }
+        }
+        Object[] rArgs = RArguments.create(func, caller == null ? RArguments.getCall(actualFrame) : caller, actualFrame, newArgs, null);
         return func.getTarget().call(rArgs);
     }
 
@@ -570,7 +584,7 @@ final class REngine implements Engine, Engine.Timings {
         result = RRuntime.asAbstractVector(result);
         // this supports printing of non-R values (via toString for now)
         if (result instanceof RTypedValue) {
-            return PrettyPrinterNode.prettyPrintDefault(result);
+            return ValuePrinterNode.prettyPrint(result);
         } else if (result == null) {
             return "[external object (null)]";
         } else if (result instanceof TruffleObject) {
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
index 29700d0b926722999fa95f84fde571c2ebeb4468..4939a7e6690cc8f6a80366fc5950fe72ea08dc0a 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
@@ -366,14 +366,14 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
 
     @Override
     public Object callback(RFunction f, Object[] args) {
-        boolean gd = DebugHandling.globalDisable(true);
+        boolean gd = RContext.getInstance().stateInstrumentation.setDebugGloballyDisabled(true);
         try {
-            return RContext.getEngine().evalFunction(f, null, null, args);
+            return RContext.getEngine().evalFunction(f, null, null, null, args);
         } catch (ReturnException ex) {
             // cannot throw return exceptions further up.
             return ex.getResult();
         } finally {
-            DebugHandling.globalDisable(gd);
+            RContext.getInstance().stateInstrumentation.setDebugGloballyDisabled(gd);
         }
     }
 
@@ -646,7 +646,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
 
     @Override
     public boolean enableDebug(RFunction func, boolean once) {
-        return DebugHandling.enableDebug(func, "", RNull.instance, once);
+        return DebugHandling.enableDebug(func, "", RNull.instance, once, false);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.native/gnur/Makefile.gnur b/com.oracle.truffle.r.native/gnur/Makefile.gnur
index 76eb523030ffa5275c1111b968117073b6311ec0..238eb6c3e5a21fa21ec597b8d78257f57b055d68 100644
--- a/com.oracle.truffle.r.native/gnur/Makefile.gnur
+++ b/com.oracle.truffle.r.native/gnur/Makefile.gnur
@@ -116,7 +116,7 @@ endif
 
 $(GNUR_HOME)/Makefile:
 	ed $(GNUR_HOME)/src/extra/xz/Makefile.in < patchXzMakefile
-	(cd $(GNUR_HOME); ./configure --with-x=no --without-recommended-packages $(GNUR_CONFIG_FLAGS) > gnur_configure.log 2>&1)
+	(cd $(GNUR_HOME); ./configure --with-x=no --without-recommended-packages --enable-memory-profiling $(GNUR_CONFIG_FLAGS) > gnur_configure.log 2>&1)
 
 build: $(GNUR_HOME)/bin/R
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
index 90def9d1d66e671944f5d9db7dbce3a4ab77cf64..8e8df708cc2813a6e1311a8115502b8328734c75 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
@@ -69,6 +69,7 @@ import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypes;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 
 @RBuiltin(name = "as.vector", kind = INTERNAL, parameterNames = {"x", "mode"})
 public abstract class AsVector extends RBuiltinNode {
@@ -207,12 +208,20 @@ public abstract class AsVector extends RBuiltinNode {
         }
 
         @Specialization(guards = "modeIsPairList(mode)")
+        @TruffleBoundary
         protected Object asVectorPairList(RList x, @SuppressWarnings("unused") String mode) {
             // TODO implement non-empty element list conversion; this is a placeholder for type test
             if (x.getLength() == 0) {
                 return RNull.instance;
             } else {
-                throw RError.nyi(RError.SHOW_CALLER, "non-empty lists");
+                Object list = RNull.instance;
+                RStringVector names = x.getNames();
+                for (int i = x.getLength() - 1; i >= 0; i--) {
+                    Object name = names == null ? RNull.instance : RDataFactory.createSymbolInterned(names.getDataAt(i));
+                    Object data = x.getDataAt(i);
+                    list = RDataFactory.createPairList(data, list, name);
+                }
+                return list;
             }
         }
 
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 baa600759e5a7f148c1d9195bdd6bad536a4f611..87d627da486027bc7e0850cc681e71bc99b6fb8f 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
@@ -581,6 +581,9 @@ public class BasePackage extends RBuiltinPackage {
         add(TraceFunctions.PrimTrace.class, TraceFunctionsFactory.PrimTraceNodeGen::create);
         add(TraceFunctions.PrimUnTrace.class, TraceFunctionsFactory.PrimUnTraceNodeGen::create);
         add(TraceFunctions.TraceOnOff.class, TraceFunctionsFactory.TraceOnOffNodeGen::create);
+        add(TraceFunctions.Tracemem.class, TraceFunctionsFactory.TracememNodeGen::create);
+        add(TraceFunctions.Retracemem.class, TraceFunctionsFactory.RetracememNodeGen::create);
+        add(TraceFunctions.Untracemem.class, TraceFunctionsFactory.UntracememNodeGen::create);
         add(Transpose.class, TransposeNodeGen::create);
         add(TrigExpFunctions.Acos.class, TrigExpFunctionsFactory.AcosNodeGen::create);
         add(TrigExpFunctions.Acosh.class, TrigExpFunctionsFactory.AcoshNodeGen::create);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java
index ce364a8e0471b9ab7be948c354bace2715bd96b7..1c7d8acffacd364516e4f6b1a9bce4bb91e0a347 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java
@@ -22,62 +22,54 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.defaultValue;
 import static com.oracle.truffle.r.runtime.RBuiltinKind.INTERNAL;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RBuiltin;
-import com.oracle.truffle.r.runtime.RRuntime;
 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.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "complex", kind = INTERNAL, parameterNames = {"length.out", "real", "imaginary"})
 public abstract class Complex extends RBuiltinNode {
 
-    private static final RDoubleVector ZERO = RDataFactory.createDoubleVectorFromScalar(0.0);
-
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.toInteger(0);
-    }
-
-    @SuppressWarnings("unused")
-    @Specialization(guards = "resultEmpty(lengthOut, realAbsVec, imaginaryAbsVec)")
-    protected RComplexVector complexEmpty(int lengthOut, RAbstractDoubleVector realAbsVec, RAbstractDoubleVector imaginaryAbsVec) {
-        return RDataFactory.createEmptyComplexVector();
+        casts.arg("length.out").asIntegerVector().findFirst(0);
+        casts.arg("real").map(defaultValue(RDataFactory.createEmptyDoubleVector())).asDoubleVector();
+        casts.arg("imaginary").map(defaultValue(RDataFactory.createEmptyDoubleVector())).asDoubleVector();
     }
 
-    @Specialization(guards = "!resultEmpty(lengthOut, realAbsVec, imaginaryAbsVec)")
-    protected RComplexVector complex(int lengthOut, RAbstractDoubleVector realAbsVec, RAbstractDoubleVector imaginaryAbsVec) {
-        RDoubleVector real = checkLength(realAbsVec);
-        RDoubleVector imaginary = checkLength(imaginaryAbsVec);
-        int realLength = real.getLength();
-        int imaginaryLength = imaginary.getLength();
-        int length = Math.max(Math.max(realLength, imaginaryLength), lengthOut);
-        boolean complete = RDataFactory.COMPLETE_VECTOR;
+    @Specialization
+    protected RComplexVector complex(int lengthOut, RAbstractDoubleVector real, RAbstractDoubleVector imaginary, //
+                    @Cached("create()") NACheck realNA, //
+                    @Cached("create()") NACheck imaginaryNA, //
+                    @Cached("create()") VectorLengthProfile realLengthProfile, //
+                    @Cached("create()") VectorLengthProfile imaginaryLengthProfile, //
+                    @Cached("create()") VectorLengthProfile lengthProfile, //
+                    @Cached("createCountingProfile()") LoopConditionProfile loopProfile) {
+        int realLength = realLengthProfile.profile(real.getLength());
+        int imaginaryLength = imaginaryLengthProfile.profile(imaginary.getLength());
+        int length = lengthProfile.profile(Math.max(Math.max(lengthOut, realLength), imaginaryLength));
         double[] data = new double[length << 1];
-        for (int i = 0; i < data.length; i += 2) {
-            data[i] = real.getDataAt((i >> 1) % realLength);
-            data[i + 1] = imaginary.getDataAt((i >> 1) % imaginaryLength);
-            if (RRuntime.isNA(data[i]) || RRuntime.isNA(data[i + 1])) {
-                complete = RDataFactory.INCOMPLETE_VECTOR;
-            }
-        }
-        return RDataFactory.createComplexVector(data, complete);
-    }
-
-    private static RDoubleVector checkLength(RAbstractDoubleVector v) {
-        if (v.getLength() == 0) {
-            return ZERO;
-        } else {
-            return v.materialize();
+        realNA.enable(real);
+        imaginaryNA.enable(imaginary);
+        loopProfile.profileCounted(length);
+        for (int i = 0; loopProfile.inject(i < data.length); i += 2) {
+            double realValue = realLength == 0 ? 0 : real.getDataAt((i >> 1) % realLength);
+            double imaginaryValue = imaginaryLength == 0 ? 0 : imaginary.getDataAt((i >> 1) % imaginaryLength);
+            data[i] = realValue;
+            data[i + 1] = imaginaryValue;
+            realNA.check(realValue);
+            imaginaryNA.check(imaginaryValue);
         }
-    }
-
-    protected static boolean resultEmpty(int lengthOut, RAbstractDoubleVector realAbsVec, RAbstractDoubleVector imaginaryAbsVec) {
-        return lengthOut == 0 && realAbsVec.getLength() == 0 && imaginaryAbsVec.getLength() == 0;
+        return RDataFactory.createComplexVector(data, realNA.neverSeenNA() && imaginaryNA.neverSeenNA());
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java
index 02acf9fe42d316abed1979ff6a69697d981cabb2..306d58f0e1a6e0b312e129a47f5ab7faf76033ad 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java
@@ -47,7 +47,7 @@ public class DebugFunctions {
         protected void doDebug(RFunction fun, Object text, Object condition, boolean once) throws RError {
             // GnuR does not generate an error for builtins, but debug (obviously) has no effect
             if (!fun.isBuiltin()) {
-                if (!DebugHandling.enableDebug(fun, text, condition, once)) {
+                if (!DebugHandling.enableDebug(fun, text, condition, once, false)) {
                     throw RError.error(this, RError.Message.GENERIC, "failed to attach debug handler (not instrumented?)");
                 }
             }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
index cbf5f639747597685c6fce213ad7f1661bcb94ac..58a270898eb117dd079565f80757abdce5344b30 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
@@ -22,8 +22,10 @@
  */
 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.asStringVector;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.RBuiltinKind.INTERNAL;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
@@ -34,11 +36,9 @@ import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
-import com.oracle.truffle.r.nodes.unary.ConversionFailedException;
 import com.oracle.truffle.r.runtime.RBuiltin;
 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.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
@@ -70,11 +70,7 @@ public abstract class NChar extends RBuiltinNode {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             convertString = insert(CastStringNodeGen.create(false, false, false, false));
         }
-        try {
-            return (String) convertString.executeString(content);
-        } catch (ConversionFailedException e) {
-            throw RError.error(this, RError.Message.TYPE_EXPECTED, RType.Character.getName());
-        }
+        return (String) convertString.executeString(content);
     }
 
     @SuppressWarnings("unused")
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java
index 69a5311f651d88637f52e3a560c49693531a713f..08378721add61691818828c4ca4ce5ea436999ba 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java
@@ -29,11 +29,8 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
-import com.oracle.truffle.r.nodes.unary.ConversionFailedException;
 import com.oracle.truffle.r.runtime.RBuiltin;
-import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -49,11 +46,7 @@ public abstract class NZChar extends RBuiltinNode {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             convertString = insert(CastStringNodeGen.create(false, true, false, false));
         }
-        try {
-            return (String) convertString.execute(content);
-        } catch (ConversionFailedException e) {
-            throw RError.error(this, RError.Message.TYPE_EXPECTED, RType.Character.getName());
-        }
+        return (String) convertString.execute(content);
     }
 
     private static byte isNonZeroLength(String s) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java
deleted file mode 100644
index fd9176181cbeff8b626880e1ab6c876a2b9c62ca..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java
+++ /dev/null
@@ -1,1869 +0,0 @@
-/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.builtin.base;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.Truffle;
-import com.oracle.truffle.api.TruffleLanguage;
-import com.oracle.truffle.api.dsl.NodeChild;
-import com.oracle.truffle.api.dsl.NodeChildren;
-import com.oracle.truffle.api.dsl.NodeField;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.nodes.IndirectCallNode;
-import com.oracle.truffle.api.nodes.RootNode;
-import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.nodes.RRootNode;
-import com.oracle.truffle.r.nodes.access.ConstantNode;
-import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNodeGen.PrettyPrinterSingleListElementNodeGen;
-import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNodeGen.PrettyPrinterSingleVectorElementNodeGen;
-import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNodeGen.PrintDimNodeGen;
-import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNodeGen.PrintVector2DimNodeGen;
-import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNodeGen.PrintVectorMultiDimNodeGen;
-import com.oracle.truffle.r.nodes.function.FormalArguments;
-import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
-import com.oracle.truffle.r.nodes.helpers.RFactorNodes;
-import com.oracle.truffle.r.nodes.unary.CastStringNode;
-import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
-import com.oracle.truffle.r.runtime.ArgumentsSignature;
-import com.oracle.truffle.r.runtime.RArguments;
-import com.oracle.truffle.r.runtime.RDeparse;
-import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.conn.SocketConnections;
-import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.data.RAttributable;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
-import com.oracle.truffle.r.runtime.data.RAttributes;
-import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute;
-import com.oracle.truffle.r.runtime.data.RBuiltinDescriptor;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RDouble;
-import com.oracle.truffle.r.runtime.data.RExpression;
-import com.oracle.truffle.r.runtime.data.RExternalPtr;
-import com.oracle.truffle.r.runtime.data.RFunction;
-import com.oracle.truffle.r.runtime.data.RIntVector;
-import com.oracle.truffle.r.runtime.data.RLanguage;
-import com.oracle.truffle.r.runtime.data.RList;
-import com.oracle.truffle.r.runtime.data.RMissing;
-import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RPairList;
-import com.oracle.truffle.r.runtime.data.RPromise;
-import com.oracle.truffle.r.runtime.data.RRaw;
-import com.oracle.truffle.r.runtime.data.RS4Object;
-import com.oracle.truffle.r.runtime.data.RString;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RSymbol;
-import com.oracle.truffle.r.runtime.data.RVector;
-import com.oracle.truffle.r.runtime.data.closures.RClosures;
-import com.oracle.truffle.r.runtime.data.closures.RFactorToStringVectorClosure;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.env.REnvironment;
-import com.oracle.truffle.r.runtime.nodes.RNode;
-import com.oracle.truffle.r.runtime.ops.na.NACheck;
-
-@SuppressWarnings("unused")
-@NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "listElementName", type = RNode.class), @NodeChild(value = "quote", type = RNode.class),
-                @NodeChild(value = "right", type = RNode.class)})
-@NodeField(name = "printingAttributes", type = boolean.class)
-public abstract class PrettyPrinterNode extends RNode {
-
-    @Override
-    public abstract Object execute(VirtualFrame frame);
-
-    public abstract Object executeString(int o, Object listElementName, byte quote, byte right);
-
-    public abstract Object executeString(double o, Object listElementName, byte quote, byte right);
-
-    public abstract Object executeString(byte o, Object listElementName, byte quote, byte right);
-
-    public abstract Object executeString(Object o, Object listElementName, byte quote, byte right);
-
-    @Child private PrettyPrinterNode attributePrettyPrinter;
-    @Child private PrettyPrinterNode recursivePrettyPrinter;
-    @Child private PrettyPrinterSingleListElementNode singleListElementPrettyPrinter;
-    @Child private PrettyPrinterSingleVectorElementNode singleVectorElementPrettyPrinter;
-    @Child private PrintVectorMultiDimNode multiDimPrinter;
-
-    @Child private NumericalFunctions.Re re = NumericalFunctionsFactory.ReNodeGen.create(null);
-    @Child private NumericalFunctions.Im im = NumericalFunctionsFactory.ImNodeGen.create(null);
-
-    @Child private IndirectCallNode indirectCall = Truffle.getRuntime().createIndirectCallNode();
-
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
-
-    protected abstract boolean isPrintingAttributes();
-
-    private static final FrameAccess FRAME_ACCESS = FrameAccess.NONE;
-
-    private String prettyPrintAttribute(Object o) {
-        if (attributePrettyPrinter == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            attributePrettyPrinter = insert(PrettyPrinterNodeGen.create(null, null, null, null, true));
-        }
-        return (String) attributePrettyPrinter.executeString(o, null, RRuntime.LOGICAL_TRUE, RRuntime.LOGICAL_FALSE);
-    }
-
-    private String prettyPrintRecursive(Object o, Object listElementName, byte quote, byte right) {
-        if (recursivePrettyPrinter == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursivePrettyPrinter = insert(PrettyPrinterNodeGen.create(null, null, null, null, isPrintingAttributes()));
-        }
-        return (String) recursivePrettyPrinter.executeString(o, listElementName, quote, right);
-    }
-
-    private String prettyPrintSingleListElement(Object o, Object listElementName, byte quote, byte right) {
-        if (singleListElementPrettyPrinter == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            singleListElementPrettyPrinter = insert(PrettyPrinterSingleListElementNodeGen.create(null, null, null, null));
-        }
-        return (String) singleListElementPrettyPrinter.executeString(o, listElementName, quote, right);
-    }
-
-    private String prettyPrintSingleVectorElement(Object o, byte isQuoted) {
-        if (singleVectorElementPrettyPrinter == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            singleVectorElementPrettyPrinter = insert(PrettyPrinterSingleVectorElementNodeGen.create(null, null));
-        }
-        return (String) singleVectorElementPrettyPrinter.executeString(o, isQuoted);
-    }
-
-    private String printVectorMultiDim(RAbstractVector vector, boolean isListOrStringVector, boolean isComplexOrRawVector, byte quote) {
-        if (multiDimPrinter == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            multiDimPrinter = insert(PrintVectorMultiDimNodeGen.create(null, null, null, null));
-        }
-        StringBuilder sb = new StringBuilder();
-        sb.append((String) multiDimPrinter.executeString(vector, RRuntime.asLogical(isListOrStringVector), RRuntime.asLogical(isComplexOrRawVector), quote));
-        RAttributes attributes = vector.getAttributes();
-        if (attributes != null) {
-            sb.append(printAttributes(vector, attributes));
-        }
-        return builderToString(sb);
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrint(RNull operand, Object listElementName, byte quote, byte right) {
-        return "NULL";
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintVector(byte operand, Object listElementName, byte quote, byte right) {
-        return concat("[1] ", prettyPrint(operand));
-    }
-
-    public static String prettyPrint(byte operand, int width) {
-        StringBuilder sb = new StringBuilder();
-        String valStr = RRuntime.logicalToString(operand);
-        return spaces(sb, width - valStr.length()).append(valStr).toString();
-    }
-
-    public static String prettyPrint(byte operand) {
-        return RRuntime.logicalToString(operand);
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintVector(int operand, Object listElementName, byte quote, byte right) {
-        return concat("[1] ", prettyPrint(operand));
-    }
-
-    public static String prettyPrint(int operand) {
-        return RRuntime.intToString(operand);
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintVector(double operand, Object listElementName, byte quote, byte right) {
-        return concat("[1] ", prettyPrint(operand));
-    }
-
-    public static String prettyPrint(double operand) {
-        return doubleToStringPrintFormat(operand, calcRoundFactor(operand, 10000000));
-    }
-
-    public static String prettyPrint(double operand, double roundFactor, int digitsBehindDot) {
-        return doubleToStringPrintFormat(operand, roundFactor, digitsBehindDot);
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintVector(RComplex operand, Object listElementName, byte quote, byte right) {
-        return concat("[1] ", prettyPrint(operand));
-    }
-
-    public static String prettyPrint(RComplex operand) {
-        double rfactor = calcRoundFactor(operand.getRealPart(), 10000000);
-        double ifactor = calcRoundFactor(operand.getImaginaryPart(), 10000000);
-        return operand.toString(doubleToStringPrintFormat(operand.getRealPart(), rfactor), doubleToStringPrintFormat(operand.getImaginaryPart(), ifactor));
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintVector(String operand, Object listElementName, byte quote, byte right) {
-        if (RRuntime.fromLogical(quote)) {
-            return concat("[1] ", prettyPrint(operand));
-        }
-        return concat("[1] ", operand);
-    }
-
-    public static String prettyPrint(String operand) {
-        return RRuntime.quoteString(operand, false);
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintVector(RRaw operand, Object listElementName, byte quote, byte right) {
-        return concat("[1] ", prettyPrint(operand));
-    }
-
-    public static String prettyPrint(RRaw operand) {
-        return operand.toString();
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrint(RFunction operand, Object listElementName, byte quote, byte right) {
-        return prettyPrintFunction(operand, listElementName, quote, right, true);
-    }
-
-    public String prettyPrintFunction(RFunction operand, Object listElementName, byte quote, byte right, boolean useSource) {
-        String string;
-        if (operand.isBuiltin()) {
-            RBuiltinDescriptor rBuiltin = operand.getRBuiltin();
-            RRootNode node = (RRootNode) operand.getTarget().getRootNode();
-            FormalArguments formals = node.getFormalArguments();
-            StringBuffer sb = new StringBuffer();
-            sb.append("function (");
-            ArgumentsSignature signature = formals.getSignature();
-            for (int i = 0; i < signature.getLength(); i++) {
-                RNode defaultArg = formals.getDefaultArgument(i);
-                sb.append(signature.getName(i));
-                if (defaultArg != null) {
-                    sb.append(" = ");
-                    Object value = ((ConstantNode) defaultArg).getValue();
-                    String printValue = prettyPrintRecursive(value, listElementName, quote, right);
-                    // remove the "[1] "
-                    sb.append(printValue.substring(4));
-                }
-                if (i != signature.getLength() - 1) {
-                    sb.append(", ");
-                }
-            }
-            sb.append(")  .Primitive(\"");
-            sb.append(rBuiltin.getName());
-            sb.append("\")");
-            string = sb.toString();
-        } else {
-            String source = ((RRootNode) operand.getTarget().getRootNode()).getSourceCode();
-            if (source == null || !useSource) {
-                source = RDeparse.deparse(operand);
-            }
-            REnvironment env = RArguments.getEnvironment(operand.getEnclosingFrame());
-            if (env != null && env.isNamespaceEnv()) {
-                source += "\n" + env.getPrintName();
-            }
-            string = source;
-        }
-        return printValueAndAttributes(string, operand, false);
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrint(REnvironment operand, Object listElementName, byte quote, byte right) {
-        return printValueAndAttributes(operand.toString(), operand, false);
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrint(RExpression expr, Object listElementName, byte quote, byte right) {
-        StringBuilder builder = new StringBuilder();
-        builder.append("expression(");
-        RList exprs = expr.getList();
-        RStringVector names = (RStringVector) expr.getAttr(attrProfiles, RRuntime.NAMES_ATTR_KEY);
-        for (int i = 0; i < exprs.getLength(); i++) {
-            if (i != 0) {
-                builder.append(", ");
-            }
-            if (names != null && names.getDataAt(i) != null) {
-                builder.append(names.getDataAt(i));
-                builder.append(" = ");
-            }
-            builder.append(prettyPrintSingleVectorElement(exprs.getDataAt(i), quote));
-        }
-        builder.append(')');
-        return builderToString(builder);
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintSymbol(RSymbol operand, Object listElementName, byte quote, byte right) {
-        return printValueAndAttributes(operand.getName(), operand, false);
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintExternalPtr(RExternalPtr operand, Object listElementName, byte quote, byte right) {
-        return printValueAndAttributes(String.format("<pointer: %#x>", operand.getAddr()), operand, false);
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintPromise(RPromise promise, Object listElementName, byte quote, byte right) {
-        if (promise.isEvaluated()) {
-            return prettyPrintRecursive(promise.getValue(), listElementName, quote, right);
-        } else {
-            return prettyPrintPromise(promise);
-        }
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintLanguage(RLanguage language, Object listElementName, byte quote, byte right) {
-        return printValueAndAttributes(prettyPrintLanguageInternal(language), language, true);
-    }
-
-    private static String prettyPrintLanguageInternal(RLanguage language) {
-        return RDeparse.deparse(language, 60, false, 0, -1);
-    }
-
-    private static String prettyPrintPromise(RPromise promise) {
-        RNode node = (RNode) promise.getRep();
-        SourceSection ss = node.asRSyntaxNode().getSourceSection();
-        if (ss == null) {
-            return "<no source available>";
-        } else {
-            return ss.getCode();
-        }
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintPairList(RPairList pairList, Object listElementName, byte quote, byte right) {
-        StringBuilder sb = new StringBuilder();
-        int i = 1;
-        Object plObject = pairList;
-        RPairList pl = pairList;
-        while (!RPairList.isNull(plObject)) {
-            if (!pl.isNullTag()) {
-                sb.append('$');
-                sb.append(pl.getTag());
-            } else {
-                sb.append("[[");
-                sb.append(Integer.toString(i));
-                sb.append("]]");
-            }
-            sb.append('\n');
-            if (!RPairList.isNull(pl.car())) {
-                sb.append(prettyPrintRecursive(pl.car(), listElementName, quote, right));
-                sb.append('\n');
-            }
-            plObject = pl.cdr();
-            if (!RPairList.isNull(plObject)) {
-                pl = (RPairList) plObject;
-                sb.append('\n');
-            }
-            i++;
-        }
-        return sb.toString();
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPrintMissing(RMissing missing, Object listElementName, byte quote, byte right) {
-        return "";
-    }
-
-    @TruffleBoundary
-    @Specialization
-    protected String prettyPringS4(RS4Object o, Object listElementName, byte quote, byte right) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("<S4 Type Object>");
-        for (RAttribute attr : o.getAttributes()) {
-            printAttribute(sb, attr);
-        }
-        return sb.toString();
-    }
-
-    private static String getStringFromObj(Object o, String msg) {
-        if (o instanceof String) {
-            return (String) o;
-        } else if (o instanceof RStringVector && ((RStringVector) o).getLength() == 1) {
-            return ((RStringVector) o).getDataAt(0);
-        } else {
-            throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
-        }
-    }
-
-    private String printAttributes(RAbstractVector vector, RAttributes attributes) {
-        StringBuilder builder = new StringBuilder();
-        for (RAttribute attr : attributes) {
-            if (attr.getName().equals(RRuntime.NAMES_ATTR_KEY) && !vector.hasDimensions()) {
-                // names attribute already printed
-                continue;
-            }
-            if (attr.getName().equals(RRuntime.DIM_ATTR_KEY) || attr.getName().equals(RRuntime.DIMNAMES_ATTR_KEY)) {
-                // dim and dimnames attributes never gets printed
-                continue;
-            }
-            printAttribute(builder, attr);
-        }
-        return builderToString(builder);
-    }
-
-    /**
-     * Encapsulates the printing of the value and attributes for {@link RAttributable} types.
-     *
-     * @param ignoreNames TODO
-     */
-    private String printValueAndAttributes(String value, RAttributable object, boolean ignoreNames) {
-        RAttributes attributes = object.getAttributes();
-        if (attributes == null) {
-            return value;
-        } else {
-            StringBuilder builder = new StringBuilder(value);
-            for (RAttribute attr : attributes) {
-                if (ignoreNames && attr.getName().equals(RRuntime.NAMES_ATTR_KEY)) {
-                    continue;
-                }
-                printAttribute(builder, attr);
-            }
-            return builderToString(builder);
-        }
-    }
-
-    private void printAttribute(StringBuilder builder, RAttribute attr) {
-        builder.append("\n");
-        builder.append(concat("attr(,\"", attr.getName(), "\")\n"));
-        builder.append(prettyPrintAttribute(attr.getValue()));
-    }
-
-    private static int getMaxPrintLength() {
-        int maxPrint = RRuntime.asInteger(RContext.getInstance().stateROptions.getValue("max.print"));
-        return RRuntime.isNA(maxPrint) ? -1 : maxPrint;
-    }
-
-    private String printVector(RAbstractVector vector, String[] values, boolean isStringVector, boolean isRawVector) {
-        assert vector.getLength() == values.length;
-        int maxPrint = getMaxPrintLength();
-        if (values.length == 0) {
-            String result = concat(RRuntime.classToString(vector.getElementClass()), "(0)");
-            if (vector.getNames(attrProfiles) != null) {
-                result = concat("named ", result);
-            }
-            return result;
-        } else {
-            boolean printNamesHeader = ((!vector.hasDimensions() || (vector.getDimensions().length == 1 && vector.getDimNames(attrProfiles) != null)) && vector.getNames(attrProfiles) != null);
-            RStringVector names = printNamesHeader ? vector.getNames(attrProfiles) : null;
-            int maxWidth = 0;
-            for (String s : values) {
-                maxWidth = Math.max(maxWidth, s.length());
-            }
-            if (printNamesHeader) {
-                for (int i = 0; i < names.getLength(); i++) {
-                    String s = names.getDataAt(i);
-                    if (RRuntime.isNA(s)) {
-                        s = RRuntime.NA_HEADER;
-                    }
-                    maxWidth = Math.max(maxWidth, s.length());
-                }
-            }
-            int columnWidth = maxWidth + 1; // There is a blank before each column.
-            int leftWidth = 0;
-            int maxPositionLength = 0;
-            if (!printNamesHeader) {
-                maxPositionLength = intString(vector.getLength()).length();
-                leftWidth = maxPositionLength + 2; // There is [] around the number.
-            }
-            int forColumns = (int) RContext.getInstance().stateROptions.getValue("width") - leftWidth;
-            int numberOfColumns = Math.max(1, forColumns / columnWidth);
-
-            int index = 0;
-            StringBuilder builder = new StringBuilder();
-            StringBuilder headerBuilder = null;
-            if (printNamesHeader) {
-                headerBuilder = new StringBuilder();
-            }
-            while (index < vector.getLength()) {
-                if (!printNamesHeader) {
-                    int position = index + 1;
-                    String positionString = intString(position);
-                    appendSpaces(builder, maxPositionLength - positionString.length());
-                    builder.append("[").append(positionString).append("]");
-                }
-                for (int j = 0; j < numberOfColumns && index < vector.getLength(); j++) {
-                    String valueString = values[index];
-                    if (!printNamesHeader) {
-                        builder.append(' ');
-                        // for some reason vectors of strings are printed differently
-                        if (isStringVector) {
-                            builder.append(valueString);
-                            appendSpaces(builder, (columnWidth - 1) - valueString.length());
-                        } else {
-                            appendSpaces(builder, (columnWidth - 1) - valueString.length());
-                            builder.append(valueString);
-                        }
-                    } else {
-                        int actualColumnWidth = columnWidth;
-                        if (j == 0) {
-                            actualColumnWidth--;
-                        }
-                        // for some reason vectors of raw values are printed differently
-                        if (!isRawVector) {
-                            appendSpaces(builder, actualColumnWidth - valueString.length());
-                        }
-                        builder.append(valueString);
-                        if (isRawVector) {
-                            builder.append(' ');
-                        }
-                        String headerString = names.getDataAt(index);
-                        if (RRuntime.isNA(headerString)) {
-                            headerString = RRuntime.NA_HEADER;
-                        }
-                        appendSpaces(headerBuilder, actualColumnWidth - headerString.length());
-                        headerBuilder.append(headerString);
-                    }
-                    index++;
-                    if (index == maxPrint) {
-                        break;
-                    }
-                }
-                builder.append('\n');
-                if (printNamesHeader) {
-                    headerBuilder.append('\n');
-                    headerBuilder.append(builderToString(builder));
-                    builder = new StringBuilder();
-                }
-                if (index == maxPrint) {
-                    break;
-                }
-            }
-            StringBuilder resultBuilder = printNamesHeader ? headerBuilder : builder;
-            resultBuilder.deleteCharAt(resultBuilder.length() - 1);
-            if (index == maxPrint) {
-                resultBuilder.append("\n [ reached getOption(\"max.print\") -- omitted ");
-                resultBuilder.append(vector.getLength() - maxPrint);
-                resultBuilder.append(" entries ]");
-            }
-            if (!(vector instanceof RFactorToStringVectorClosure)) {
-                // it's a bit of a hack, but factors are meant to be printed using the S3 function
-                // anyway - the idea is to suppress attribute printing for factors nested in lists
-                RAttributes attributes = vector.getAttributes();
-                if (attributes != null) {
-                    resultBuilder.append(printAttributes(vector, attributes));
-                }
-            }
-            return builderToString(resultBuilder);
-        }
-    }
-
-    private static void appendSpaces(StringBuilder builder, int spaces) {
-        for (int k = 0; k < spaces; k++) {
-            builder.append(' ');
-        }
-    }
-
-    protected static String padColHeader(int r, int dataColWidth, RAbstractVector vector, boolean isListOrStringVector, RAttributeProfiles attrProfiles) {
-        RList dimNames = vector.getDimNames(attrProfiles);
-        StringBuilder sb = new StringBuilder();
-        int wdiff;
-        if (dimNames == null || dimNames.getDataAt(1) == RNull.instance) {
-            String rs = intString(r);
-            wdiff = dataColWidth - (rs.length() + 3); // 3: [,]
-            if (!isListOrStringVector && wdiff > 0) {
-                spaces(sb, wdiff);
-            }
-            sb.append("[,").append(rs).append(']');
-        } else {
-            String dimId;
-            if (dimNames.getDataAt(1) instanceof String) {
-                assert r == 1;
-                dimId = (String) dimNames.getDataAt(1);
-            } else {
-                RStringVector dimNamesVector = (RStringVector) dimNames.getDataAt(1);
-                dimId = dimNamesVector.getDataAt(r - 1);
-            }
-            if (RRuntime.isNA(dimId)) {
-                dimId = RRuntime.NA_HEADER;
-            }
-            wdiff = dataColWidth - dimId.length();
-            if (!isListOrStringVector && wdiff > 0) {
-                spaces(sb, wdiff);
-            }
-            sb.append(dimId);
-        }
-        if (isListOrStringVector && wdiff > 0) {
-            spaces(sb, wdiff);
-        }
-        return builderToString(sb);
-    }
-
-    protected static boolean rowHeaderUsesIndices(RList dimNames) {
-        return dimNames == null || dimNames.getDataAt(0) == RNull.instance;
-    }
-
-    protected static String rowHeader(int c, RAbstractVector vector, RAttributeProfiles attrProfiles) {
-        RList dimNames = vector.getDimNames(attrProfiles);
-        if (rowHeaderUsesIndices(dimNames)) {
-            return concat("[", intString(c), ",]");
-        } else {
-            RAbstractStringVector dimNamesVector = (RAbstractStringVector) getDimNamesAt(dimNames, 1);
-            String dimId = dimNamesVector.getDataAt(c - 1);
-            if (RRuntime.isNA(dimId)) {
-                dimId = RRuntime.NA_HEADER;
-            }
-            return dimId;
-        }
-    }
-
-    public static StringBuilder spaces(StringBuilder sb, int s) {
-        if (s > 0) {
-            appendSpaces(sb, s);
-        }
-        return sb;
-    }
-
-    private static String getDimId(RAbstractVector vector, int dimLevel, int dimInd, RAttributeProfiles attrProfiles) {
-        String dimId;
-        RList dimNames = vector.getDimNames(attrProfiles);
-        if (dimNames == null || getDimNamesAt(dimNames, dimLevel) == RNull.instance) {
-            dimId = intString(dimInd + 1);
-        } else {
-            RAbstractStringVector dimNamesVector = (RAbstractStringVector) getDimNamesAt(dimNames, dimLevel);
-            dimId = dimNamesVector.getDataAt(dimInd);
-        }
-        return dimId;
-    }
-
-    private static Object getDimNamesAt(RList dimNames, int dimLevel) {
-        Object result = dimNames.getDataAt(dimLevel - 1);
-        if (result instanceof String) {
-            return RString.valueOf((String) result);
-        }
-        return result;
-    }
-
-    private static double calcRoundFactor(double input, long maxFactor) {
-        if (Double.isNaN(input) || Double.isInfinite(input) || input == 0.0) {
-            return maxFactor * 10;
-        }
-        double data = input;
-        double factor = 1;
-        if (Math.abs(data) > 1000000000000L) {
-            while (Math.abs(data) > 10000000L) {
-                data = data / 10;
-                factor /= 10;
-            }
-        } else if ((int) data != 0) {
-            while (Math.abs(data) < maxFactor / 10) {
-                data = data * 10;
-                factor *= 10;
-            }
-        } else {
-            long current = maxFactor / 10;
-            while (Math.abs(data) < 1 && current > 1) {
-                data = data * 10;
-                current = current * 10;
-            }
-            return current;
-        }
-        return factor;
-    }
-
-    private static String doubleToStringPrintFormat(double input, double roundFactor, int digitsBehindDot) {
-        double data = input;
-        if (digitsBehindDot == -1) {
-            // processing a single double value or a complex value; use rounding instead of
-            // digitsBehindDot (which is in this case invalid) to determine precision
-            if (!Double.isNaN(data) && !Double.isInfinite(data)) {
-                if (roundFactor < 1) {
-                    double inverse = 1 / roundFactor;
-                    data = Math.round(data / inverse) * inverse;
-                } else {
-                    data = Math.round(data * roundFactor) / roundFactor;
-                }
-            }
-        }
-        return RRuntime.doubleToString(data, digitsBehindDot);
-    }
-
-    private static String doubleToStringPrintFormat(double input, double roundFactor) {
-        return doubleToStringPrintFormat(input, roundFactor, -1);
-    }
-
-    private String prettyPrintList0(RList operand, Object listElementName, byte quote, byte right) {
-        int length = operand.getLength();
-        if (length == 0) {
-            String result = "list()";
-            if (operand.getNames(attrProfiles) != null) {
-                result = concat("named ", result);
-            }
-            return result;
-        } else {
-            StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < length; i++) {
-                if (isPrintingAttributes() && operand.elementNamePrefix != null) {
-                    sb.append(operand.elementNamePrefix);
-                }
-                Object name = operand.getNameAt(i);
-                if (listElementName != null) {
-                    name = concat(RRuntime.toString(listElementName), RRuntime.toString(name));
-                }
-                sb.append(name).append('\n');
-                Object value = operand.getDataAt(i);
-                sb.append(prettyPrintSingleListElement(value, name, quote, right)).append("\n\n");
-            }
-            sb.deleteCharAt(sb.length() - 1);
-            RAttributes attributes = operand.getAttributes();
-            if (attributes != null) {
-                sb.append(printAttributes(operand, attributes));
-            }
-            return builderToString(sb);
-        }
-    }
-
-    public static String prettyPrint(RList operand) {
-        return concat("List,", intString(operand.getLength()));
-    }
-
-    public static String prettyPrint(RAbstractVector operand) {
-        return concat(RRuntime.classToStringCap(operand.getElementClass()), ",", intString(operand.getLength()));
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "twoDimsOrMore(operand)")
-    protected String prettyPrintM(RList operand, Object listElementName, byte quote, byte right) {
-        return printVectorMultiDim(operand, true, false, quote);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "twoDimsOrMore(operand)")
-    protected String prettyPrintM(RAbstractStringVector operand, Object listElementName, byte quote, byte right) {
-        return printVectorMultiDim(operand, right == RRuntime.LOGICAL_FALSE, false, quote);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "twoDimsOrMore(operand)")
-    protected String prettyPrintM(RAbstractComplexVector operand, Object listElementName, byte quote, byte right) {
-        return printVectorMultiDim(operand, false, true, quote);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "twoDimsOrMore(operand)")
-    protected String prettyPrintM(RAbstractRawVector operand, Object listElementName, byte quote, byte right) {
-        return printVectorMultiDim(operand, false, true, quote);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "twoDimsOrMore(operand)")
-    protected String prettyPrintM(RAbstractDoubleVector operand, Object listElementName, byte quote, byte right) {
-        return printVectorMultiDim(operand, false, false, quote);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "twoDimsOrMore(operand)")
-    protected String prettyPrintM(RAbstractIntVector operand, Object listElementName, byte quote, byte right) {
-        return printVectorMultiDim(operand, false, false, quote);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "twoDimsOrMore(operand)")
-    protected String prettyPrintM(RAbstractLogicalVector operand, Object listElementName, byte quote, byte right) {
-        return printVectorMultiDim(operand, false, false, quote);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "!twoDimsOrMore(operand)")
-    protected String prettyPrint(RList operand, Object listElementName, byte quote, byte right) {
-        return prettyPrintList0(operand, listElementName, quote, right);
-    }
-
-    private static double getMaxRoundFactor(RAbstractDoubleVector operand) {
-        double maxRoundFactor = 0;
-        for (int i = 0; i < operand.getLength(); i++) {
-            double data = operand.getDataAt(i);
-            double roundFactor = calcRoundFactor(data, 10000000);
-            if (roundFactor > maxRoundFactor) {
-                maxRoundFactor = roundFactor;
-            }
-        }
-        return maxRoundFactor;
-    }
-
-    private static int getMaxDigitsBehindDot(double maxRoundFactor) {
-        int maxDigitsBehindDot = 0;
-        for (double j = 1; j < maxRoundFactor; j *= 10) {
-            maxDigitsBehindDot++;
-        }
-        return maxDigitsBehindDot;
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "!twoDimsOrMore(operand)")
-    protected String prettyPrint(RAbstractDoubleVector operand, Object listElementName, byte quote, byte right) {
-        int length = operand.getLength();
-        String[] values = new String[length];
-        double maxRoundFactor = getMaxRoundFactor(operand);
-        int maxDigitsBehindDot = getMaxDigitsBehindDot(maxRoundFactor);
-        for (int i = 0; i < length; i++) {
-            double data = operand.getDataAt(i);
-            values[i] = prettyPrint(data, maxRoundFactor, maxDigitsBehindDot);
-        }
-        padTrailingDecimalPointAndZeroesIfRequired(values);
-        return printVector(operand, values, false, false);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "!twoDimsOrMore(operand)")
-    protected String prettyPrint(RAbstractIntVector operand, Object listElementName, byte quote, byte right) {
-        int length = operand.getLength();
-        String[] values = new String[length];
-        for (int i = 0; i < length; i++) {
-            int data = operand.getDataAt(i);
-            values[i] = prettyPrint(data);
-        }
-        return printVector(operand, values, false, false);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "!twoDimsOrMore(operand)")
-    protected String prettyPrint(RAbstractStringVector operand, Object listElementName, byte quote, byte right) {
-        int length = operand.getLength();
-        String[] values = new String[length];
-        for (int i = 0; i < length; i++) {
-            String data = operand.getDataAt(i);
-            if (RRuntime.fromLogical(quote)) {
-                values[i] = prettyPrint(data);
-            } else {
-                if (RRuntime.isNA(data)) {
-                    values[i] = RRuntime.NA_HEADER;
-                } else {
-                    values[i] = data;
-                }
-            }
-        }
-        return printVector(operand, values, true, false);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "!twoDimsOrMore(operand)")
-    protected String prettyPrint(RAbstractLogicalVector operand, Object listElementName, byte quote, byte right) {
-        int length = operand.getLength();
-        String[] values = new String[length];
-        for (int i = 0; i < length; i++) {
-            byte data = operand.getDataAt(i);
-            values[i] = prettyPrint(data);
-        }
-        return printVector(operand, values, false, false);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "!twoDimsOrMore(operand)")
-    protected String prettyPrint(RAbstractRawVector operand, Object listElementName, byte quote, byte right) {
-        int length = operand.getLength();
-        String[] values = new String[length];
-        for (int i = 0; i < length; i++) {
-            RRaw data = operand.getDataAt(i);
-            values[i] = prettyPrint(data);
-        }
-        return printVector(operand, values, false, true);
-    }
-
-    @TruffleBoundary
-    @Specialization(guards = "!twoDimsOrMore(operand)")
-    protected String prettyPrint(RAbstractComplexVector operand, Object listElementName, byte quote, byte right) {
-
-        RAbstractDoubleVector realParts = (RAbstractDoubleVector) re.calculateUnboxed(operand);
-        RAbstractDoubleVector imaginaryParts = (RAbstractDoubleVector) im.calculateUnboxed(operand);
-
-        int length = operand.getLength();
-        String[] realValues = new String[length];
-        String[] imaginaryValues = new String[length];
-        for (int i = 0; i < length; i++) {
-            realValues[i] = prettyPrint(realParts.getDataAt(i));
-            imaginaryValues[i] = prettyPrint(imaginaryParts.getDataAt(i));
-        }
-        padTrailingDecimalPointAndZeroesIfRequired(realValues);
-        padTrailingDecimalPointAndZeroesIfRequired(imaginaryValues);
-        removeLeadingMinus(imaginaryValues);
-        rightJustify(imaginaryValues);
-
-        String[] values = new String[length];
-        for (int i = 0; i < length; i++) {
-            values[i] = operand.getDataAt(i).isNA() ? "NA" : concat(realValues[i], imaginaryParts.getDataAt(i) < 0.0 ? "-" : "+", imaginaryValues[i], "i");
-        }
-        return printVector(operand, values, false, false);
-    }
-
-    protected static boolean twoDimsOrMore(RAbstractContainer v) {
-        return v.hasDimensions() && v.getDimensions().length > 1;
-    }
-
-    protected static boolean isLengthOne(RAbstractIntVector v) {
-        return v.getLength() == 1;
-    }
-
-    private static String builderToString(StringBuilder sb) {
-        return sb.toString();
-    }
-
-    private static String builderToSubstring(StringBuilder sb, int start, int end) {
-        return sb.substring(start, end);
-    }
-
-    private static String intString(int x) {
-        return Integer.toString(x);
-    }
-
-    private static String stringFormat(String format, Object arg) {
-        return String.format(format, arg);
-    }
-
-    private static String concat(String... ss) {
-        StringBuilder sb = new StringBuilder();
-        for (String s : ss) {
-            sb.append(s);
-        }
-        return builderToString(sb);
-    }
-
-    private static String substring(String s, int start) {
-        return s.substring(start);
-    }
-
-    private static int requiresDecimalPointsAndTrailingZeroes(String[] values, int[] decimalPointOffsets, int[] lenAfterPoint) {
-        boolean foundWithDecimalPoint = false;
-        boolean foundWithoutDecimalPoint = false;
-        boolean inequalLenAfterPoint = false;
-        int maxLenAfterPoint = -1;
-        for (int i = 0; i < values.length; i++) {
-            String v = values[i];
-            decimalPointOffsets[i] = v.indexOf('.');
-            if (decimalPointOffsets[i] == -1) {
-                foundWithoutDecimalPoint = true;
-                lenAfterPoint[i] = 0;
-            } else {
-                foundWithDecimalPoint = true;
-                int lap = substring(v, decimalPointOffsets[i] + 1).length();
-                lenAfterPoint[i] = lap;
-                if (lap > maxLenAfterPoint) {
-                    if (maxLenAfterPoint == -1) {
-                        inequalLenAfterPoint = true;
-                    }
-                    maxLenAfterPoint = lap;
-                }
-            }
-        }
-        return (foundWithDecimalPoint && foundWithoutDecimalPoint) || inequalLenAfterPoint ? maxLenAfterPoint : -1;
-    }
-
-    public static void padTrailingDecimalPointAndZeroesIfRequired(String[] values) {
-        int[] decimalPointOffsets = new int[values.length];
-        int[] lenAfterPoint = new int[values.length];
-        int maxLenAfterPoint = requiresDecimalPointsAndTrailingZeroes(values, decimalPointOffsets, lenAfterPoint);
-        if (maxLenAfterPoint == -1) {
-            return;
-        }
-
-        for (int i = 0; i < values.length; i++) {
-            String v = values[i];
-            if (RRuntime.isNA(v) || "NaN".equals(v)) {
-                continue;
-            }
-            if (decimalPointOffsets[i] == -1) {
-                v = concat(v, ".");
-            }
-            if (lenAfterPoint[i] < maxLenAfterPoint) {
-                values[i] = concat(v, stringFormat(concat("%0", intString(maxLenAfterPoint - lenAfterPoint[i]), "d"), 0));
-            }
-        }
-    }
-
-    private static void rightJustify(String[] values) {
-        int maxLen = 0;
-        boolean inequalLengths = false;
-        int lastLen = 0;
-        for (int i = 0; i < values.length; i++) {
-            String v = values[i];
-            if (RRuntime.isNA(v)) {
-                // do not use NA for deciding alignment
-                continue;
-            }
-            int l = v.length();
-            maxLen = Math.max(maxLen, l);
-            inequalLengths = lastLen != 0 && lastLen != l;
-            lastLen = l;
-        }
-        if (!inequalLengths) {
-            return;
-        }
-        for (int i = 0; i < values.length; i++) {
-            String v = values[i];
-            int l = v.length();
-            if (l < maxLen) {
-                int d = maxLen - l;
-                if (d == 1) {
-                    values[i] = concat(" ", v);
-                } else {
-                    values[i] = concat(stringFormat(concat("%", intString(d), "s"), " "), v);
-                }
-            }
-        }
-    }
-
-    private static void removeLeadingMinus(String[] values) {
-        for (int i = 0; i < values.length; i++) {
-            String v = values[i];
-            if (v.charAt(0) == '-') {
-                values[i] = substring(v, 1);
-            }
-        }
-    }
-
-    public static String prettyPrintDefault(Object value) {
-        return (String) Truffle.getRuntime().createCallTarget(new RootNode(TruffleLanguage.class, null, null) {
-
-            @Child PrettyPrinterNode node = PrettyPrinterNodeGen.create(null, null, null, null, false);
-
-            @Override
-            public Object execute(VirtualFrame frame) {
-                return node.executeString(frame.getArguments()[0], null, RRuntime.LOGICAL_FALSE, RRuntime.LOGICAL_FALSE);
-            }
-        }).call(value);
-    }
-
-    @NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "listElementName", type = RNode.class), @NodeChild(value = "quote", type = RNode.class),
-                    @NodeChild(value = "right", type = RNode.class)})
-    abstract static class PrettyPrinterSingleListElementNode extends RNode {
-
-        @Child private PrettyPrinterNode prettyPrinter;
-        @Child private CastStringNode castStringNode;
-
-        private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
-
-        private final NACheck naCheck = NACheck.create();
-
-        private void initCast(Object listElementName) {
-            if (prettyPrinter == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                prettyPrinter = insert(PrettyPrinterNodeGen.create(null, null, null, null, false));
-            }
-        }
-
-        private void initCast() {
-            if (castStringNode == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                castStringNode = insert(CastStringNodeGen.create(false, false, false, false));
-            }
-        }
-
-        private String prettyPrintSingleElement(byte o, Object listElementName, byte quote, byte right) {
-            initCast(listElementName);
-            return (String) prettyPrinter.executeString(o, listElementName, quote, right);
-        }
-
-        private String prettyPrintSingleElement(int o, Object listElementName, byte quote, byte right) {
-            initCast(listElementName);
-            return (String) prettyPrinter.executeString(o, listElementName, quote, right);
-        }
-
-        private String prettyPrintSingleElement(double o, Object listElementName, byte quote, byte right) {
-            initCast(listElementName);
-            return (String) prettyPrinter.executeString(o, listElementName, quote, right);
-        }
-
-        private String prettyPrintSingleElement(Object o, Object listElementName, byte quote, byte right) {
-            initCast(listElementName);
-            return (String) prettyPrinter.executeString(o, listElementName, quote, right);
-        }
-
-        public abstract Object executeString(int o, Object listElementName, byte quote, byte right);
-
-        public abstract Object executeString(double o, Object listElementName, byte quote, byte right);
-
-        public abstract Object executeString(byte o, Object listElementName, byte quote, byte right);
-
-        public abstract Object executeString(Object o, Object listElementName, byte quote, byte right);
-
-        @Specialization
-        protected String prettyPrintListElement(SocketConnections.RSocketConnection operand, Object listElementName, byte quote, byte right) {
-            // TODO; fixing this properly would likely require overhaul of the whole
-            // formatting/printing infrastructure, which does not seem worth it at this point
-            return "SOCKET CONNECTION";
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(RNull operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(byte operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(int operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(double operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(RComplex operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(String operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(RRaw operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization(guards = "!isFactor(operand)")
-        protected String prettyPrintListElement(RAbstractVector operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(RSymbol operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(RLanguage operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(REnvironment operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(RFunction operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintListElement(RExternalPtr operand, Object listElementName, byte quote, byte right) {
-            return prettyPrintSingleElement(operand, listElementName, quote, right);
-        }
-
-        @Child InheritsCheckNode factorInheritsCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR);
-        @Child RFactorNodes.GetLevels getFactorLevels;
-
-        protected boolean isFactor(Object o) {
-            return this.factorInheritsCheck.execute(o);
-        }
-
-        // TODO: this should be handled by an S3 function
-        @Specialization(guards = "isFactor(factor)")
-        protected String prettyPrintListElement(RAbstractIntVector factor, Object listElementName, byte quote, byte right) {
-            if (getFactorLevels == null) {
-                CompilerDirectives.transferToInterpreter();
-                getFactorLevels = insert(new RFactorNodes.GetLevels());
-            }
-
-            RVector vec = getFactorLevels.execute(factor);
-            String[] strings;
-            if (vec == null) {
-                strings = new String[0];
-            } else {
-                initCast();
-                strings = new String[vec.getLength()];
-                for (int i = 0; i < vec.getLength(); i++) {
-                    strings[i] = (String) castStringNode.executeString(vec.getDataAtAsObject(i));
-                }
-            }
-            return formatLevelStrings(factor, listElementName, right, vec, strings);
-        }
-
-        @TruffleBoundary
-        private String formatLevelStrings(RAbstractIntVector operand, Object listElementName, byte right, RVector vec, String[] strings) {
-            StringBuilder sb = new StringBuilder(prettyPrintSingleElement(RClosures.createFactorToVector(operand, true, attrProfiles), listElementName, RRuntime.LOGICAL_FALSE, right));
-            sb.append("\nLevels:");
-            if (vec != null) {
-                for (int i = 0; i < vec.getLength(); i++) {
-                    sb.append(" ");
-                    sb.append(strings[i]);
-                }
-            }
-            return sb.toString();
-        }
-    }
-
-    @NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "isQuoted", type = RNode.class)})
-    abstract static class PrettyPrinterSingleVectorElementNode extends RNode {
-
-        @Child private PrettyPrinterSingleVectorElementNode recursivePrettyPrinter;
-
-        private String prettyPrintRecursive(Object o, byte isQuoted) {
-            if (recursivePrettyPrinter == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                recursivePrettyPrinter = insert(PrettyPrinterSingleVectorElementNodeGen.create(null, null));
-            }
-            return (String) recursivePrettyPrinter.executeString(o, isQuoted);
-        }
-
-        public abstract Object executeString(Object o, byte isQuoted);
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintVectorElement(RNull operand, byte isQuoted) {
-            return "NULL";
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintVectorElement(byte operand, byte isQuoted) {
-            return prettyPrint(operand);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintVectorElement(int operand, byte isQuoted) {
-            return prettyPrint(operand);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintVectorElement(double operand, byte isQuoted) {
-            return prettyPrint(operand);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintVectorElement(RComplex operand, byte isQuoted) {
-            return prettyPrint(operand);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintVectorElement(String operand, byte isQuoted) {
-            if (RRuntime.fromLogical(isQuoted)) {
-                return prettyPrint(operand);
-            }
-            return operand;
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintVectorElement(RRaw operand, byte isQuoted) {
-            return prettyPrint(operand);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintVectorElement(RList operand, byte isQuoted) {
-            return prettyPrint(operand);
-        }
-
-        @TruffleBoundary
-        @Specialization(guards = {"operand.getLength() != 1", "!isVectorList(operand)"})
-        protected String prettyPrintVectorElement(RAbstractVector operand, byte isQuoted) {
-            return prettyPrint(operand);
-        }
-
-        @TruffleBoundary
-        @Specialization(guards = {"operand.getLength() == 1", "!isVectorList(operand)"})
-        protected String prettyPrintVectorElementLengthOne(RAbstractVector operand, byte isQuoted) {
-            return prettyPrintRecursive(operand.getDataAtAsObject(0), isQuoted);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintVectorElement(RLanguage operand, byte isQuoted) {
-            return prettyPrintLanguageInternal(operand);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String prettyPrintVectorElement(RSymbol operand, byte isQuoted) {
-            return operand.getName();
-        }
-
-        protected static boolean isVectorList(RAbstractVector v) {
-            return v instanceof RList;
-        }
-
-        protected static boolean isLengthOne(RAbstractVector v) {
-            return v.getLength() == 1;
-        }
-    }
-
-    @NodeChildren({@NodeChild(value = "vector", type = RNode.class), @NodeChild(value = "isListOrStringVector", type = RNode.class), @NodeChild(value = "isComplexOrRawVector", type = RNode.class),
-                    @NodeChild(value = "isQuoted", type = RNode.class)})
-    abstract static class PrintVectorMultiDimNode extends RNode {
-
-        @Child private PrintVector2DimNode vector2DimPrinter;
-        @Child private PrintDimNode dimPrinter;
-
-        private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
-
-        private String printVector2Dim(RAbstractVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) {
-            if (vector2DimPrinter == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                vector2DimPrinter = insert(PrintVector2DimNodeGen.create(null, null, null, null, null, null));
-            }
-            return (String) vector2DimPrinter.executeString(vector, dimensions, offset, isListOrStringVector, isComplexOrRawVector, isQuoted);
-        }
-
-        private String printDim(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, int currentDimLevel, int arrayBase, int accDimensions, String header, byte isQuoted) {
-            if (dimPrinter == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                dimPrinter = insert(PrintDimNodeGen.create(null, null, null, null, null, null, null, null));
-            }
-            return (String) dimPrinter.executeString(vector, isListOrStringVector, isComplexOrRawVector, currentDimLevel, arrayBase, accDimensions, header, isQuoted);
-        }
-
-        public abstract Object executeString(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted);
-
-        @TruffleBoundary
-        @Specialization
-        protected String printVectorMultiDim(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) {
-            int[] dimensions = vector.getDimensions();
-            RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, RDataFactory.COMPLETE_VECTOR);
-            assert dimensions != null;
-            int numDimensions = dimensions.length;
-            assert numDimensions > 1;
-            if (numDimensions == 2) {
-                return printVector2Dim(vector, dimensionsVector, 0, isListOrStringVector, isComplexOrRawVector, isQuoted);
-            } else {
-                int dimSize = dimensions[numDimensions - 1];
-                if (dimSize == 0) {
-                    return "";
-                }
-                StringBuilder sb = new StringBuilder();
-                if (numDimensions == 3) {
-                    int matrixSize = dimensions[0] * dimensions[1];
-                    for (int dimInd = 0; dimInd < dimSize; dimInd++) {
-                        // Checkstyle: stop
-                        sb.append(", , ");
-                        // Checkstyle: resume
-                        sb.append(getDimId(vector, numDimensions, dimInd, attrProfiles));
-                        sb.append("\n\n");
-                        sb.append(printVector2Dim(vector, dimensionsVector, dimInd * matrixSize, isListOrStringVector, isComplexOrRawVector, isQuoted));
-                        sb.append("\n");
-                        if (dimInd < (dimSize - 1) && vector.getLength() > 0 || vector.getLength() == 0) {
-                            sb.append("\n");
-                        }
-                    }
-                } else {
-                    int accDimensions = vector.getLength() / dimSize;
-                    for (int dimInd = 0; dimInd < dimSize; dimInd++) {
-                        int arrayBase = accDimensions * dimInd;
-                        String dimId = getDimId(vector, numDimensions, dimInd, attrProfiles);
-                        String innerDims = printDim(vector, isListOrStringVector, isComplexOrRawVector, numDimensions - 1, arrayBase, accDimensions, dimId, isQuoted);
-                        if (innerDims == null) {
-                            return "";
-                        } else {
-                            sb.append(innerDims);
-                        }
-                    }
-                }
-                if (vector.getLength() == 0) {
-                    // remove last line break
-                    return builderToSubstring(sb, 0, sb.length() - 1);
-                } else {
-                    return builderToString(sb);
-                }
-            }
-        }
-    }
-
-    @NodeChildren({@NodeChild(value = "vector", type = RNode.class), @NodeChild(value = "dimensions", type = RNode.class), @NodeChild(value = "offset", type = RNode.class),
-                    @NodeChild(value = "isListOrStringVector", type = RNode.class), @NodeChild(value = "isComplexOrRawVector", type = RNode.class), @NodeChild(value = "isQuoted", type = RNode.class)})
-    abstract static class PrintVector2DimNode extends RNode {
-
-        @Child private PrettyPrinterSingleVectorElementNode singleVectorElementPrettyPrinter;
-
-        private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
-
-        private String prettyPrintSingleVectorElement(Object o, byte isQuoted) {
-            if (singleVectorElementPrettyPrinter == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                singleVectorElementPrettyPrinter = insert(PrettyPrinterSingleVectorElementNodeGen.create(null, null));
-            }
-            return (String) singleVectorElementPrettyPrinter.executeString(o, isQuoted);
-        }
-
-        public abstract Object executeString(RAbstractVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted);
-
-        private static String getDimId(RList dimNames, int dimension, int ind, byte isComplexOrRawVector) {
-            StringBuilder sb = new StringBuilder();
-            if (dimNames == null || dimNames.getDataAt(dimension) == RNull.instance) {
-                String rs = intString(ind);
-                sb.append("[");
-                if (dimension == 1) {
-                    // columns
-                    sb.append(',');
-                }
-                sb.append(rs);
-                if (dimension == 0) {
-                    // rows
-                    sb.append(',');
-                }
-                sb.append(']');
-            } else {
-                RStringVector dimNamesVector = (RStringVector) dimNames.getDataAt(dimension);
-                String dimId = dimNamesVector.getDataAt(ind - 1);
-                if (dimension == 1 && isComplexOrRawVector == RRuntime.LOGICAL_TRUE && dimId.length() == 1) {
-                    sb.append(' ');
-                }
-                sb.append(dimId);
-            }
-            return builderToString(sb);
-        }
-
-        @TruffleBoundary
-        @Specialization(guards = "vector.getLength() == 0")
-        protected String printVector2DimEmpty(RAbstractVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) {
-            int nrow = dimensions.getDataAt(0);
-            int ncol = dimensions.getDataAt(1);
-
-            if (nrow == 0 && ncol == 0) {
-                if (dimensions.getLength() == 2) {
-                    return "<0 x 0 matrix>";
-                } else {
-                    return "";
-                }
-            }
-
-            StringBuilder sb = new StringBuilder();
-            RList dimNames = vector.getDimNames(attrProfiles);
-            if (ncol > 0) {
-                sb.append("     ");
-                for (int c = 1; c <= ncol; c++) {
-                    sb.append(getDimId(dimNames, 1, c, isComplexOrRawVector));
-                    if (c < ncol) {
-                        sb.append(' ');
-                    }
-                }
-            }
-            if (nrow > 0) {
-                sb.append('\n');
-                for (int r = 1; r <= nrow; r++) {
-                    sb.append(getDimId(dimNames, 0, r, isComplexOrRawVector));
-                    if (r < nrow) {
-                        sb.append('\n');
-                    }
-                }
-            }
-            return builderToString(sb);
-        }
-
-        @TruffleBoundary
-        @Specialization(guards = "vector.getLength() != 0")
-        protected String printVector2Dim(RAbstractDoubleVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) {
-            int nrow = dimensions.getDataAt(0);
-            int ncol = dimensions.getDataAt(1);
-
-            // prepare data (relevant for column widths)
-            String[] dataStrings = new String[nrow * ncol];
-            int[] dataColWidths = new int[ncol];
-            RList dimNames = vector.getDimNames(attrProfiles);
-            RStringVector columnDimNames = null;
-            if (dimNames != null && dimNames.getDataAt(1) != RNull.instance) {
-                columnDimNames = (RStringVector) dimNames.getDataAt(1);
-            }
-            double[] maxRoundFactors = new double[ncol];
-            int[] maxDigitsBehindDot = new int[ncol];
-            for (int c = 0; c < ncol; c++) {
-                maxRoundFactors[c] = 0;
-                for (int r = 0; r < nrow; r++) {
-                    int index = c * nrow + r;
-                    double data = vector.getDataAt(index + offset);
-                    double roundFactor = calcRoundFactor(data, 10000000);
-                    if (roundFactor > maxRoundFactors[c]) {
-                        maxRoundFactors[c] = roundFactor;
-                    }
-                }
-                maxDigitsBehindDot[c] = getMaxDigitsBehindDot(maxRoundFactors[c]);
-            }
-            int rowHeaderWidth = 0;
-            for (int c = 0; c < ncol; c++) {
-                for (int r = 0; r < nrow; r++) {
-                    int index = c * nrow + r;
-                    dataStrings[index] = prettyPrint(vector.getDataAt(index + offset), maxRoundFactors[c], maxDigitsBehindDot[c]);
-                    maintainColumnData(dataColWidths, columnDimNames, c, dataStrings[index]);
-                    rowHeaderWidth = Math.max(rowHeaderWidth, rowHeader(r + 1, vector, attrProfiles).length());
-                }
-            }
-
-            // probably add trailing decimal points and zeroes
-            // iterate over columns
-            for (int c = 0; c < ncol; c++) {
-                postProcessDoubleColumn(dataStrings, nrow, ncol, c);
-                // final adjustment of column width
-                boolean hasNegative = false;
-                for (int r = 0; r < nrow; r++) {
-                    // do not count minus signs
-                    String data = dataStrings[c * nrow + r];
-                    boolean isNegative = data.charAt(0) == '-';
-                    hasNegative = hasNegative || isNegative;
-                    int l = isNegative ? data.length() - 1 : data.length();
-                    if (l > dataColWidths[c]) {
-                        dataColWidths[c] = l;
-                    }
-                }
-                if (hasNegative) {
-                    dataColWidths[c] = -dataColWidths[c];
-                }
-            }
-
-            return formatResult(vector, nrow, ncol, dataStrings, dataColWidths, rowHeaderWidth, isListOrStringVector == RRuntime.LOGICAL_TRUE);
-        }
-
-        @TruffleBoundary
-        @Specialization(guards = "vector.getLength() != 0")
-        protected String printVector2Dim(RAbstractComplexVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) {
-            int nrow = dimensions.getDataAt(0);
-            int ncol = dimensions.getDataAt(1);
-
-            // prepare data (relevant for column widths)
-            String[] reStrings = new String[nrow * ncol];
-            String[] imStrings = new String[nrow * ncol];
-            String[] siStrings = new String[nrow * ncol];
-            int[] dataColWidths = new int[ncol];
-            RList dimNames = vector.getDimNames(attrProfiles);
-            RStringVector columnDimNames = null;
-            if (dimNames != null && dimNames.getDataAt(1) != RNull.instance) {
-                columnDimNames = (RStringVector) dimNames.getDataAt(1);
-            }
-            int rowHeaderWidth = 0;
-            for (int r = 0; r < nrow; r++) {
-                for (int c = 0; c < ncol; c++) {
-                    int index = c * nrow + r;
-                    reStrings[index] = prettyPrintSingleVectorElement(vector.getDataAt(index + offset).getRealPart(), isQuoted);
-                    imStrings[index] = prettyPrintSingleVectorElement(vector.getDataAt(index + offset).getImaginaryPart(), isQuoted);
-                    siStrings[index] = vector.getDataAt(index + offset).getImaginaryPart() < 0.0 ? "-" : "+";
-                    // "" because column width is computed later
-                    maintainColumnData(dataColWidths, columnDimNames, c, "");
-                }
-                rowHeaderWidth = Math.max(rowHeaderWidth, rowHeader(r + 1, vector, attrProfiles).length());
-            }
-
-            // adjust formatting
-            // iterate over columns
-            for (int c = 0; c < ncol; c++) {
-                postProcessComplexColumn(reStrings, imStrings, nrow, ncol, c);
-            }
-
-            String[] dataStrings = new String[nrow * ncol];
-            for (int i = 0; i < dataStrings.length; i++) {
-                dataStrings[i] = vector.getDataAt(i).isNA() ? "NA" : concat(reStrings[i], siStrings[i], imStrings[i], "i");
-            }
-
-            // final adjustment of column width
-            for (int c = 0; c < ncol; c++) {
-                for (int r = 0; r < nrow; r++) {
-                    // do not count minus signs
-                    String data = dataStrings[c * nrow + r];
-                    int l = data.charAt(0) == '-' ? data.length() - 1 : data.length();
-                    if (l > dataColWidths[c]) {
-                        dataColWidths[c] = l;
-                    }
-                }
-            }
-
-            return formatResult(vector, nrow, ncol, dataStrings, dataColWidths, rowHeaderWidth, isListOrStringVector == RRuntime.LOGICAL_TRUE);
-        }
-
-        @TruffleBoundary
-        @Specialization(guards = {"vector.getLength() != 0", "notDoubleOrComplex(vector)"})
-        protected String printVector2Dim(RAbstractVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) {
-            int nrow = dimensions.getDataAt(0);
-            int ncol = dimensions.getDataAt(1);
-
-            // prepare data (relevant for column widths)
-            String[] dataStrings = new String[nrow * ncol];
-            int[] dataColWidths = new int[ncol];
-            RList dimNames = vector.getDimNames(attrProfiles);
-            RStringVector columnDimNames = null;
-            if (dimNames != null && dimNames.getDataAt(1) != RNull.instance) {
-                if (dimNames.getDataAt(1) instanceof String) {
-                    columnDimNames = RDataFactory.createStringVector((String) dimNames.getDataAt(1));
-                } else {
-                    columnDimNames = (RStringVector) dimNames.getDataAt(1);
-                }
-            }
-            int rowHeaderWidth = 0;
-            for (int r = 0; r < nrow; r++) {
-                for (int c = 0; c < ncol; c++) {
-                    int index = c * nrow + r;
-                    dataStrings[index] = prettyPrintSingleVectorElement(vector.getDataAtAsObject(index + offset), isQuoted);
-                    maintainColumnData(dataColWidths, columnDimNames, c, dataStrings[index]);
-                }
-                rowHeaderWidth = Math.max(rowHeaderWidth, rowHeader(r + 1, vector, attrProfiles).length());
-            }
-
-            return formatResult(vector, nrow, ncol, dataStrings, dataColWidths, rowHeaderWidth, isListOrStringVector == RRuntime.LOGICAL_TRUE);
-        }
-
-        protected boolean notDoubleOrComplex(RAbstractVector vector) {
-            return vector.getElementClass() != RDouble.class && vector.getElementClass() != RComplex.class;
-        }
-
-        private static void postProcessDoubleColumn(String[] dataStrings, int nrow, int ncol, int col) {
-            // create and populate array with column data
-            String[] columnData = new String[nrow];
-            for (int r = 0; r < nrow; r++) {
-                columnData[r] = dataStrings[col * nrow + r];
-            }
-            padTrailingDecimalPointAndZeroesIfRequired(columnData);
-            // put possibly changed data back
-            for (int r = 0; r < nrow; r++) {
-                dataStrings[col * nrow + r] = columnData[r];
-            }
-        }
-
-        private static void postProcessComplexColumn(String[] re, String[] im, int nrow, int ncol, int col) {
-            // create and populate arrays with column data
-            String[] cre = new String[nrow];
-            String[] cim = new String[nrow];
-            for (int r = 0; r < nrow; r++) {
-                cre[r] = re[col * nrow + r];
-                cim[r] = im[col * nrow + r];
-            }
-
-            padTrailingDecimalPointAndZeroesIfRequired(cre);
-            padTrailingDecimalPointAndZeroesIfRequired(cim);
-            removeLeadingMinus(cim);
-            rightJustify(cre);
-            rightJustify(cim);
-
-            // put possibly changed data back
-            for (int r = 0; r < nrow; r++) {
-                re[col * nrow + r] = cre[r];
-                im[col * nrow + r] = cim[r];
-            }
-        }
-
-        private static void maintainColumnData(int[] dataColWidths, RStringVector columnDimNames, int c, String data) {
-            // do not count minus signs
-            int dataLength = !data.equals("") && data.charAt(0) == '-' ? data.length() - 1 : data.length();
-            if (dataLength > dataColWidths[c]) {
-                dataColWidths[c] = dataLength;
-            }
-            if (columnDimNames != null) {
-                String columnName = columnDimNames.getDataAt(c);
-                if (RRuntime.isNA(columnName)) {
-                    columnName = RRuntime.NA_HEADER;
-                }
-                if (columnName.length() > dataColWidths[c]) {
-                    dataColWidths[c] = columnName.length();
-                }
-            }
-        }
-
-        private String formatResult(RAbstractVector vector, int nrow, int ncol, String[] dataStrings, int[] dataColWidths, int rowHeaderWidth, boolean isListOrStringVector) {
-            boolean isComplexVector = vector.getElementClass() == RComplex.class;
-            boolean isDoubleVector = vector.getElementClass() == RDouble.class;
-            String rowFormat = concat("%", intString(rowHeaderWidth), "s");
-
-            StringBuilder b = new StringBuilder();
-
-            int colInd = 0;
-            while (true) {
-                int totalWidth = rowHeaderWidth + 1;
-                int startColInd = colInd;
-                for (; colInd < dataColWidths.length; colInd++) {
-                    boolean hasNegative = dataColWidths[colInd] < 0;
-                    totalWidth += Math.abs(dataColWidths[colInd]) + ((isDoubleVector || isComplexVector) && hasNegative ? 2 : 1);
-                    if (totalWidth > (int) RContext.getInstance().stateROptions.getValue("name")) {
-                        if (colInd == startColInd) {
-                            // the first column is already too wide but needs to be printed
-                            // nevertheless
-                            colInd++;
-                        }
-                        break;
-                    }
-                }
-
-                // column header
-                spaces(b, rowHeaderWidth + 1);
-                for (int c = startColInd + 1; c <= colInd; c++) {
-                    boolean hasNegative = dataColWidths[c - 1] < 0;
-                    // header of the first column needs extra padding if this column has negative
-                    // numbers
-                    int padding = Math.abs(dataColWidths[c - 1]) + ((isDoubleVector || isComplexVector) && hasNegative ? 1 : 0);
-                    b.append(padColHeader(c, padding, vector, isListOrStringVector, attrProfiles));
-                    if (c < colInd) {
-                        b.append(" ");
-                    }
-                }
-                b.append('\n');
-
-                boolean indexRowHeaders = rowHeaderUsesIndices(vector.getDimNames(attrProfiles));
-
-                // rows
-                for (int r = 1; r <= nrow; r++) {
-                    String headerString = rowHeader(r, vector, attrProfiles);
-                    if (indexRowHeaders) {
-                        spaces(b, rowHeaderWidth - headerString.length());
-                        b.append(headerString).append(' ');
-                    } else {
-                        b.append(headerString);
-                        spaces(b, rowHeaderWidth - headerString.length() + 1);
-                    }
-                    for (int c = startColInd + 1; c <= colInd; c++) {
-                        String dataString = dataStrings[(c - 1) * nrow + (r - 1)];
-                        boolean hasNegative = dataColWidths[c - 1] < 0;
-                        int padding = Math.abs(dataColWidths[c - 1]) + ((isDoubleVector || isComplexVector) && hasNegative ? 1 : 0);
-                        if (isListOrStringVector || (isComplexVector && !RRuntime.STRING_NA.equals(dataString))) {
-                            // list elements are left-justified, and so are complex matrix elements
-                            // that are not NA
-                            b.append(dataString);
-                            spaces(b, padColHeader(c, padding, vector, isListOrStringVector, attrProfiles).length() - dataString.length());
-                        } else {
-                            // vector elements are right-justified, and so are NAs in complex
-                            // matrices
-                            String cellFormat = concat("%", intString(padColHeader(c, padding, vector, isListOrStringVector, attrProfiles).length()), "s");
-                            b.append(stringFormat(cellFormat, dataString));
-                        }
-                        if (c < colInd) {
-                            b.append(' ');
-                        }
-                    }
-                    if (r < nrow) {
-                        b.append('\n');
-                    }
-                }
-                if (colInd < dataColWidths.length) {
-                    b.append('\n');
-                } else {
-                    break;
-                }
-            }
-            return builderToString(b);
-        }
-    }
-
-    @NodeChildren({@NodeChild(value = "vector", type = RNode.class), @NodeChild(value = "isListOrStringVector", type = RNode.class), @NodeChild(value = "isComplexOrRawVector", type = RNode.class),
-                    @NodeChild(value = "currentDimLevel", type = RNode.class), @NodeChild(value = "arrayBase", type = RNode.class), @NodeChild(value = "accDimensions", type = RNode.class),
-                    @NodeChild(value = "header", type = RNode.class), @NodeChild(value = "isQuoted", type = RNode.class)})
-    abstract static class PrintDimNode extends RNode {
-
-        public abstract Object executeString(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, int currentDimLevel, int arrayBase, int accDimensions,
-                        String header, byte isQuoted);
-
-        @Child private PrintVector2DimNode vector2DimPrinter;
-        @Child private PrintDimNode dimPrinter;
-
-        private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
-
-        private String printVector2Dim(RAbstractVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) {
-            if (vector2DimPrinter == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                vector2DimPrinter = insert(PrintVector2DimNodeGen.create(null, null, null, null, null, null));
-            }
-            return (String) vector2DimPrinter.executeString(vector, dimensions, offset, isListOrStringVector, isComplexOrRawVector, isQuoted);
-        }
-
-        private String printDimRecursive(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, int currentDimLevel, int arrayBase, int accDimensions, String header,
-                        byte isQuoted) {
-            if (dimPrinter == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                dimPrinter = insert(PrintDimNodeGen.create(null, null, null, null, null, null, null, null));
-            }
-            return (String) dimPrinter.executeString(vector, isListOrStringVector, isComplexOrRawVector, currentDimLevel, arrayBase, accDimensions, header, isQuoted);
-        }
-
-        @TruffleBoundary
-        @Specialization
-        protected String printDim(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, int currentDimLevel, int arrayBase, int accDimensions, String header, byte isQuoted) {
-            int[] dimensions = vector.getDimensions();
-            RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, RDataFactory.COMPLETE_VECTOR);
-            StringBuilder sb = new StringBuilder();
-            int dimSize = dimensions[currentDimLevel - 1];
-            if (dimSize == 0) {
-                return null;
-            }
-            if (currentDimLevel == 3) {
-                int matrixSize = dimensions[0] * dimensions[1];
-                for (int dimInd = 0; dimInd < dimSize; dimInd++) {
-                    // Checkstyle: stop
-                    sb.append(", , ");
-                    // Checkstyle: resume
-                    sb.append(getDimId(vector, currentDimLevel, dimInd, attrProfiles));
-                    sb.append(", ");
-                    sb.append(header);
-                    sb.append("\n\n");
-                    sb.append(printVector2Dim(vector, dimensionsVector, arrayBase + (dimInd * matrixSize), isListOrStringVector, isComplexOrRawVector, isQuoted));
-                    sb.append("\n");
-                    if ((arrayBase + (dimInd * matrixSize) + matrixSize) < vector.getLength() || vector.getLength() == 0) {
-                        sb.append("\n");
-                    }
-                }
-            } else {
-                int newAccDimensions = accDimensions / dimSize;
-                for (int dimInd = 0; dimInd < dimSize; dimInd++) {
-                    int newArrayBase = arrayBase + newAccDimensions * dimInd;
-                    String dimId = getDimId(vector, currentDimLevel, dimInd, attrProfiles);
-                    String innerDims = printDimRecursive(vector, isListOrStringVector, isComplexOrRawVector, currentDimLevel - 1, newArrayBase, newAccDimensions, concat(dimId, ", ", header),
-                                    isQuoted);
-                    if (innerDims == null) {
-                        return null;
-                    } else {
-                        sb.append(innerDims);
-                    }
-                }
-                return builderToString(sb);
-            }
-            return builderToString(sb);
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java
index 760c12d79b473e2988b281d135c54b5822a35f83..4b209c83fe3888acb7056aac0a3b70d79999a9d8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java
@@ -80,7 +80,7 @@ public class PrintFunctions {
                         @Cached("createShowFunction(frame)") RFunction showFunction) {
             if (noOpt) {
                 // S4 should only be called in case noOpt is true
-                RContext.getEngine().evalFunction(showFunction, null, null, o);
+                RContext.getEngine().evalFunction(showFunction, null, null, null, o);
             } else {
                 printDefault(showFunction, digits, quote, naPrint, printGap, right, max, useSource, noOpt);
             }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
index d8981ee372263777514a391e9597abcf9e7c23cc..fe4860d7a7b3cc5b35a79c475f1f03a8dc6e73c7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
@@ -51,7 +51,7 @@ public abstract class Quit extends RBuiltinNode {
     @Specialization
     @TruffleBoundary
     protected Object doQuit(RAbstractStringVector saveArg, final int status, final byte runLastIn) {
-        if (RContext.getInstance().isInBrowser()) {
+        if (RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser()) {
             RError.warning(this, RError.Message.BROWSER_QUIT);
             return RNull.instance;
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
index 9cd64c59070f6381542bbb808e9b9f1421f867fd..6e4e54843c564b6ab411d24c895a1113c8372c26 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
@@ -24,14 +24,13 @@ import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.AttributeAccess;
 import com.oracle.truffle.r.nodes.attributes.AttributeAccessNodeGen;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.objects.CollectGenericArgumentsNode;
 import com.oracle.truffle.r.nodes.objects.CollectGenericArgumentsNodeGen;
 import com.oracle.truffle.r.nodes.objects.DispatchGeneric;
 import com.oracle.truffle.r.nodes.objects.DispatchGenericNodeGen;
-import com.oracle.truffle.r.nodes.unary.CastIntegerScalarNode;
-import com.oracle.truffle.r.nodes.unary.CastStringScalarNode;
-import com.oracle.truffle.r.nodes.unary.CastStringScalarNodeGen;
+import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RBuiltin;
 import com.oracle.truffle.r.runtime.RCaller;
@@ -58,14 +57,22 @@ public abstract class StandardGeneric extends RBuiltinNode {
 
     @Child private AttributeAccess genericAttrAccess;
     @Child private FrameFunctions.SysFunction sysFunction;
-    @Child private CastStringScalarNode castStringScalar = CastStringScalarNodeGen.create();
     @Child private LocalReadVariableNode readMTableFirst = LocalReadVariableNode.create(RRuntime.DOT_ALL_MTABLE, true);
     @Child private LocalReadVariableNode readSigLength = LocalReadVariableNode.create(RRuntime.DOT_SIG_LENGTH, true);
     @Child private LocalReadVariableNode readSigARgs = LocalReadVariableNode.create(RRuntime.DOT_SIG_ARGS, true);
-    @Child private CastIntegerScalarNode castIntScalar = CastIntegerScalarNode.create();
     @Child private CollectGenericArgumentsNode collectArgumentsNode;
     @Child private DispatchGeneric dispatchGeneric = DispatchGenericNodeGen.create();
 
+    @Child private CastNode castIntScalar;
+    @Child private CastNode castStringScalar;
+    {
+        CastBuilder builder = new CastBuilder();
+        builder.arg(0).asIntegerVector().findFirst(RRuntime.INT_NA);
+        builder.arg(1).asStringVector().findFirst(RRuntime.STRING_NA);
+        castIntScalar = builder.getCasts()[0];
+        castStringScalar = builder.getCasts()[1];
+    }
+
     private final BranchProfile noGenFunFound = BranchProfile.create();
     private final ConditionProfile sameNamesProfile = ConditionProfile.createBinaryProfile();
 
@@ -81,10 +88,10 @@ public abstract class StandardGeneric extends RBuiltinNode {
             // and this slow path should not be executed again
             REnvironment methodsEnv = REnvironment.getRegisteredNamespace("methods");
             RFunction currentFunction = ReadVariableNode.lookupFunction(".getMethodsTable", methodsEnv.getFrame(), true);
-            mtable = (REnvironment) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), fdef);
+            mtable = (REnvironment) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), null, fdef);
         }
         RList sigArgs = (RList) readSigARgs.execute(null, fnFrame);
-        int sigLength = castIntScalar.executeInt(readSigLength.execute(null, fnFrame));
+        int sigLength = (int) castIntScalar.execute(readSigLength.execute(null, fnFrame));
         if (sigLength > sigArgs.getLength()) {
             throw RError.error(this, RError.Message.GENERIC, "'.SigArgs' is shorter than '.SigLength' says it should be");
         }
@@ -118,7 +125,7 @@ public abstract class StandardGeneric extends RBuiltinNode {
             noGenFunFound.enter();
             return null;
         }
-        String gen = castStringScalar.executeString(genObj);
+        String gen = (String) castStringScalar.execute(genObj);
         if (sameNamesProfile.profile(gen == fname)) {
             return stdGenericInternal(frame, fVec, fn);
         } else {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java
index 341a599ab3100966d00a8cae5e0d361e6d1cf630..c724cfb934de63b4aedf83776edd6eff31a02133 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java
@@ -22,23 +22,41 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+
+import java.io.IOException;
+import java.util.HashSet;
+
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.Frame;
+import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen;
 import com.oracle.truffle.r.nodes.builtin.helpers.TraceHandling;
+import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RBuiltin;
 import com.oracle.truffle.r.runtime.RBuiltinKind;
+import com.oracle.truffle.r.runtime.RCaller;
 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.RType;
 import com.oracle.truffle.r.runtime.RVisibility;
+import com.oracle.truffle.r.runtime.conn.StdConnections;
 import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.MemoryTracer;
 import com.oracle.truffle.r.runtime.data.RFunction;
+import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public class TraceFunctions {
 
@@ -111,4 +129,128 @@ public class TraceFunctions {
             return RRuntime.asLogical(RContext.getInstance().stateInstrumentation.getTracingState());
         }
     }
+
+    public abstract static class TracememBase extends RBuiltinNode {
+        static {
+            MemoryTracer.setListener(new TracememBase.TracememListener());
+        }
+
+        protected static HashSet<Object> getTracedObjects() {
+            return RContext.getInstance().getInstrumentationState().getTracemem().getTracedObjects();
+        }
+
+        protected static String formatHashCode(Object x) {
+            return String.format("<0x%x>", x.hashCode());
+        }
+
+        protected static void startTracing(Object x) {
+            getTracedObjects().add(x);
+            MemoryTracer.reportEvents();
+        }
+
+        protected static void printToStdout(String msg) {
+            try {
+                StdConnections.getStdout().writeString(msg, true);
+            } catch (IOException ex) {
+                throw RError.error(RError.NO_CALLER, RError.Message.GENERIC, ex.getMessage());
+            }
+        }
+
+        @TruffleBoundary
+        protected static String getStackTrace() {
+            final StringBuffer result = new StringBuffer();
+            Truffle.getRuntime().iterateFrames(frame -> {
+                Frame unwrapped = RArguments.unwrap(frame.getFrame(FrameAccess.READ_ONLY, true));
+                if (RArguments.isRFrame(unwrapped)) {
+                    RCaller call = RArguments.getCall(unwrapped);
+                    if (call != null && call.isValidCaller()) {
+                        result.append(RContext.getRRuntimeASTAccess().getCallerSource(call));
+                        result.append(' ');
+                    }
+                }
+                return null;
+            });
+            return result.toString();
+        }
+
+        private static final class TracememListener implements MemoryTracer.Listener {
+            @Override
+            public void reportCopying(RAbstractVector src, RAbstractVector dest) {
+                if (getTracedObjects().contains(src)) {
+                    printToStdout(String.format("tracemem[0x%x -> 0x%x]: %s", src.hashCode(), dest.hashCode(), getStackTrace()));
+                }
+            }
+        }
+    }
+
+    /**
+     * Note: tracemem does not support scalars: these are stored in frame directly not wrapped in a
+     * vector class. When these are manipulated as 'vectors', they are wrapped temporarily, such
+     * temporary vector wrappers cannot be traced however.
+     */
+    @RBuiltin(name = "tracemem", kind = RBuiltinKind.PRIMITIVE, parameterNames = "x")
+    public abstract static class Tracemem extends TracememBase {
+        @Override
+        protected void createCasts(CastBuilder casts) {
+            casts.arg("x").mustBe(nullValue().not(), Message.TRACEMEM_NOT_NULL);
+        }
+
+        @Specialization
+        protected String execute(Object x) {
+            startTracing(x);
+            return formatHashCode(x);
+        }
+    }
+
+    /**
+     * {@code retracemem} differences from {@code tracemem} are that it fails silently when R is not
+     * build with memory tracing support or x is NULL and it has additional parameter with an
+     * unclear meaning.
+     */
+    @RBuiltin(name = "retracemem", kind = RBuiltinKind.PRIMITIVE, visibility = RVisibility.CUSTOM, parameterNames = {"x", "previous"})
+    public abstract static class Retracemem extends TracememBase {
+        @Override
+        protected void createCasts(CastBuilder casts) {
+            casts.arg("previous").defaultError(Message.INVALID_ARGUMENT, "previous").mustBe(stringValue().or(missingValue()));
+        }
+
+        @Specialization
+        protected Object execute(Object x, @SuppressWarnings("unused") RNull previous) {
+            return getResult(x);
+        }
+
+        @Specialization
+        protected Object execute(Object x, @SuppressWarnings("unused") RMissing previous) {
+            return getResult(x);
+        }
+
+        @Specialization
+        protected Object execute(Object x, String previous) {
+            Object result = getResult(x);
+            if (x != null && x != RNull.instance) {
+                startTracing(x);
+                printToStdout(String.format("tracemem[%s -> 0x%x]: %s", previous, x.hashCode(), getStackTrace()));
+            }
+            return result;
+        }
+
+        private static Object getResult(Object x) {
+            if (!isRNull(x) && getTracedObjects().contains(x)) {
+                RContext.getInstance().setVisible(true);
+                return formatHashCode(x);
+            } else {
+                RContext.getInstance().setVisible(false);
+                return RNull.instance;
+            }
+        }
+    }
+
+    @RBuiltin(name = "untracemem", kind = RBuiltinKind.PRIMITIVE, visibility = RVisibility.OFF, parameterNames = "x")
+    public abstract static class Untracemem extends TracememBase {
+        @Specialization
+        protected RNull execute(Object x) {
+            getTracedObjects().remove(x);
+            return RNull.instance;
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
index d91d4a8fbbe67167fb4ef437b99865e6abca9fe0..8c67c523f28176fe28445d8b3b5cd24ab0d73260 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
@@ -163,7 +163,7 @@ public abstract class UpdateDimNames extends RBuiltinNode {
             RList resDimNames = newDimNames;
             if (newDimNamesLength < dimensions.length) {
                 // resize the array and fill the missing entries with NULL-s
-                resDimNames = resDimNames.copyResized(dimensions.length, true);
+                resDimNames = (RList) resDimNames.copyResized(dimensions.length, true);
                 resDimNames.setAttributes(newDimNames);
                 for (int i = newDimNamesLength; i < dimensions.length; i++) {
                     resDimNames.updateDataAt(i, RNull.instance, null);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java
index d192337e3792cb3a2d984f9081c02eaf12713e9d..317ce79c47937da8c3668727093dd086aeb21372 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java
@@ -72,7 +72,7 @@ public abstract class UpdateNames extends RBuiltinNode {
         }
         RAbstractContainer result = (RAbstractContainer) container.getNonShared();
         if (stringVector.getLength() < result.getLength()) {
-            stringVector = stringVector.copyResized(result.getLength(), true);
+            stringVector = (RStringVector) stringVector.copyResized(result.getLength(), true);
         } else if (stringVector.getLength() > result.getLength()) {
             throw RError.error(this, Message.NAMES_LONGER, stringVector.getLength(), result.getLength());
         } else if (stringVector == container) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
index 34b82ecb414147552844b3dee4600d72809f2c5b..31d5719ff049de145a5bffefc6dd648a4c6b5fec 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
@@ -107,7 +107,7 @@ public abstract class UpdateSlot extends RBuiltinNode {
             checkAtAssignmentCall.call(frame, args);
         } else {
             // slow path
-            RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), objClass, name, valClass);
+            RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), null, objClass, name, valClass);
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
index 6d314f2c96ab4922cae488b2172ca3cfe206a09f..fac8867b5f7d166621ab0b1438eb78eb4d568577 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
 import static com.oracle.truffle.r.runtime.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -45,7 +46,7 @@ public abstract class Vector extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.convertToInteger(1);
+        casts.arg("length").asIntegerVector().mustBe(singleElement()).findFirst();
     }
 
     protected RType modeToType(String mode) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java
index 3e2a6aaa8deccf201689df416f80212bce615034..d66b1be427541de72840a0cabaccb3aeb4b72115 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java
@@ -52,6 +52,6 @@ public abstract class Xtfrm extends RBuiltinNode {
             getNode = insert(GetNodeGen.create(null));
         }
         RFunction func = (RFunction) getNode.execute(frame, "xtfrm.default", RArguments.getEnvironment(frame), RType.Function.getName(), true);
-        return RContext.getEngine().evalFunction(func, null, null, x);
+        return RContext.getEngine().evalFunction(func, null, null, null, x);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java
index ad3a084a0509bca41911f3b84dbcb649a000d033..e3c6e354648afc064ce811405de7837b8ecf98aa 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java
@@ -60,7 +60,7 @@ final class S4ObjectPrinter implements ValuePrinter<RS4Object> {
 
     static void printS4(PrintContext printCtx, Object o) {
         Frame frame = com.oracle.truffle.r.runtime.Utils.getActualCurrentFrame();
-        RContext.getEngine().evalFunction(createShowFunction(frame), null, null, o);
+        RContext.getEngine().evalFunction(createShowFunction(frame), null, null, null, o);
         // The show function prints an additional new line character. The following attribute
         // instructs the ValuePrinter.println method not to print the new line since it was
         // already printed.
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java
index 5020e439eb0315feca814e87cfa54aa8fe1ef7bc..d124cf1fcf353ea953fba02552e7f63f02f3d5d2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java
@@ -25,7 +25,11 @@ package com.oracle.truffle.r.nodes.builtin.base.printer;
 import java.io.IOException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode;
 import com.oracle.truffle.r.nodes.builtin.base.Inherits;
 import com.oracle.truffle.r.nodes.builtin.base.InheritsNodeGen;
@@ -130,4 +134,17 @@ public abstract class ValuePrinterNode extends RBaseNode {
     private static void prettyPrint(Object o, PrintContext printCtx) throws IOException {
         ValuePrinters.INSTANCE.println(o, printCtx);
     }
+
+    public static String prettyPrint(final Object value) {
+        return (String) Truffle.getRuntime().createCallTarget(new RootNode(TruffleLanguage.class, null, null) {
+
+            @Child ValuePrinterNode valuePrinterNode = ValuePrinterNodeGen.create();
+
+            @Override
+            public Object execute(VirtualFrame frame) {
+                return valuePrinterNode.prettyPrint(value, AnyVectorToStringVectorWriter::new);
+            }
+        }).call(value);
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java
index 684450a20e1db09768ac470155812eee1bd3f76a..72afb897490df85bbbd3f7e4e8e2a2047a74b4ea 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java
@@ -29,7 +29,7 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RBuiltin;
 
-@RBuiltin(aliases = "fastr.identity", name = ".fastr.identity", kind = PRIMITIVE, parameterNames = {""})
+@RBuiltin(name = ".fastr.identity", kind = PRIMITIVE, parameterNames = {""})
 public abstract class FastRIdentity extends RBuiltinNode {
     @Specialization
     @TruffleBoundary
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java
index 8f8d110389efc85db52d5646f675f56affa90ae1..ebbf9c234093fb3b997aa08ed58417a696e61447 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java
@@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.data.RShareable;
  * returns -1 for non-shareable, 0 for private, 1 for temp, 2 for shared and SHARED_PERMANENT_VAL
  * for permanent shared
  */
-@RBuiltin(aliases = "fastr.refcountinfo", name = ".fastr.refcountinfo", kind = PRIMITIVE, parameterNames = {""})
+@RBuiltin(name = ".fastr.refcountinfo", kind = PRIMITIVE, parameterNames = {""})
 public abstract class FastRRefCountInfo extends RBuiltinNode {
     @Specialization
     protected int refcount(Object x) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
index d88a058041e5dc99e68ddf349047e9aa9e70747e..6f4d154672217f2e9c6283836df8b593987500af 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
@@ -36,18 +36,25 @@ import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
 import com.oracle.truffle.r.runtime.context.Engine.ParseException;
 import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.instrument.InstrumentationState.BrowserState;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
 /**
  * The interactive component of the {@code browser} function.
  *
- * TODO GnuR does not allow quit() from the browser. This really needs to be checked in the quit
- * builtin somehow.
+ * This is called in two ways:
+ * <ol>
+ * <li>implicitly when a function has had {@code debug} called</li>
+ * <li>explicitly by a call in the source code. N.B. in this case we must enable debugging
+ * (instrumentation) because a {@code n} command must stop at the next statement.</li>
+ * </ol>
+ *
  */
 public abstract class BrowserInteractNode extends RNode {
 
@@ -56,18 +63,19 @@ public abstract class BrowserInteractNode extends RNode {
     public static final int CONTINUE = 2;
     public static final int FINISH = 3;
 
-    private static String lastEmptyLineCommand = "n";
-
     @Specialization
     protected int interact(VirtualFrame frame) {
         CompilerDirectives.transferToInterpreter();
         MaterializedFrame mFrame = frame.materialize();
         ConsoleHandler ch = RContext.getInstance().getConsoleHandler();
+        BrowserState browserState = RContext.getInstance().stateInstrumentation.getBrowserState();
         String savedPrompt = ch.getPrompt();
         ch.setPrompt(browserPrompt(RArguments.getDepth(frame)));
+        RFunction caller = RArguments.getFunction(frame);
+        boolean callerIsDebugged = DebugHandling.isDebugged(caller);
         int exitMode = NEXT;
         try {
-            RContext.getInstance().setInBrowser(true);
+            browserState.setInBrowser(true);
             LW: while (true) {
                 String input = ch.readLine();
                 if (input != null) {
@@ -76,7 +84,7 @@ public abstract class BrowserInteractNode extends RNode {
                 if (input == null || input.length() == 0) {
                     byte browserNLdisabledVec = RRuntime.asLogicalObject(RContext.getInstance().stateROptions.getValue("browserNLdisabled"));
                     if (!RRuntime.fromLogical(browserNLdisabledVec)) {
-                        input = lastEmptyLineCommand;
+                        input = browserState.lastEmptyLineCommand();
                     }
                 }
                 switch (input) {
@@ -86,11 +94,17 @@ public abstract class BrowserInteractNode extends RNode {
                         break LW;
                     case "n":
                         exitMode = NEXT;
-                        lastEmptyLineCommand = "n";
+                        if (!callerIsDebugged) {
+                            DebugHandling.enableDebug(caller, "", "", true, true);
+                        }
+                        browserState.setLastEmptyLineCommand("n");
                         break LW;
                     case "s":
                         exitMode = STEP;
-                        lastEmptyLineCommand = "s";
+                        if (!callerIsDebugged) {
+                            DebugHandling.enableDebug(caller, "", "", true, true);
+                        }
+                        browserState.setLastEmptyLineCommand("s");
                         break LW;
                     case "f":
                         exitMode = FINISH;
@@ -128,7 +142,7 @@ public abstract class BrowserInteractNode extends RNode {
             }
         } finally {
             ch.setPrompt(savedPrompt);
-            RContext.getInstance().setInBrowser(false);
+            browserState.setInBrowser(false);
         }
         return exitMode;
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java
index 76c6e1167e48c003fdb5ee32c9fb597514912321..799fa83b5bd2f153efc32738aee19ed16c462890 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java
@@ -100,19 +100,15 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNodeVisitor;
  */
 public class DebugHandling {
 
-    /**
-     * This flag is used to (temporarily) disable all debugging across calls that are used
-     * internally in the implementation.
-     */
-    private static boolean globalDisable;
-
     /**
      * Attach the DebugHandling instrument to the FunctionStatementsNode and all syntactic nodes.
+     *
+     * @param implicit TODO
      */
-    public static boolean enableDebug(RFunction func, Object text, Object condition, boolean once) {
+    public static boolean enableDebug(RFunction func, Object text, Object condition, boolean once, boolean implicit) {
         FunctionStatementsEventListener fbr = getFunctionStatementsEventListener(func);
         if (fbr == null) {
-            attachDebugHandler(func, text, condition, once);
+            attachDebugHandler(func, text, condition, once, implicit);
         } else {
             fbr.enable();
         }
@@ -142,25 +138,12 @@ public class DebugHandling {
         return (FunctionStatementsEventListener) RContext.getInstance().stateInstrumentation.getDebugListener(fdn.getSourceSection());
     }
 
-    /**
-     * Disables/enables debugging globally. Intended to be used for short period, typically while
-     * executing functions used internally by the implementation.
-     *
-     * @param disable {@code true} to disable, {@code false} to enable.
-     * @return the current value (default {@code false}.
-     */
-    public static boolean globalDisable(boolean disable) {
-        boolean current = globalDisable;
-        globalDisable = disable;
-        return current;
+    private static void attachDebugHandler(RFunction func, Object text, Object condition, boolean once, boolean implicit) {
+        attachDebugHandler(RInstrumentation.getFunctionDefinitionNode(func), text, condition, once, implicit);
     }
 
-    private static void attachDebugHandler(RFunction func, Object text, Object condition, boolean once) {
-        attachDebugHandler(RInstrumentation.getFunctionDefinitionNode(func), text, condition, once);
-    }
-
-    private static FunctionStatementsEventListener attachDebugHandler(FunctionDefinitionNode fdn, Object text, Object condition, boolean once) {
-        FunctionStatementsEventListener fser = new FunctionStatementsEventListener(fdn, text, condition, once);
+    private static FunctionStatementsEventListener attachDebugHandler(FunctionDefinitionNode fdn, Object text, Object condition, boolean once, boolean implicit) {
+        FunctionStatementsEventListener fser = new FunctionStatementsEventListener(fdn, text, condition, once, implicit);
         // First attach the main listener on the START_FUNCTION
         Instrumenter instrumenter = RInstrumentation.getInstrumenter();
         SourceSectionFilter.Builder functionBuilder = RInstrumentation.createFunctionFilter(fdn, StandardTags.RootTag.class);
@@ -189,7 +172,7 @@ public class DebugHandling {
         FunctionStatementsEventListener fser = getFunctionStatementsEventListener(fdn);
         if (fser == null) {
             // attach a "once" listener
-            fser = attachDebugHandler(fdn, null, null, true);
+            fser = attachDebugHandler(fdn, null, null, true, false);
         } else {
             if (fser.disabled()) {
                 fser.enable();
@@ -221,7 +204,7 @@ public class DebugHandling {
         }
 
         boolean disabled() {
-            return disabled || globalDisable;
+            return disabled || RContext.getInstance().stateInstrumentation.debugGloballyDisabled();
         }
 
         void disable() {
@@ -314,6 +297,11 @@ public class DebugHandling {
          * handler established temporarily for step-into.
          */
         private final boolean once;
+        /**
+         * Denotes that this was installed by an explicit call to {@code browser()} on an otherwise
+         * undebugged function. {@code assert once == true}.
+         */
+        private final boolean implicit;
         /**
          * Records whether a permanent handler was (temporarily) enabled for a step-into.
          *
@@ -321,11 +309,12 @@ public class DebugHandling {
         private boolean enabledForStepInto;
         private boolean continuing;
 
-        FunctionStatementsEventListener(FunctionDefinitionNode functionDefinitionNode, Object text, Object condition, boolean once) {
+        FunctionStatementsEventListener(FunctionDefinitionNode functionDefinitionNode, Object text, Object condition, boolean once, boolean implicit) {
             super(functionDefinitionNode, text, condition);
             RContext.getInstance().stateInstrumentation.putDebugListener(functionDefinitionNode.getSourceSection(), this);
             statementListener = new StatementEventListener(functionDefinitionNode, text, condition);
             this.once = once;
+            this.implicit = implicit;
         }
 
         StatementEventListener getStatementListener() {
@@ -415,8 +404,10 @@ public class DebugHandling {
         }
 
         private void returnCleanup(VirtualFrame frame) {
-            print("exiting from: ", false);
-            printCall(frame);
+            if (!implicit) {
+                print("exiting from: ", false);
+                printCall(frame);
+            }
             if (once || enabledForStepInto) {
                 disable();
             } else if (continuing) {
@@ -559,7 +550,7 @@ public class DebugHandling {
 
         @Override
         public void onEnter(EventContext context, VirtualFrame frame) {
-            if (!globalDisable) {
+            if (!RContext.getInstance().stateInstrumentation.debugGloballyDisabled()) {
                 FunctionDefinitionNode fdn = (FunctionDefinitionNode) context.getInstrumentedNode().getRootNode();
                 ensureSingleStep(fdn);
                 functionStatementsEventListener.clearStepInstrument();
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastStringNodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastStringNodeGenSampler.java
index 95814c609349b8e2114f5314a6e5c4bca4518a33..777b8e0e05be525d5a074cf03e726f00ac77707a 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastStringNodeGenSampler.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastStringNodeGenSampler.java
@@ -35,11 +35,10 @@ public class CastStringNodeGenSampler extends CastNodeSampler<CastStringNodeGen>
     @Override
     public TypeExpr resultTypes(TypeExpr inputType) {
         TypeExpr rt = super.resultTypes(inputType);
-        if (castNode.isEmptyVectorConvertedToNull()) {
+        if (castNode.convertEmptyVectorToNull()) {
             return rt.or(TypeExpr.union(RNull.class));
         } else {
             return rt;
         }
     }
-
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
index 81fec609976bd179e5c43f6c9a39c3ed30c1ad7d..887a6d7609e140f0d12ee908f7aebdc91ad88f31 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
@@ -79,7 +79,7 @@ public abstract class AccessSlotNode extends RNode {
                 // TODO: any way to cache it or use a mechanism similar to overrides?
                 REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods");
                 RFunction dataPart = getDataPartFunction(methodsNamespace);
-                return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), object);
+                return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), null, object);
             } else if (name == RRuntime.NAMES_ATTR_KEY && object instanceof RAbstractVector) {
                 assert false; // RS4Object can never be a vector?
                 return RNull.instance;
@@ -137,7 +137,7 @@ public abstract class AccessSlotNode extends RNode {
         // TODO: any way to cache it or use a mechanism similar to overrides?
         REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods");
         RFunction dataPart = getDataPartFunction(methodsNamespace);
-        return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), object);
+        return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), null, object);
     }
 
     // this is really a fallback specialization but @Fallback does not work here (because of the
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
index 5a751ab1ec34382631eabd8fad06bf13c27c47e3..1055b68104d67594963fe2adf41a7c0bf37bdfe2 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
@@ -68,7 +68,8 @@ public abstract class UpdateSlotNode extends RNode {
         REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods");
         Object f = methodsNamespace.findFunction("setDataPart");
         RFunction dataPart = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(f);
-        return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), object, prepareValue(value),
+        return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), null, object,
+                        prepareValue(value),
                         RRuntime.LOGICAL_TRUE);
     }
 
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 66ac8ced4bcd2759534d469d1ee878725afa55aa..908e71262a44a928adcade80d4287a953fc8215a 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
@@ -43,7 +43,6 @@ import com.oracle.truffle.r.nodes.unary.CastLogicalBaseNode;
 import com.oracle.truffle.r.nodes.unary.CastLogicalBaseNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastLogicalNode;
 import com.oracle.truffle.r.nodes.unary.CastLogicalNodeGen;
-import com.oracle.truffle.r.nodes.unary.CastLogicalScalarNode;
 import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.nodes.unary.CastStringBaseNode;
 import com.oracle.truffle.r.nodes.unary.CastStringBaseNodeGen;
@@ -53,7 +52,6 @@ import com.oracle.truffle.r.nodes.unary.CastToAttributableNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNodeGen;
 import com.oracle.truffle.r.nodes.unary.ChainedCastNode;
 import com.oracle.truffle.r.nodes.unary.ConditionalMapNodeGen;
-import com.oracle.truffle.r.nodes.unary.ConvertIntNodeGen;
 import com.oracle.truffle.r.nodes.unary.FilterNodeGen;
 import com.oracle.truffle.r.nodes.unary.FindFirstNodeGen;
 import com.oracle.truffle.r.nodes.unary.FirstBooleanNodeGen;
@@ -162,10 +160,6 @@ public final class CastBuilder {
         return insert(index, FirstIntNode.createWithWarning(RError.Message.FIRST_ELEMENT_USED, name, intNa));
     }
 
-    public CastBuilder convertToInteger(int index) {
-        return insert(index, ConvertIntNodeGen.create());
-    }
-
     public CastBuilder firstIntegerWithError(int index, RError.Message error, String name) {
         insert(index, CastIntegerNodeGen.create(false, false, false));
         return insert(index, FirstIntNode.createWithError(error, name));
@@ -184,7 +178,8 @@ public final class CastBuilder {
     }
 
     public CastBuilder firstLogical(int index) {
-        return insert(index, CastLogicalScalarNode.create());
+        arg(index).asLogicalVector().findFirst(RRuntime.LOGICAL_NA);
+        return this;
     }
 
     public InitialPhaseBuilder<Object> arg(int argumentIndex, String argumentName) {
@@ -387,7 +382,7 @@ public final class CastBuilder {
 
         @Override
         public <T, R extends T> TypePredicateArgumentFilter<T, R> nullValue() {
-            return TypePredicateArgumentFilter.fromLambda(x -> x == RNull.instance || x == null);
+            return new TypePredicateArgumentFilter<>(x -> x == RNull.instance || x == null, true);
         }
 
         @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
index d0be229b8ae28d07c86c50eef7b72d1af1308919..01b3e47c819e48bb4e9cc597456c04ccdd18dbb9 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
@@ -246,18 +246,18 @@ public abstract class CallMatcherNode extends RBaseNode {
                 // Note: see CallMatcherNode#specialize for details on suppliedSignature/Arguments
 
                 // this unrolls all varargs instances in suppliedArgs into a flat array of arguments
-                RArgsValuesAndNames preparedArguments = prepareSuppliedArgument(preparePermutation, suppliedArguments, suppliedSignature);
+                Object[] preparedArguments = prepareSuppliedArgument(preparePermutation, suppliedArguments);
 
                 // This is then matched to formal signature: the result is non-flat array of
                 // arguments possibly containing varargs -- something that argument matching for a
                 // direct function call would create would this be a direct function call
-                RArgsValuesAndNames matchedArgs = ArgumentMatcher.matchArgumentsEvaluated(permutation, preparedArguments.getArguments(), null, formals);
+                RArgsValuesAndNames matchedArgs = ArgumentMatcher.matchArgumentsEvaluated(permutation, preparedArguments, null, formals);
                 Object[] reorderedArgs = matchedArgs.getArguments();
                 evaluatePromises(frame, cachedFunction, reorderedArgs, formals.getSignature().getVarArgIndex());
                 if (call != null) {
                     RCaller parent = RArguments.getCall(frame).getParent();
                     String genFunctionName = functionName == null ? function.getName() : functionName;
-                    Supplier<RSyntaxNode> argsSupplier = RCallerHelper.createFromArguments(genFunctionName, preparedArguments);
+                    Supplier<RSyntaxNode> argsSupplier = RCallerHelper.createFromArguments(genFunctionName, preparePermutation, suppliedArguments, suppliedSignature);
                     RCaller caller = genFunctionName == null ? RCaller.createInvalid(frame, parent) : RCaller.create(frame, parent, argsSupplier);
                     Object[] arguments = prepareArguments(reorderedArgs, matchedArgs.getSignature(), cachedFunction, dispatchArgs, caller);
                     return call.call(frame, arguments);
@@ -311,27 +311,24 @@ public abstract class CallMatcherNode extends RBaseNode {
         }
 
         @ExplodeLoop
-        private static RArgsValuesAndNames prepareSuppliedArgument(long[] preparePermutation, Object[] arguments, ArgumentsSignature suppliedSignature) {
+        private static Object[] prepareSuppliedArgument(long[] preparePermutation, Object[] arguments) {
             Object[] values = new Object[preparePermutation.length];
-            String[] names = new String[preparePermutation.length];
             for (int i = 0; i < values.length; i++) {
                 long source = preparePermutation[i];
-                if (!ArgumentsSignature.isVarArgsIndex(source)) {
-                    values[i] = arguments[(int) source];
-                    names[i] = suppliedSignature.getName((int) source);
-                } else {
+                if (ArgumentsSignature.isVarArgsIndex(source)) {
                     int varArgsIdx = ArgumentsSignature.extractVarArgsIndex(source);
                     int argsIdx = ArgumentsSignature.extractVarArgsArgumentIndex(source);
                     RArgsValuesAndNames varargs = (RArgsValuesAndNames) arguments[varArgsIdx];
                     values[i] = varargs.getArguments()[argsIdx];
-                    names[i] = varargs.getSignature().getName(argsIdx);
+                } else {
+                    values[i] = arguments[(int) source];
                 }
             }
-            return new RArgsValuesAndNames(values, ArgumentsSignature.get(names));
+            return values;
         }
     }
 
-    private static final class CallMatcherGenericNode extends CallMatcherNode {
+    public static final class CallMatcherGenericNode extends CallMatcherNode {
 
         CallMatcherGenericNode(boolean forNextMethod, boolean argsAreEvaluated) {
             super(forNextMethod, argsAreEvaluated);
@@ -339,12 +336,9 @@ public abstract class CallMatcherNode extends RBaseNode {
 
         @Child private IndirectCallNode call = Truffle.getRuntime().createIndirectCallNode();
 
-        private final ConditionProfile hasVarArgsProfile = ConditionProfile.createBinaryProfile();
-        private final ConditionProfile hasUnmatchedProfile = ConditionProfile.createBinaryProfile();
-
         @Override
         public Object execute(VirtualFrame frame, ArgumentsSignature suppliedSignature, Object[] suppliedArguments, RFunction function, String functionName, DispatchArgs dispatchArgs) {
-            RArgsValuesAndNames reorderedArgs = reorderArguments(suppliedArguments, function, suppliedSignature);
+            RArgsValuesAndNames reorderedArgs = reorderArguments(suppliedArguments, function, suppliedSignature, forNextMethod, this);
             evaluatePromises(frame, function, reorderedArgs.getArguments(), reorderedArgs.getSignature().getVarArgIndex());
 
             RCaller parent = RArguments.getCall(frame).getParent();
@@ -368,7 +362,7 @@ public abstract class CallMatcherNode extends RBaseNode {
         }
 
         @TruffleBoundary
-        protected RArgsValuesAndNames reorderArguments(Object[] args, RFunction function, ArgumentsSignature paramSignature) {
+        public static RArgsValuesAndNames reorderArguments(Object[] args, RFunction function, ArgumentsSignature paramSignature, boolean forNextMethod, RBaseNode callingNode) {
             assert paramSignature.getLength() == args.length;
 
             int argCount = args.length;
@@ -378,10 +372,10 @@ public abstract class CallMatcherNode extends RBaseNode {
             boolean hasUnmatched = false;
             for (int fi = 0; fi < argCount; fi++) {
                 Object arg = args[fi];
-                if (hasVarArgsProfile.profile(arg instanceof RArgsValuesAndNames)) {
+                if (arg instanceof RArgsValuesAndNames) {
                     hasVarArgs = true;
                     argListSize += ((RArgsValuesAndNames) arg).getLength() - 1;
-                } else if (hasUnmatchedProfile.profile(paramSignature.isUnmatched(fi))) {
+                } else if (paramSignature.isUnmatched(fi)) {
                     hasUnmatched = true;
                     argListSize--;
                 }
@@ -429,7 +423,7 @@ public abstract class CallMatcherNode extends RBaseNode {
             RArgsValuesAndNames evaledArgs = new RArgsValuesAndNames(argValues, signature);
 
             // ...to match them against the chosen function's formal arguments
-            RArgsValuesAndNames evaluated = ArgumentMatcher.matchArgumentsEvaluated((RRootNode) function.getRootNode(), evaledArgs, null, forNextMethod, this);
+            RArgsValuesAndNames evaluated = ArgumentMatcher.matchArgumentsEvaluated((RRootNode) function.getRootNode(), evaledArgs, null, forNextMethod, callingNode);
             return evaluated;
         }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
index a680de8e2b195b3c1980f4cb0be923b10fb9081d..a680b84ceb4391222b721c5e3898fec41614a7be 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
@@ -185,7 +185,8 @@ abstract class S4Class extends RBaseNode {
             // the assumption here is that the R function can only return either a String or
             // RStringVector
             s4Extends = (RStringVector) castToVector.execute(
-                            RContext.getEngine().evalFunction(sExtendsForS3Function, methodsEnv.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), classAttr));
+                            RContext.getEngine().evalFunction(sExtendsForS3Function, methodsEnv.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), null,
+                                            classAttr));
             RContext.getInstance().putS4Extends(classAttr, s4Extends);
         }
         return s4Extends;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java
index 13b9a157c77574f6ee21f603f8d72fa7281aebad..af7f0639df7fd2f1dc27484dbcd0017a644bce79 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java
@@ -51,7 +51,7 @@ public final class RCallerHelper {
      * S3/S4 dispatch), and that can then be used to retrieve correct syntax nodes.
      *
      * @param arguments array with arguments and corresponding names. This method strips any
-     *            {@code RMissing} arguments and unrolls all varargs withint arguments array.
+     *            {@code RMissing} arguments and unrolls all varargs within the arguments array.
      */
     public static Supplier<RSyntaxNode> createFromArguments(RFunction function, RArgsValuesAndNames arguments) {
         return createFromArgumentsInternal(function, arguments);
@@ -105,17 +105,50 @@ public final class RCallerHelper {
                 }
                 return syntaxNode;
             }
+        };
+    }
 
-            private RSyntaxNode getArgumentNode(Object arg) {
-                if (arg instanceof RPromise) {
-                    RPromise p = (RPromise) arg;
-                    return p.getRep().asRSyntaxNode();
-                } else if (!(arg instanceof RMissing)) {
-                    return ConstantNode.create(arg);
+    private static RSyntaxNode getArgumentNode(Object arg) {
+        if (arg instanceof RPromise) {
+            RPromise p = (RPromise) arg;
+            return p.getRep().asRSyntaxNode();
+        } else if (!(arg instanceof RMissing)) {
+            return ConstantNode.create(arg);
+        }
+        return null;
+    }
+
+    /**
+     * This method calculates the signature of the permuted arguments lazily.
+     */
+    public static Supplier<RSyntaxNode> createFromArguments(String function, long[] preparePermutation, Object[] suppliedArguments, ArgumentsSignature suppliedSignature) {
+        return new Supplier<RSyntaxNode>() {
+
+            RSyntaxNode syntaxNode = null;
+
+            @Override
+            public RSyntaxNode get() {
+                if (syntaxNode == null) {
+                    Object[] values = new Object[preparePermutation.length];
+                    String[] names = new String[preparePermutation.length];
+                    for (int i = 0; i < values.length; i++) {
+                        long source = preparePermutation[i];
+                        if (!ArgumentsSignature.isVarArgsIndex(source)) {
+                            values[i] = suppliedArguments[(int) source];
+                            names[i] = suppliedSignature.getName((int) source);
+                        } else {
+                            int varArgsIdx = ArgumentsSignature.extractVarArgsIndex(source);
+                            int argsIdx = ArgumentsSignature.extractVarArgsArgumentIndex(source);
+                            RArgsValuesAndNames varargs = (RArgsValuesAndNames) suppliedArguments[varArgsIdx];
+                            values[i] = varargs.getArguments()[argsIdx];
+                            names[i] = varargs.getSignature().getName(argsIdx);
+                        }
+                    }
+                    RArgsValuesAndNames arguments = new RArgsValuesAndNames(values, ArgumentsSignature.get(names));
+                    syntaxNode = createFromArguments(function, arguments).get();
                 }
-                return null;
+                return syntaxNode;
             }
-
         };
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java
index b54a2b7daf74a520f530cb33fb92f9dcf08e85e0..ea78fd31ab168ccb3dd5c1bde48c717af525b335 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.function;
 
 import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RS4Object;
@@ -38,6 +39,7 @@ public abstract class WrapArgumentBaseNode extends RNode {
 
     @Child protected RNode operand;
 
+    private final ValueProfile argumentValueProfile;
     private final BranchProfile everSeenVector;
     private final BranchProfile everSeenLanguage;
     private final BranchProfile everSeenFunction;
@@ -49,6 +51,7 @@ public abstract class WrapArgumentBaseNode extends RNode {
     protected WrapArgumentBaseNode(RNode operand, boolean initProfiles) {
         this.operand = operand;
         if (initProfiles) {
+            argumentValueProfile = ValueProfile.createClassProfile();
             everSeenVector = BranchProfile.create();
             everSeenLanguage = BranchProfile.create();
             everSeenFunction = BranchProfile.create();
@@ -56,6 +59,7 @@ public abstract class WrapArgumentBaseNode extends RNode {
             shareable = BranchProfile.create();
             nonShareable = BranchProfile.create();
         } else {
+            argumentValueProfile = null;
             everSeenVector = null;
             everSeenLanguage = null;
             everSeenFunction = null;
@@ -65,7 +69,8 @@ public abstract class WrapArgumentBaseNode extends RNode {
         }
     }
 
-    protected RShareable getShareable(Object result) {
+    protected RShareable getShareable(Object initialResult) {
+        Object result = argumentValueProfile.profile(initialResult);
         if (result instanceof RVector) {
             everSeenVector.enter();
             return (RVector) result;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
index 116526a385172cdcded48933ec097afb5218560d..8f9367277fe9c26aa4414ea4a1e78344cbfbfb60 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
@@ -74,7 +74,7 @@ public abstract class DispatchGeneric extends RBaseNode {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             REnvironment methodsEnv = REnvironment.getRegisteredNamespace("methods");
             RFunction currentFunction = ReadVariableNode.lookupFunction(".InheritForDispatch", methodsEnv.getFrame(), true);
-            method = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, RASTUtils.getOriginalCall(this)), classes, fdef, mtable);
+            method = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, RASTUtils.getOriginalCall(this)), null, classes, fdef, mtable);
         }
         method = loadMethod.executeRFunction(frame, method, fname);
         Object ret = executeMethod.executeObject(frame, method, fname);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
index d4cfc8497ec4751b17cc0654c1149a1a8b5194ca..72a4c84ab2dcfdc2f42b28b3d0a4a3ed09b55855 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
@@ -135,7 +135,7 @@ abstract class LoadMethod extends RBaseNode {
                 ret = (RFunction) loadMethodCall.call(frame, args);
             } else {
                 // slow path
-                ret = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), caller, fdef, fname, REnvironment.frameToEnvironment(frame.materialize()));
+                ret = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), caller, null, fdef, fname, REnvironment.frameToEnvironment(frame.materialize()));
             }
 
         } else {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
index bc94284a06417fc4261627bda80c3edcacce48f8..9f8baf3851fb8e0f2ea5d8c9ec82a81c04e5bc9c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
@@ -12,15 +12,14 @@
  */
 package com.oracle.truffle.r.nodes.objects;
 
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.access.AccessSlotNode;
 import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.attributes.AttributeAccess;
 import com.oracle.truffle.r.nodes.attributes.AttributeAccessNodeGen;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
-import com.oracle.truffle.r.nodes.unary.CastLogicalScalarNode;
-import com.oracle.truffle.r.nodes.unary.CastStringScalarNode;
+import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.nodes.unary.DuplicateNode;
 import com.oracle.truffle.r.nodes.unary.DuplicateNodeGen;
 import com.oracle.truffle.r.runtime.RError;
@@ -36,22 +35,26 @@ public abstract class NewObject extends RExternalBuiltinNode.Arg1 {
     @Child private AccessSlotNode accessSlotVirtual = AccessSlotNodeGen.create(true, null, null);
     @Child private AccessSlotNode accessSlotClassName = AccessSlotNodeGen.create(true, null, null);
     @Child private AccessSlotNode accessSlotPrototypeName = AccessSlotNodeGen.create(true, null, null);
-    @Child private CastStringScalarNode castStringScalar;
-    @Child private CastLogicalScalarNode castLogicalScalar = CastLogicalScalarNode.create();
     @Child private DuplicateNode duplicate = DuplicateNodeGen.create(true);
     @Child private AttributeAccess pckgAttrAccess = AttributeAccessNodeGen.create(RRuntime.PCKG_ATTR_KEY);
 
+    @Child private CastNode castStringScalar;
+    @Child private CastNode castLogicalScalar;
+    {
+        CastBuilder builder = new CastBuilder();
+        builder.arg(0).asStringVector().findFirst(RRuntime.STRING_NA);
+        builder.arg(1).asLogicalVector().findFirst(RRuntime.LOGICAL_NA);
+        castStringScalar = builder.getCasts()[0];
+        castLogicalScalar = builder.getCasts()[1];
+    }
+
     @Specialization(guards = "!isNull(classDef)")
     protected Object doNewObject(Object classDef) {
 
         Object e = accessSlotVirtual.executeAccess(classDef, RRuntime.S_VIRTUAL);
-        if (castLogicalScalar.executeByte(e) != RRuntime.LOGICAL_FALSE) {
-            if (castStringScalar == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                castStringScalar = insert(CastStringScalarNode.create());
-            }
+        if (((byte) castLogicalScalar.execute(e)) != RRuntime.LOGICAL_FALSE) {
             e = accessSlotClassName.executeAccess(classDef, RRuntime.S_CLASSNAME);
-            throw RError.error(this, RError.Message.OBJECT_FROM_VIRTUAL, castStringScalar.executeString(e));
+            throw RError.error(this, RError.Message.OBJECT_FROM_VIRTUAL, castStringScalar.execute(e));
         }
         e = accessSlotClassName.executeAccess(classDef, RRuntime.S_CLASSNAME);
         Object prototype = accessSlotPrototypeName.executeAccess(classDef, RRuntime.S_PROTOTYPE);
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 4590f6475ff18b5620d80e531d2701f094114497..9f401aa09158f569c14c17be0220dbd234d13d1e 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
@@ -22,19 +22,24 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.dsl.NodeField;
-import com.oracle.truffle.api.dsl.NodeFields;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+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.r.runtime.NullProfile;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.env.REnvironment;
 
-@NodeFields({@NodeField(name = "preserveNames", type = boolean.class), @NodeField(name = "dimensionsPreservation", type = boolean.class), @NodeField(name = "attrPreservation", type = boolean.class)})
 public abstract class CastBaseNode extends CastNode {
 
     private final BranchProfile listCoercionErrorBranch = BranchProfile.create();
@@ -43,11 +48,29 @@ public abstract class CastBaseNode extends CastNode {
     private final NullProfile hasNamesProfile = NullProfile.create();
     private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
 
-    protected abstract boolean isPreserveNames();
+    private final boolean preserveNames;
+    private final boolean preserveDimensions;
+    private final boolean preserveAttributes;
 
-    protected abstract boolean isDimensionsPreservation();
+    protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        this.preserveNames = preserveNames;
+        this.preserveDimensions = preserveDimensions;
+        this.preserveAttributes = preserveAttributes;
+    }
+
+    public boolean preserveNames() {
+        return preserveNames;
+    }
 
-    protected abstract boolean isAttrPreservation();
+    public boolean preserveDimensions() {
+        return preserveDimensions;
+    }
+
+    public boolean preserveAttributes() {
+        return preserveAttributes;
+    }
+
+    protected abstract RType getTargetType();
 
     protected RError throwCannotCoerceListError(String type) {
         listCoercionErrorBranch.enter();
@@ -55,7 +78,7 @@ public abstract class CastBaseNode extends CastNode {
     }
 
     protected int[] getPreservedDimensions(RAbstractContainer operand) {
-        if (isDimensionsPreservation()) {
+        if (preserveDimensions()) {
             return hasDimensionsProfile.profile(operand.getDimensions());
         } else {
             return null;
@@ -63,7 +86,7 @@ public abstract class CastBaseNode extends CastNode {
     }
 
     protected RStringVector getPreservedNames(RAbstractContainer operand) {
-        if (isPreserveNames()) {
+        if (preserveNames()) {
             return hasNamesProfile.profile(operand.getNames(attrProfiles));
         } else {
             return null;
@@ -71,11 +94,26 @@ public abstract class CastBaseNode extends CastNode {
     }
 
     protected void preserveDimensionNames(RAbstractContainer operand, RVector ret) {
-        if (isDimensionsPreservation()) {
+        if (preserveDimensions()) {
             RList dimNames = operand.getDimNames(attrProfiles);
             if (hasDimNamesProfile.profile(dimNames != null)) {
                 ret.setDimNames((RList) dimNames.copy());
             }
         }
     }
+
+    @Fallback
+    @TruffleBoundary
+    protected Object doOther(Object value) {
+        Object mappedValue = RRuntime.asAbstractVector(value);
+        if (mappedValue instanceof REnvironment) {
+            throw RError.error(RError.SHOW_CALLER, RError.Message.ENVIRONMENTS_COERCE);
+        } else if (mappedValue instanceof RTypedValue) {
+            throw RError.error(RError.SHOW_CALLER, RError.Message.CANNOT_COERCE, ((RTypedValue) mappedValue).getRType().getName(), getTargetType().getName());
+        } else if (mappedValue instanceof TruffleObject) {
+            throw RError.error(RError.SHOW_CALLER, RError.Message.CANNOT_COERCE, "truffleobject", getTargetType().getName());
+        } else {
+            throw RInternalError.shouldNotReachHere("unexpected value of type " + (mappedValue == null ? "null" : mappedValue.getClass()));
+        }
+    }
 }
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 b781b66977c8d4a3fb2fb183bcbe63fd51cd6723..2e6fae29105ba85c5233d5ed27c7ec804b8173a1 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
@@ -24,14 +24,13 @@ package com.oracle.truffle.r.nodes.unary;
 
 import java.util.function.IntFunction;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.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.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;
@@ -60,6 +59,15 @@ public abstract class CastComplexNode extends CastBaseNode {
 
     public abstract Object executeComplex(Object o);
 
+    protected CastComplexNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
+    @Override
+    protected final RType getTargetType() {
+        return RType.Complex;
+    }
+
     @Specialization
     protected RNull doNull(@SuppressWarnings("unused") RNull operand) {
         return RNull.instance;
@@ -121,7 +129,7 @@ public abstract class CastComplexNode extends CastBaseNode {
         }
         RComplexVector ret = RDataFactory.createComplexVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -174,7 +182,7 @@ public abstract class CastComplexNode extends CastBaseNode {
         }
         RComplexVector ret = RDataFactory.createComplexVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -190,12 +198,6 @@ public abstract class CastComplexNode extends CastBaseNode {
         return createResultVector(operand, index -> RDataFactory.createComplex(operand.getDataAt(index).getValue(), 0));
     }
 
-    @Fallback
-    @TruffleBoundary
-    protected int doOther(Object operand) {
-        throw new ConversionFailedException(operand.getClass().getName());
-    }
-
     public static CastComplexNode create() {
         return CastComplexNodeGen.create(true, true, true);
     }
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 159da03c48d96ea984e285b89d44b3ce3a7ed9ea..c4377e38e2f9e050931b613a7f2e815cb8fb1bac 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
@@ -22,14 +22,13 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 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.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
@@ -38,9 +37,18 @@ import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
 public abstract class CastDoubleBaseNode extends CastBaseNode {
 
-    private final NACheck naCheck = NACheck.create();
-    private final NAProfile naProfile = NAProfile.create();
-    private final BranchProfile warningBranch = BranchProfile.create();
+    protected final NACheck naCheck = NACheck.create();
+    protected final NAProfile naProfile = NAProfile.create();
+    protected final BranchProfile warningBranch = BranchProfile.create();
+
+    protected CastDoubleBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
+    @Override
+    protected final RType getTargetType() {
+        return RType.Double;
+    }
 
     public abstract Object executeDouble(int o);
 
@@ -101,11 +109,4 @@ public abstract class CastDoubleBaseNode extends CastBaseNode {
     protected double doRaw(RRaw operand) {
         return RRuntime.raw2double(operand);
     }
-
-    @Fallback
-    @TruffleBoundary
-    protected double doOther(Object operand) {
-        throw new ConversionFailedException(operand.getClass().getName());
-    }
-
 }
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 ae8e7d86ba191c6f14f165743912026249fd0e6a..47459c84f748ba2d2c43a1eaeb17820d77e69ecb 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
@@ -27,7 +27,6 @@ import java.util.function.IntToDoubleFunction;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -42,21 +41,19 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.ops.na.NACheck;
-import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
 public abstract class CastDoubleNode extends CastDoubleBaseNode {
 
-    private final NACheck naCheck = NACheck.create();
-    private final NAProfile naProfile = NAProfile.create();
-    private final BranchProfile warningBranch = BranchProfile.create();
+    protected CastDoubleNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
 
     @Child private CastDoubleNode recursiveCastDouble;
 
     private Object castDoubleRecursive(Object o) {
         if (recursiveCastDouble == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastDouble = insert(CastDoubleNodeGen.create(isPreserveNames(), isDimensionsPreservation(), isAttrPreservation()));
+            recursiveCastDouble = insert(CastDoubleNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
         }
         return recursiveCastDouble.executeDouble(o);
     }
@@ -64,7 +61,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
     private RDoubleVector createResultVector(RAbstractVector operand, double[] ddata) {
         RDoubleVector ret = RDataFactory.createDoubleVector(ddata, naCheck.neverSeenNA(), getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -81,7 +78,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
         }
         RDoubleVector ret = RDataFactory.createDoubleVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -127,7 +124,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
         }
         RDoubleVector ret = RDataFactory.createDoubleVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -201,7 +198,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
             }
         }
         RDoubleVector ret = RDataFactory.createDoubleVector(result, !seenNA);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(list);
         }
         return ret;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
index cd73b7847f815970da3903c065779659dc8c2e8f..10e7fe8bfe7acb9b5388f997afb9859a29b56e53 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.nodes.unary;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RExpression;
@@ -39,6 +40,15 @@ public abstract class CastExpressionNode extends CastBaseNode {
 
     public abstract Object executeExpression(Object o);
 
+    protected CastExpressionNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
+    @Override
+    protected final RType getTargetType() {
+        return RType.Expression;
+    }
+
     @Specialization
     protected RExpression doNull(@SuppressWarnings("unused") RNull value) {
         return create(RNull.instance);
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 9445804d02df77dbe1d82a72a041bd8228b8b446..5e3b5b5aa16d0650fcd6cd5a22389a84cb0d50e3 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
@@ -29,12 +29,11 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 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.RFunction;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
-import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public abstract class CastIntegerBaseNode extends CastBaseNode {
@@ -44,10 +43,19 @@ public abstract class CastIntegerBaseNode extends CastBaseNode {
 
     @Child private CastIntegerNode recursiveCastInteger;
 
+    protected CastIntegerBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
+    @Override
+    protected final RType getTargetType() {
+        return RType.Integer;
+    }
+
     protected Object castIntegerRecursive(Object o) {
         if (recursiveCastInteger == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastInteger = insert(CastIntegerNodeGen.create(isPreserveNames(), isDimensionsPreservation(), isAttrPreservation()));
+            recursiveCastInteger = insert(CastIntegerNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
         }
         return recursiveCastInteger.executeInt(o);
     }
@@ -109,14 +117,4 @@ public abstract class CastIntegerBaseNode extends CastBaseNode {
     protected int doRaw(RRaw operand) {
         return RRuntime.raw2int(operand);
     }
-
-    @Specialization
-    protected Object doEnvironment(@SuppressWarnings("unused") REnvironment value) {
-        throw RError.error(RError.SHOW_CALLER, RError.Message.ENVIRONMENTS_COERCE);
-    }
-
-    @Specialization
-    protected Object doFunction(@SuppressWarnings("unused") RFunction value) {
-        throw RError.error(RError.SHOW_CALLER, RError.Message.CLOSURE_COERCE);
-    }
 }
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 f9b782dc101aee43469ef62cc1a73e0acd8a81d0..60d21ca021724d29ff2cf57c4277b96bf3088208 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
@@ -22,9 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RError;
@@ -50,6 +48,10 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
 
     private final NAProfile naProfile = NAProfile.create();
 
+    protected CastIntegerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
     public abstract Object executeInt(int o);
 
     public abstract Object executeInt(double o);
@@ -58,8 +60,6 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
 
     public abstract Object executeInt(Object o);
 
-    @Child private CastIntegerNode recursiveCastInteger;
-
     @Specialization
     protected RAbstractIntVector doIntVector(RAbstractIntVector operand) {
         return operand;
@@ -74,7 +74,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
     private RIntVector createResultVector(RAbstractVector operand, int[] idata) {
         RIntVector ret = RDataFactory.createIntVector(idata, naCheck.neverSeenNA(), getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -96,7 +96,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
         }
         RIntVector ret = RDataFactory.createIntVector(idata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -152,7 +152,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
         }
         RIntVector ret = RDataFactory.createIntVector(idata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -190,8 +190,8 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
                     int value = (Integer) castEntry;
                     result[i] = value;
                     seenNA = seenNA || RRuntime.isNA(value);
-                } else if (castEntry instanceof RIntVector) {
-                    RIntVector intVector = (RIntVector) castEntry;
+                } else if (castEntry instanceof RAbstractIntVector) {
+                    RAbstractIntVector intVector = (RAbstractIntVector) castEntry;
                     if (intVector.getLength() == 1) {
                         int value = intVector.getDataAt(0);
                         result[i] = value;
@@ -208,7 +208,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
             }
         }
         RIntVector ret = RDataFactory.createIntVector(result, !seenNA);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(list);
         }
         return ret;
@@ -224,12 +224,6 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
         return arg instanceof RIntVector;
     }
 
-    @Fallback
-    @TruffleBoundary
-    protected int doOther(Object operand) {
-        throw new ConversionFailedException(operand.getClass().getName());
-    }
-
     public static CastIntegerNode create() {
         return CastIntegerNodeGen.create(true, true, true);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerScalarNode.java
deleted file mode 100644
index dc7525c99bc4d225c1f6ab9deabafedb7dbb07ea..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerScalarNode.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.unary;
-
-import com.oracle.truffle.api.dsl.Fallback;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
-import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-
-public abstract class CastIntegerScalarNode extends CastIntegerBaseNode {
-
-    public abstract int executeInt(Object o);
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected int doLogicalVector(RLogicalVector operand) {
-        return (int) castIntegerRecursive(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected int doIntVector(RAbstractIntVector operand) {
-        return (int) castIntegerRecursive(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected int doDoubleVector(RAbstractDoubleVector operand) {
-        return (int) castIntegerRecursive(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected int doStringVector(RStringVector operand) {
-        return (int) castIntegerRecursive(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected int doComplexVector(RComplexVector operand) {
-        return (int) castIntegerRecursive(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected int doRawVectorDims(RRawVector operand) {
-        return (int) castIntegerRecursive(operand.getDataAt(0));
-    }
-
-    @Fallback
-    protected int castInt(@SuppressWarnings("unused") Object o) {
-        // for non-atomic structures and vectors of length 0
-        return RRuntime.INT_NA;
-    }
-
-    public static CastIntegerScalarNode create() {
-        return CastIntegerScalarNodeGen.create(false, false, false);
-    }
-}
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 ba4330cc0849dc3ad0093651103740e1cb806bd5..8a67bbad26382d5854dc1d232ea40b558f2bbd9f 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
@@ -27,6 +27,7 @@ import java.util.Iterator;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributes;
 import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute;
@@ -45,10 +46,17 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 
 public abstract class CastListNode extends CastBaseNode {
 
-    @Child private CastListNode castListRecursive;
-
     public abstract RList executeList(Object o);
 
+    protected CastListNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
+    @Override
+    protected final RType getTargetType() {
+        return RType.List;
+    }
+
     @Specialization
     protected RList doNull(@SuppressWarnings("unused") RNull operand) {
         return RDataFactory.createList();
@@ -72,7 +80,7 @@ public abstract class CastListNode extends CastBaseNode {
         }
         RList ret = RDataFactory.createList(data, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java
index 1de63001a8fab2521cd1070037313452976d13c2..03ea9e3eb653978486ba62171af92fc0b7b962b2 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java
@@ -22,9 +22,9 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 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.RRaw;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
@@ -33,14 +33,13 @@ public abstract class CastLogicalBaseNode extends CastBaseNode {
 
     protected final NACheck naCheck = NACheck.create();
 
-    @Child private CastLogicalNode recursiveCastLogical;
+    protected CastLogicalBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
 
-    protected Object castLogicalRecursive(Object o) {
-        if (recursiveCastLogical == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastLogical = insert(CastLogicalNodeGen.create(isPreserveNames(), isDimensionsPreservation(), isAttrPreservation()));
-        }
-        return recursiveCastLogical.execute(o);
+    @Override
+    protected final RType getTargetType() {
+        return RType.Logical;
     }
 
     @Specialization
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 90fc83be7044eb76e719e4fee206e137914ec1d5..b7eac7f903810077889f3957e746be082c3a64c6 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
@@ -24,8 +24,7 @@ package com.oracle.truffle.r.nodes.unary;
 
 import java.util.Arrays;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -47,6 +46,29 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
 
     private final NAProfile naProfile = NAProfile.create();
 
+    @Child private CastLogicalNode recursiveCastLogical;
+    @Child private InheritsCheckNode inheritsFactorCheck;
+
+    protected CastLogicalNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
+    protected Object castLogicalRecursive(Object o) {
+        if (recursiveCastLogical == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursiveCastLogical = insert(CastLogicalNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
+        }
+        return recursiveCastLogical.execute(o);
+    }
+
+    protected boolean isFactor(Object o) {
+        if (inheritsFactorCheck == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            inheritsFactorCheck = insert(new InheritsCheckNode(RRuntime.CLASS_FACTOR));
+        }
+        return inheritsFactorCheck.execute(o);
+    }
+
     @Specialization
     protected RNull doNull(@SuppressWarnings("unused") RNull operand) {
         return RNull.instance;
@@ -68,7 +90,7 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
         }
         RLogicalVector ret = RDataFactory.createLogicalVector(bdata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -84,6 +106,13 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
         return createResultVector(operand, index -> naCheck.convertIntToLogical(operand.getDataAt(index)));
     }
 
+    @Specialization(guards = "isFactor(factor)")
+    protected RLogicalVector asLogical(RAbstractIntVector factor) {
+        byte[] data = new byte[factor.getLength()];
+        Arrays.fill(data, RRuntime.LOGICAL_NA);
+        return RDataFactory.createLogicalVector(data, RDataFactory.INCOMPLETE_VECTOR);
+    }
+
     @Specialization
     protected RLogicalVector doDoubleVector(RAbstractDoubleVector operand) {
         return createResultVector(operand, index -> naCheck.convertDoubleToLogical(operand.getDataAt(index)));
@@ -138,7 +167,7 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
             }
         }
         RLogicalVector ret = RDataFactory.createLogicalVector(result, !seenNA);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(list);
         }
         return ret;
@@ -154,26 +183,7 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
         return missing;
     }
 
-    @Specialization(guards = "isFactor(factor)")
-    protected RLogicalVector asLogical(RAbstractIntVector factor) {
-        byte[] data = new byte[factor.getLength()];
-        Arrays.fill(data, RRuntime.LOGICAL_NA);
-        return RDataFactory.createLogicalVector(data, RDataFactory.INCOMPLETE_VECTOR);
-    }
-
-    @Fallback
-    @TruffleBoundary
-    protected int doOther(Object operand) {
-        throw new ConversionFailedException(operand.getClass().getName());
-    }
-
     public static CastLogicalNode createNonPreserving() {
         return CastLogicalNodeGen.create(false, false, false);
     }
-
-    @Child private InheritsCheckNode inheritsFactorCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR);
-
-    protected boolean isFactor(Object o) {
-        return inheritsFactorCheck.execute(o);
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalScalarNode.java
deleted file mode 100644
index 71513232170913e47071ab77b61cb01e99424db4..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalScalarNode.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.unary;
-
-import com.oracle.truffle.api.dsl.Fallback;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
-import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-
-public abstract class CastLogicalScalarNode extends CastLogicalBaseNode {
-
-    public abstract byte executeByte(Object o);
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected byte doLogicalVector(RLogicalVector operand) {
-        return (byte) castLogicalRecursive(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected byte doIntVector(RAbstractIntVector operand) {
-        return (byte) castLogicalRecursive(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected byte doDoubleVector(RAbstractDoubleVector operand) {
-        return (byte) castLogicalRecursive(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected byte doStringVector(RStringVector operand) {
-        return (byte) castLogicalRecursive(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected byte doComplexVector(RComplexVector operand) {
-        return (byte) castLogicalRecursive(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected byte doRawVectorDims(RRawVector operand) {
-        return (byte) castLogicalRecursive(operand.getDataAt(0));
-    }
-
-    @Fallback
-    protected byte castLogical(@SuppressWarnings("unused") Object o) {
-        // for non-atomic structures and vectors of length 0
-        return RRuntime.LOGICAL_NA;
-    }
-
-    public static CastLogicalScalarNode create() {
-        return CastLogicalScalarNodeGen.create(false, false, false);
-    }
-}
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 120d4232b83f602a30aea46bc8f485cffd7893f6..c4216503fa42031bb450494e4ca88ffeb4c3fad3 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
@@ -22,14 +22,13 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 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;
@@ -49,6 +48,15 @@ public abstract class CastRawNode extends CastBaseNode {
     private final NACheck naCheck = NACheck.create();
     private final BranchProfile warningBranch = BranchProfile.create();
 
+    protected CastRawNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
+    @Override
+    protected final RType getTargetType() {
+        return RType.Raw;
+    }
+
     public abstract Object executeRaw(int o);
 
     public abstract Object executeRaw(double o);
@@ -130,7 +138,7 @@ public abstract class CastRawNode extends CastBaseNode {
     private RRawVector createResultVector(RAbstractVector operand, byte[] bdata) {
         RRawVector ret = RDataFactory.createRawVector(bdata, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
@@ -271,12 +279,6 @@ public abstract class CastRawNode extends CastBaseNode {
         return operand;
     }
 
-    @Fallback
-    @TruffleBoundary
-    protected int doOther(Object operand) {
-        throw new ConversionFailedException(operand.getClass().getName());
-    }
-
     public static CastRawNode createNonPreserving() {
         return CastRawNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java
index 290505762224c50a33ae3632f8a3bec7132e8d2e..9c2b21f546c2cebbf1f14bdb329233844cea2a06 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.unary;
 
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RRaw;
 
@@ -30,6 +31,15 @@ public abstract class CastStringBaseNode extends CastBaseNode {
 
     @Child private ToStringNode toString = ToStringNodeGen.create();
 
+    protected CastStringBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
+    @Override
+    protected final RType getTargetType() {
+        return RType.Character;
+    }
+
     @Specialization
     protected String doString(String value) {
         return value;
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 2ad538134cc4987e3f8cc813c10750804f6b2270..9a258c8124fc2ca1f264a0f054dc899b0c89acb0 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
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.dsl.NodeField;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -33,9 +32,19 @@ import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
-@NodeField(name = "emptyVectorConvertedToNull", type = boolean.class)
 public abstract class CastStringNode extends CastStringBaseNode {
 
+    private final boolean convertEmptyVectorToNull;
+
+    protected CastStringNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean convertEmptyVectorToNull) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+        this.convertEmptyVectorToNull = convertEmptyVectorToNull;
+    }
+
+    public boolean convertEmptyVectorToNull() {
+        return convertEmptyVectorToNull;
+    }
+
     public abstract Object executeString(int o);
 
     public abstract Object executeString(double o);
@@ -44,8 +53,6 @@ public abstract class CastStringNode extends CastStringBaseNode {
 
     public abstract Object executeString(Object o);
 
-    public abstract boolean isEmptyVectorConvertedToNull();
-
     @Specialization
     protected RNull doNull(@SuppressWarnings("unused") RNull operand) {
         return RNull.instance;
@@ -53,7 +60,7 @@ public abstract class CastStringNode extends CastStringBaseNode {
 
     @Specialization(guards = "vector.getLength() == 0")
     protected Object doEmptyVector(@SuppressWarnings("unused") RAbstractVector vector) {
-        return isEmptyVectorConvertedToNull() ? RNull.instance : RDataFactory.createStringVector(0);
+        return convertEmptyVectorToNull ? RNull.instance : RDataFactory.createStringVector(0);
     }
 
     @Specialization(guards = "vector.getLength() != 0")
@@ -75,7 +82,7 @@ public abstract class CastStringNode extends CastStringBaseNode {
         }
         RStringVector ret = RDataFactory.createStringVector(sdata, operand.isComplete(), getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
-        if (isAttrPreservation()) {
+        if (preserveAttributes()) {
             ret.copyRegAttributesFrom(operand);
         }
         return ret;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringScalarNode.java
deleted file mode 100644
index 7a5f961d4fc921bbc5d9c065ab8ae0033650dd5a..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringScalarNode.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.unary;
-
-import com.oracle.truffle.api.dsl.Fallback;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
-import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-
-public abstract class CastStringScalarNode extends CastStringBaseNode {
-
-    public abstract String executeString(Object o);
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected String doLogicalVector(RLogicalVector operand) {
-        return toString(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected String doIntVector(RAbstractIntVector operand) {
-        return toString(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected String doDoubleVector(RAbstractDoubleVector operand) {
-        return toString(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected String doStringVector(RStringVector operand) {
-        return toString(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected String doComplexVector(RComplexVector operand) {
-        return toString(operand.getDataAt(0));
-    }
-
-    @Specialization(guards = "operand.getLength() > 0")
-    protected String doRawVectorDims(RRawVector operand) {
-        return toString(operand.getDataAt(0));
-    }
-
-    @Fallback
-    protected String castLogical(@SuppressWarnings("unused") Object o) {
-        // for non-atomic structures, vectors of length 0, and NULL
-        return RRuntime.STRING_NA;
-    }
-
-    public static CastStringScalarNode create() {
-        return CastStringScalarNodeGen.create(false, false, false);
-    }
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
index cfd853bfe0b4af5e6e92c4bdf56edb34b6204928..c567944d82dd273656521a82d5dbe8af7d79426c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
@@ -25,6 +25,7 @@ package com.oracle.truffle.r.nodes.unary;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RIntVector;
@@ -37,6 +38,15 @@ public abstract class CastSymbolNode extends CastBaseNode {
 
     @Child private ToStringNode toString = ToStringNodeGen.create();
 
+    protected CastSymbolNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
+    @Override
+    protected final RType getTargetType() {
+        return RType.Symbol;
+    }
+
     public abstract Object executeSymbol(Object o);
 
     private String toString(Object value) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java
index 89199ea9571e54514ddce53b7972f094ccc74b8d..769ee3d5558aa4b64476b6a7476e3e90c4c7d0a5 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.unary;
 
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -35,6 +36,15 @@ public abstract class CastToAttributableNode extends CastBaseNode {
 
     public abstract Object executeObject(Object value);
 
+    protected CastToAttributableNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
+    @Override
+    protected final RType getTargetType() {
+        return RType.Any;
+    }
+
     @Specialization
     @SuppressWarnings("unused")
     protected RNull cast(RNull rnull) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java
index 607e59d5c87ebb86ee7d06e551286a4647599100..7bd1fd595cbb70500660a57c559305252bb520e1 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.unary;
 
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
@@ -35,6 +36,15 @@ public abstract class CastToContainerNode extends CastBaseNode {
 
     public abstract Object executeObject(Object value);
 
+    protected CastToContainerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        super(preserveNames, preserveDimensions, preserveAttributes);
+    }
+
+    @Override
+    protected final RType getTargetType() {
+        return RType.Any;
+    }
+
     @Specialization
     @SuppressWarnings("unused")
     protected RNull castNull(RNull rnull) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConversionFailedException.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConversionFailedException.java
deleted file mode 100644
index 364e2787010541ac8bf8e6da672bcae02a7c5919..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConversionFailedException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.unary;
-
-/** Thrown by a convert node. Indicates that a parent node must rewrite itself. */
-public final class ConversionFailedException extends RuntimeException {
-
-    private static final long serialVersionUID = 1L;
-
-    ConversionFailedException(String message) {
-        super(message);
-    }
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertInt.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertInt.java
deleted file mode 100644
index dbfb7f96d877a673ba19d553cf4776e7e531c4b2..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertInt.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.unary;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.dsl.Fallback;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
-
-public abstract class ConvertInt extends CastNode {
-
-    @Child private ConvertInt convertIntRecursive;
-
-    public abstract int executeInteger(Object operand);
-
-    private int convertIntRecursive(Object operand) {
-        if (convertIntRecursive == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            convertIntRecursive = insert(ConvertIntNodeGen.create());
-        }
-        return executeInteger(operand);
-    }
-
-    @Specialization
-    protected int doInt(int operand) {
-        return operand;
-    }
-
-    @Specialization
-    protected int doDouble(double operand) {
-        return (int) operand;
-    }
-
-    @Specialization
-    protected int doLogical(byte operand) {
-        return RRuntime.logical2int(operand);
-    }
-
-    @Specialization(guards = "operand.getLength() == 1")
-    protected int doLogical(RAbstractContainer operand) {
-        return convertIntRecursive(operand.getDataAtAsObject(0));
-    }
-
-    @Fallback
-    @TruffleBoundary
-    protected int doOther(Object operand) {
-        throw new ConversionFailedException(operand.getClass().getName());
-    }
-}
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java
index de33418f4c6c31fd5e0d0a6c671d783a7b3ebb6c..731cbc5ac2557d606af6fd9b8002b45447355926 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java
@@ -279,7 +279,7 @@ public class CallRFFIHelper {
 
     public static Object R_do_MAKE_CLASS(String clazz) {
         RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(REnvironment.getRegisteredNamespace("methods").get("getClass"));
-        return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), clazz);
+        return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), null, clazz);
     }
 
     public static Object Rf_findVar(Object symbolArg, Object envArg) {
@@ -894,31 +894,6 @@ public class CallRFFIHelper {
         return result;
     }
 
-    private static Object convertPairList(RPairList list) {
-        try {
-            if (list.getType() == SEXPTYPE.LANGSXP) {
-                RPairList pl = list;
-                Map<String, Object> constants = new HashMap<>();
-                String deparse = RDeparse.deparseDeserialize(constants, pl);
-                Source source = RSource.fromTextInternal(deparse, RSource.Internal.PAIRLIST_DEPARSE);
-                RExpression expr = RContext.getEngine().parse(constants, source);
-                assert expr.getLength() == 1;
-                Object result = expr.getDataAt(0);
-                RAttributes attrs = pl.getAttributes();
-                if (result instanceof RAttributable) {
-                    RAttributes.copyAttributes((RAttributable) result, attrs);
-                }
-                return result;
-
-            } else {
-                throw RInternalError.shouldNotReachHere();
-            }
-        } catch (Throwable x) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
-    }
-
     @TruffleBoundary
     public static Object Rf_eval(Object expr, Object env) {
         if (RFFIUtils.traceEnabled()) {
@@ -929,11 +904,20 @@ public class CallRFFIHelper {
         if (expr instanceof RPromise) {
             result = RContext.getRRuntimeASTAccess().forcePromise(expr);
         } else if (expr instanceof RExpression) {
-            result = RContext.getEngine().eval((RExpression) expr, (REnvironment) env, RCaller.createInvalid(null));
+            result = RContext.getEngine().eval((RExpression) expr, (REnvironment) env, topLevel);
         } else if (expr instanceof RLanguage) {
-            result = RContext.getEngine().eval((RLanguage) expr, (REnvironment) env, RCaller.createInvalid(null));
+            result = RContext.getEngine().eval((RLanguage) expr, (REnvironment) env, topLevel);
         } else if (expr instanceof RPairList) {
-            result = Rf_eval(convertPairList((RPairList) expr), env);
+            RPairList l = (RPairList) expr;
+            RFunction f = (RFunction) l.car();
+            Object args = l.cdr();
+            if (args == RNull.instance) {
+                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), topLevel, null, new Object[0]);
+            } else {
+                RList argsList = ((RPairList) args).toRList();
+                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), topLevel, argsList.getNames(), argsList.getDataNonShared());
+            }
+
         } else {
             // just return value
             result = expr;
@@ -1008,7 +992,7 @@ public class CallRFFIHelper {
             RFFIUtils.traceUpCall("R_computeIdentical", x, y, flags);
         }
         RFunction indenticalBuiltin = RContext.lookupBuiltin("identical");
-        Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))),
+        Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))),
                         RRuntime.asLogical((!((flags & 2) == 0))), RRuntime.asLogical((!((flags & 4) == 0))), RRuntime.asLogical((!((flags & 8) == 0))), RRuntime.asLogical((!((flags & 16) == 0))));
         return (int) res;
     }
@@ -1276,12 +1260,12 @@ public class CallRFFIHelper {
         }
         RCaller currentCaller = RArguments.getCall(frame);
         while (currentCaller != null) {
-            if (!currentCaller.isPromise()) {
+            if (!currentCaller.isPromise() && currentCaller.isValidCaller()) {
                 break;
             }
             currentCaller = currentCaller.getParent();
         }
-        return currentCaller == null ? RNull.instance : currentCaller;
+        return currentCaller == null || currentCaller == topLevel ? RNull.instance : currentCaller;
     }
 
     public static Object R_getParentFunctionContext(Object c) {
@@ -1291,30 +1275,11 @@ public class CallRFFIHelper {
         RCaller currentCaller = guaranteeInstanceOf(c, RCaller.class);
         while (true) {
             currentCaller = currentCaller.getParent();
-            if (currentCaller == null || !currentCaller.isPromise()) {
+            if (currentCaller == null || (!currentCaller.isPromise() && currentCaller.isValidCaller())) {
                 break;
             }
         }
-        return currentCaller == null ? RNull.instance : currentCaller;
-    }
-
-    public static Object R_getFunctionContext(int depth) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getFunctionContext", depth);
-        }
-        Frame frame = Utils.getActualCurrentFrame();
-        RCaller currentCaller = RArguments.getCall(frame);
-        int currentDepth = 0;
-        while (currentCaller != null) {
-            if (!currentCaller.isPromise()) {
-                currentDepth++;
-                if (currentDepth >= depth) {
-                    break;
-                }
-            }
-            currentCaller = currentCaller.getParent();
-        }
-        return currentCaller == null ? RNull.instance : currentCaller;
+        return currentCaller == null || currentCaller == topLevel ? RNull.instance : currentCaller;
     }
 
     public static Object R_getContextEnv(Object c) {
@@ -1419,7 +1384,6 @@ public class CallRFFIHelper {
     }
 
     public static int R_insideBrowser() {
-        return RContext.getInstance().isInBrowser() ? 1 : 0;
+        return RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser() ? 1 : 0;
     }
-
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java
index 168618a998bd8e666fe27f37136eaf78372965a4..da24f27db4ab82bba8840d97541dffae4e408e88 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.runtime.ffi.jnr;
 
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.r.runtime.RPlatform;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
@@ -90,111 +92,122 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI {
         return this;
     }
 
-    private BaseRFFI baseRFFI;
+    @CompilationFinal private BaseRFFI baseRFFI;
 
     @Override
     public BaseRFFI getBaseRFFI() {
         if (baseRFFI == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             baseRFFI = new JNR_Base();
         }
         return baseRFFI;
     }
 
-    private LapackRFFI lapackRFFI;
+    @CompilationFinal private LapackRFFI lapackRFFI;
 
     @Override
     public LapackRFFI getLapackRFFI() {
         if (lapackRFFI == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             lapackRFFI = new JNR_Lapack();
         }
         return lapackRFFI;
     }
 
-    private RApplRFFI rApplRFFI;
+    @CompilationFinal private RApplRFFI rApplRFFI;
 
     @Override
     public RApplRFFI getRApplRFFI() {
         if (rApplRFFI == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             rApplRFFI = new JNR_RAppl();
         }
         return rApplRFFI;
     }
 
-    private StatsRFFI statsRFFI;
+    @CompilationFinal private StatsRFFI statsRFFI;
 
     @Override
     public StatsRFFI getStatsRFFI() {
         if (statsRFFI == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             statsRFFI = new JNR_Stats();
         }
         return statsRFFI;
     }
 
-    private ToolsRFFI toolsRFFI;
+    @CompilationFinal private ToolsRFFI toolsRFFI;
 
     @Override
     public ToolsRFFI getToolsRFFI() {
         if (toolsRFFI == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             toolsRFFI = new Generic_Tools();
         }
         return toolsRFFI;
     }
 
-    private GridRFFI gridRFFI;
+    @CompilationFinal private GridRFFI gridRFFI;
 
     @Override
     public GridRFFI getGridRFFI() {
         if (gridRFFI == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             gridRFFI = new Generic_Grid();
         }
         return gridRFFI;
     }
 
-    private UserRngRFFI userRngRFFI;
+    @CompilationFinal private UserRngRFFI userRngRFFI;
 
     @Override
     public UserRngRFFI getUserRngRFFI() {
         if (userRngRFFI == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             userRngRFFI = new JNR_UserRng();
         }
         return userRngRFFI;
     }
 
-    private CRFFI cRFFI;
+    @CompilationFinal private CRFFI cRFFI;
 
     @Override
     public CRFFI getCRFFI() {
         if (cRFFI == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             cRFFI = new CRFFI_JNR_Invoke();
         }
         return cRFFI;
     }
 
-    private CallRFFI callRFFI;
+    @CompilationFinal private CallRFFI callRFFI;
 
     @Override
     public CallRFFI getCallRFFI() {
         if (callRFFI == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             callRFFI = new JNI_CallRFFI();
         }
         return callRFFI;
     }
 
-    private ZipRFFI zipRFFI;
+    @CompilationFinal private ZipRFFI zipRFFI;
 
     @Override
     public ZipRFFI getZipRFFI() {
         if (zipRFFI == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             zipRFFI = new JNR_Zip();
         }
         return zipRFFI;
     }
 
-    private PCRERFFI pcreRFFI;
+    @CompilationFinal private PCRERFFI pcreRFFI;
 
     @Override
     public PCRERFFI getPCRERFFI() {
         if (pcreRFFI == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             pcreRFFI = new JNR_PCRE();
         }
         return pcreRFFI;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
index 1c9a2d4d54a118b253be02e4587f821dfa9e5719..50a18c02504f470cbfb08d67dc5d3fba23b240de 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
@@ -596,7 +596,10 @@ public class RDeparse {
                         append("list(").appendListContents(obj).append(')');
                     }
                 } else if (value instanceof RAbstractVector) {
-                    appendVector((RAbstractVector) value);
+                    RAbstractVector obj = (RAbstractVector) value;
+                    try (C c = withAttributes(obj)) {
+                        appendVector((RAbstractVector) value);
+                    }
                 } else if (value instanceof RNull) {
                     append("NULL");
                 } else if (value instanceof RFunction) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index a90d09540304fac64402f98e4bafbb04709ba768..15777101afe3c9342eaab71f1313a9f15dda53ae 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -270,6 +270,7 @@ public final class RError extends RuntimeException {
         EMPTY_WHAT("empty 'what' specified"),
         LINE_ELEMENTS("line %d did not have %d elements"),
         ITEMS_NOT_MULTIPLE("number of items read is not a multiple of the number of columns"),
+        TRACEMEM_NOT_NULL("cannot trace NULL"),
         // below: GNU R gives also expression for the argument
         NOT_FUNCTION("'%s' is not a function, character or symbol"),
         NON_CHARACTER("non-character argument"),
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
index 911a09d8291a12e6d029ee2120a74c3b58f83c0a..84afa3b4041e4ac89f860278200c93ab1d4af85c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
@@ -340,7 +340,7 @@ public class RErrorHandling {
                     errorcallDfltWithCall(fromCall(call), Message.GENERIC, msg);
                 } else {
                     RFunction hf = (RFunction) h;
-                    RContext.getEngine().evalFunction(hf, null, null, cond);
+                    RContext.getEngine().evalFunction(hf, null, null, null, cond);
                 }
             } else {
                 throw gotoExitingHandler(cond, call, entry);
@@ -503,7 +503,7 @@ public class RErrorHandling {
                             evaluatedArgs[i] = RMissing.instance;
                         }
                     }
-                    RContext.getEngine().evalFunction(errorFunction, null, null, evaluatedArgs);
+                    RContext.getEngine().evalFunction(errorFunction, null, null, null, evaluatedArgs);
                 } else if (errorExpr instanceof RLanguage || errorExpr instanceof RExpression) {
                     if (errorExpr instanceof RLanguage) {
                         RContext.getEngine().eval((RLanguage) errorExpr, materializedFrame);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
index 3c826891dd099b8bcfe4952440c971abc1bb4f13..85fbeff658a1db99fd8f16bc4364379305ee7993 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
@@ -445,7 +445,7 @@ public class RSerialize {
                      * only used in a warning message in the unlikely event that the namespace
                      * cannot be found.
                      */
-                    Object r = RContext.getEngine().evalFunction(contextState.getDotDotFindNamespace(), null, null, s, "");
+                    Object r = RContext.getEngine().evalFunction(contextState.getDotDotFindNamespace(), null, null, null, s, "");
                     return checkResult(addReadRef(r));
                 }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
index e8363e5a00435d101d9e1a99987924ec2a96fb2b..f6c0f60ed573f8ce488923a6dcb895dc1b938963 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
@@ -35,6 +35,7 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
+import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
@@ -167,9 +168,10 @@ public interface Engine {
      * case the current frame is used). In many cases {@code frame} may not represent the current
      * call stack, for example many S4-related evaluations set {@code frame} to the {@code methods}
      * namespace, but the current stack is not empty. So when {@code frame} is not {@code null} a
-     * {@code caller} should be passed to maintain the call stack correctly.
+     * {@code caller} should be passed to maintain the call stack correctly. {@code names} string
+     * vector describing (optional) argument names
      */
-    Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, Object... args);
+    Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, RStringVector names, Object... args);
 
     /**
      * Checks for the existence of (startup/shutdown) function {@code name} and, if present, invokes
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
index ec21c2f7e22ddbd63241af45c167c0eb31bfcef4..8e011cfa039c2d2d87b63e33897271cfbb7f0a80 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
@@ -293,11 +293,6 @@ public final class RContext extends ExecutionContext implements TruffleObject {
 
     private boolean nullS4Object = false;
 
-    /**
-     * This used to prevent a "quit" from the browser (as per GnuR).
-     */
-    private boolean inBrowser = false;
-
     private boolean active;
 
     private PrimitiveMethodsInfo primitiveMethodsInfo;
@@ -623,14 +618,6 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         nullS4Object = on;
     }
 
-    public boolean isInBrowser() {
-        return inBrowser;
-    }
-
-    public void setInBrowser(boolean on) {
-        inBrowser = on;
-    }
-
     public boolean allowPrimitiveMethods() {
         return allowPrimitiveMethods;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryTracer.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryTracer.java
new file mode 100644
index 0000000000000000000000000000000000000000..05b5db6c2ab0659d63d734052b21dd3216ae1553
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryTracer.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.truffle.r.runtime.data;
+
+import com.oracle.truffle.api.Assumption;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+
+/**
+ * Helper for tracing memory related events. All implementors of {@link RAbstractVector} are
+ * expected to report to {@link MemoryTracer} and others can listen to them through {@link Listener}
+ * interface. Use method {@link #reportEvents()} to start the tracing.
+ */
+public final class MemoryTracer {
+    private static Listener listener;
+    private static final Assumption noMemoryTracingAssumption = Truffle.getRuntime().createAssumption();
+
+    private MemoryTracer() {
+        // only static methods
+    }
+
+    /**
+     * Sets the listener of memory tracing events. For the time being there can only be one
+     * listener. This can be extended to an array should we need more listeners.
+     */
+    public static void setListener(Listener newListener) {
+        listener = newListener;
+    }
+
+    /**
+     * After calling this method memory related events will be reported to the listener. This
+     * invalidates global assumption and should be used with caution.
+     */
+    public static void reportEvents() {
+        noMemoryTracingAssumption.invalidate();
+    }
+
+    /**
+     * Reports copy event to the listener. If there are no traced objects, this should turn into
+     * no-op. TODO might be worth interposing on a change in {@code tracingState} to turn off the
+     * collection.
+     */
+    public static void reportCopying(RAbstractVector source, RAbstractVector dest) {
+        if (!noMemoryTracingAssumption.isValid() && listener != null && RContext.getInstance().stateInstrumentation.getTracingState()) {
+            listener.reportCopying(source, dest);
+        }
+    }
+
+    public interface Listener {
+        void reportCopying(RAbstractVector source, RAbstractVector dest);
+    }
+}
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 a3d7858c77f15957b42b902e19e6a6d2a4707d1d..1bfe70252de40c3162543da9ef30c416b27154b2 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
@@ -67,7 +67,9 @@ public final class RComplex extends RScalarVector implements RAbstractComplexVec
 
     @Override
     public RComplexVector materialize() {
-        return RDataFactory.createComplexVectorFromScalar(this);
+        RComplexVector result = RDataFactory.createComplexVectorFromScalar(this);
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
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 530b0796a9308505f41a7194f8b702ffb35b88f7..e94bd445cc3b6d629053f86da551dbab6deea2bf 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
@@ -198,7 +198,7 @@ public final class RComplexVector extends RVector implements RAbstractComplexVec
     }
 
     @Override
-    public RComplexVector copyResized(int size, boolean fillNA) {
+    protected RComplexVector internalCopyResized(int size, boolean fillNA) {
         boolean isComplete = isComplete() && ((data.length >= size) || !fillNA);
         return RDataFactory.createComplexVector(copyResizedData(size, fillNA), isComplete);
     }
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 b31722d76e5a1b49c4774fc3ed16079908c5b775..096356c36aaf5031ea8b85166e820cfbd7d960b5 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
@@ -89,7 +89,9 @@ public final class RDouble extends RScalarVector implements RAbstractDoubleVecto
 
     @Override
     public RDoubleVector materialize() {
-        return RDataFactory.createDoubleVectorFromScalar(getValue());
+        RDoubleVector result = RDataFactory.createDoubleVectorFromScalar(getValue());
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
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 a3be26975816e8a310f72bf77f809fdd84c72146..c542875fa7f26d8e6b64219f65df90db26b6db82 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
@@ -211,7 +211,7 @@ public final class RDoubleVector extends RVector implements RAbstractDoubleVecto
     }
 
     @Override
-    public RDoubleVector copyResized(int size, boolean fillNA) {
+    protected RDoubleVector internalCopyResized(int size, boolean fillNA) {
         boolean isComplete = isComplete() && ((data.length >= size) || !fillNA);
         return RDataFactory.createDoubleVector(copyResizedData(size, fillNA), isComplete);
     }
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 6a672cdbace2b30459625d2caa289cce155ffd4d..74e182b9cee2de064c08e037eea0ad49440e66dd 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
@@ -208,7 +208,7 @@ public final class RIntVector extends RVector implements RAbstractIntVector {
     }
 
     @Override
-    public RIntVector copyResized(int size, boolean fillNA) {
+    protected RIntVector internalCopyResized(int size, boolean fillNA) {
         boolean isComplete = isComplete() && ((data.length >= size) || !fillNA);
         return RDataFactory.createIntVector(copyResizedData(size, fillNA), isComplete);
     }
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 0df0f556e1b7226069b7e983910c8cbabaf6e25d..075d9ee51126ff8bd297ebffb5b11bed48055b13 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
@@ -87,7 +87,9 @@ public final class RInteger extends RScalarVector implements RAbstractIntVector
 
     @Override
     public RIntVector materialize() {
-        return RDataFactory.createIntVectorFromScalar(value);
+        RIntVector result = RDataFactory.createIntVectorFromScalar(value);
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
index cb0496f25de6cc7d472d396e7a04a1736a142b25..c97e5a73d88d9290e5597a439ec0b73d82d13a7e 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
@@ -72,7 +72,7 @@ public final class RList extends RListBase {
     }
 
     @Override
-    public RList copyResized(int size, boolean fillNA) {
+    protected RList internalCopyResized(int size, boolean fillNA) {
         return RDataFactory.createList(copyResizedData(size, fillNA));
     }
 
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 65f0ad784fd53bec3301152b834b74c3e4efc5b2..05d0e6d1b1d642a39fc13b620d15a3727a3c130d 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
@@ -93,7 +93,9 @@ public final class RLogical extends RScalarVector implements RAbstractLogicalVec
 
     @Override
     public RLogicalVector materialize() {
-        return RDataFactory.createLogicalVectorFromScalar(value);
+        RLogicalVector result = RDataFactory.createLogicalVectorFromScalar(value);
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
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 4d3068841936b172d547b8cad3a69073785ff11d..a492093eb77cf75441f3b9218fb7b370fb9fe891 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
@@ -169,7 +169,7 @@ public final class RLogicalVector extends RVector implements RAbstractLogicalVec
     }
 
     @Override
-    public RLogicalVector copyResized(int size, boolean fillNA) {
+    protected RLogicalVector internalCopyResized(int size, boolean fillNA) {
         boolean isComplete = isComplete() && ((data.length >= size) || !fillNA);
         return RDataFactory.createLogicalVector(copyResizedData(size, fillNA), isComplete);
     }
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 bb93e20a576774f9b6697cdc6b0e47f6b5467417..d843cacfb937a8518c91151e91e7e33b3c553076 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
@@ -64,7 +64,9 @@ public final class RRaw extends RScalarVector implements RAbstractRawVector {
 
     @Override
     public RRawVector materialize() {
-        return RDataFactory.createRawVector(new byte[]{value});
+        RRawVector result = RDataFactory.createRawVector(new byte[]{value});
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
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 fdadc7cd66a1a41c9d046a33e0872ce52827e0a7..01ef62b132ffb705df18b6646b7ca419a06e3da9 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
@@ -187,7 +187,7 @@ public final class RRawVector extends RVector implements RAbstractRawVector {
     }
 
     @Override
-    public RRawVector copyResized(int size, boolean fillNA) {
+    protected RRawVector internalCopyResized(int size, boolean fillNA) {
         return RDataFactory.createRawVector(copyResizedData(size, fillNA));
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java
index 6d7ddced925c96d8bebedfbb4b98892d18dba52f..6e4a7ca5d9590b16c937b8bb62608c6f25ef8cd7 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java
@@ -142,22 +142,30 @@ public abstract class RScalarVector extends RScalar implements RAbstractVector {
 
     @Override
     public RVector copyResized(int size, boolean fillNA) {
-        return materialize().copyResized(size, fillNA);
+        RVector result = materialize().copyResized(size, fillNA);
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
     public RAbstractVector copyWithNewDimensions(int[] newDimensions) {
-        return materialize().copyWithNewDimensions(newDimensions);
+        RAbstractVector result = materialize().copyWithNewDimensions(newDimensions);
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
     public RVector copyResizedWithDimensions(int[] newDimensions, boolean fillNA) {
-        return materialize().copyResizedWithDimensions(newDimensions, fillNA);
+        RVector result = materialize().copyResizedWithDimensions(newDimensions, fillNA);
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
     public RAbstractVector copyDropAttributes() {
-        return materialize().copyDropAttributes();
+        RVector result = materialize().copyDropAttributes();
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java
index df3204230ada99193b5ba8a0003154bd26105c0f..3dcc48a783d72896755c68f58238721596a0d86c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java
@@ -80,7 +80,9 @@ public abstract class RSequence implements RAbstractVector {
     }
 
     public final RVector createVector() {
-        return internalCreateVector();
+        RVector result = internalCreateVector();
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     protected abstract RVector internalCreateVector();
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 03edef949b3c7b03135e912ab175d2079c023b25..764f4c4b4ba2c88556989eb83461fdf4b8409bc5 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
@@ -73,7 +73,9 @@ public final class RString extends RScalarVector implements RAbstractStringVecto
 
     @Override
     public RStringVector materialize() {
-        return RDataFactory.createStringVector(new String[]{getValue()}, isComplete());
+        RStringVector result = RDataFactory.createStringVector(new String[]{getValue()}, isComplete());
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
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 85a263b13b224a23a06cfcbb5bdc50eec83f417e..53f6667432c8ca54341247372fbab98b5a38f82f 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
@@ -190,7 +190,7 @@ public final class RStringVector extends RVector implements RAbstractStringVecto
     }
 
     @Override
-    public RStringVector copyResized(int size, boolean fillNA) {
+    protected RStringVector internalCopyResized(int size, boolean fillNA) {
         boolean isComplete = isComplete() && ((data.length >= size) || !fillNA);
         return RDataFactory.createStringVector(copyResizedData(size, fillNA ? RRuntime.STRING_NA : null), isComplete);
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
index 2c7e3e715317addc7183cab2c3f8b6ac78bb4cd0..159addc3e228b3bda6e2e3bbcc9e9504544c5987 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
@@ -410,7 +410,7 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare
             RList resDimNames = newDimNames;
             if (newDimNamesLength < dimensions.length) {
                 // resize the array and fill the missing entries with NULL-s
-                resDimNames = resDimNames.copyResized(dimensions.length, true);
+                resDimNames = (RList) resDimNames.copyResized(dimensions.length, true);
                 resDimNames.setAttributes(newDimNames);
                 for (int i = newDimNamesLength; i < dimensions.length; i++) {
                     resDimNames.updateDataAt(i, RNull.instance, null);
@@ -547,9 +547,11 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare
         }
     }
 
+    // public interface *copy* methods are final and delegate to *internalCopyAndReport* methods
+
     @Override
     public final RVector copy() {
-        RVector result = internalCopy();
+        RVector result = internalCopyAndReport();
         setAttributes(result);
         incCopyCount();
         result.setTypedValueInfo(getTypedValueInfo());
@@ -558,21 +560,55 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare
 
     @Override
     public final RVector copyDropAttributes() {
-        return internalCopy();
+        RVector result = internalCopyAndReport();
+        return result;
     }
 
     @Override
-    public RVector deepCopy() {
-        RVector result = internalDeepCopy();
+    public final RVector deepCopy() {
+        RVector result = internalDeepCopyAndReport();
         setAttributes(result);
         return result;
     }
 
+    @Override
+    public final RVector copyResized(int size, boolean fillNA) {
+        return internalCopyResizedAndReport(size, fillNA);
+    }
+
+    // *internalCopyAndReport* methods do just the copy and report it to MemoryTracer. These should
+    // be used if additional logic in public interface *copy* method is not desired.
+
+    protected final RVector internalCopyAndReport() {
+        RVector result = internalCopy();
+        MemoryTracer.reportCopying(this, result);
+        return result;
+    }
+
+    protected final RVector internalDeepCopyAndReport() {
+        RVector result = internalDeepCopy();
+        MemoryTracer.reportCopying(this, result);
+        return result;
+    }
+
+    protected final RVector internalCopyResizedAndReport(int size, boolean fillNA) {
+        RVector result = internalCopyResized(size, fillNA);
+        MemoryTracer.reportCopying(this, result);
+        return result;
+    }
+
+    // *internalCopy* methods should only be overridden, but never invoked from anywhere but
+    // *internalCopyAndReport*
+
+    protected abstract RVector internalCopyResized(int size, boolean fillNA);
+
     // to be overridden by recursive structures
     protected RVector internalDeepCopy() {
         return internalCopy();
     }
 
+    protected abstract RVector internalCopy();
+
     @Override
     public RVector copyResizedWithDimensions(int[] newDimensions, boolean fillNA) {
         // TODO support for higher dimensions
@@ -588,8 +624,6 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare
 
     protected abstract String getDataAtAsString(int index);
 
-    protected abstract RVector internalCopy();
-
     protected abstract boolean internalVerify();
 
     /**
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 a0a74fcdcb3df189eb2397dee4f99d42ed18306d..0fe0baccfc90e7e0bb0b1a374322b1d431b37cc2 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
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.data.closures;
 
+import com.oracle.truffle.r.runtime.data.MemoryTracer;
 import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RAttributes;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -127,12 +128,16 @@ abstract class RToVectorClosure implements RAbstractVector {
 
     @Override
     public final RAbstractVector copy() {
-        return vector.copy();
+        RAbstractVector result = vector.copy();
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
     public final RVector copyResized(int size, boolean fillNA) {
-        return vector.copyResized(size, fillNA);
+        RVector result = vector.copyResized(size, fillNA);
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
@@ -146,7 +151,9 @@ abstract class RToVectorClosure implements RAbstractVector {
 
     @Override
     public final RAbstractVector copyDropAttributes() {
-        return vector.copyDropAttributes();
+        RAbstractVector result = vector.copyDropAttributes();
+        MemoryTracer.reportCopying(this, result);
+        return result;
     }
 
     @Override
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 b0f2d25be47dfeb42fb3d7d4cc7eaadea0f5fcc7..a2ae57288b474717f66033b2bacd43a882e5e899 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
@@ -24,8 +24,12 @@ package com.oracle.truffle.r.runtime.data.model;
 
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.MemoryTracer;
 import com.oracle.truffle.r.runtime.data.RVector;
 
+/**
+ * When implementing, make sure to invoke related {@link MemoryTracer} methods.
+ */
 public interface RAbstractVector extends RAbstractContainer {
 
     /**
@@ -76,5 +80,4 @@ public interface RAbstractVector extends RAbstractContainer {
     void setComplete(boolean complete);
 
     void setNA(Object store, int index);
-
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
index e34c048fda5393653330a81013f66d3907276fec..694ac019f0eed1aa25cfcede1df14b03bd45d1aa 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
@@ -36,7 +37,7 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextState;
  */
 public abstract class RFFIFactory {
 
-    protected static RFFI theRFFI;
+    @CompilationFinal protected static RFFI theRFFI;
 
     public static void setRFFIFactory(RFFIFactory factory) {
         RFFIContextStateFactory.registerFactory(factory);
@@ -52,7 +53,7 @@ public abstract class RFFIFactory {
      * Initialize the factory instance. This method will be called immediately after the factory
      * instance is created allowing any additional initialization that could not be done in the
      * constructor.
-     * 
+     *
      * @param runtime {@code true} if the initialization is being done at runtime. An AOT system may
      *            call this twice, once with {@code false} whern an image is being bilt and once
      *            when starting up.
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java
index 87b3341dae1bdc444b1f3e64b7657a8835905597..09f5a10046d079cd9b7697e1d51e4fb172fb4556 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.runtime.instrument;
 
 import java.io.PrintWriter;
+import java.util.HashSet;
 import java.util.WeakHashMap;
 
 import com.oracle.truffle.api.instrumentation.EventBinding;
@@ -52,27 +53,60 @@ public final class InstrumentationState implements RContext.ContextState {
      */
     private final WeakHashMap<SourceSection, ExecutionEventListener> debugListenerMap = new WeakHashMap<>();
 
+    /**
+     * The {@link Instrumenter} associated with this {@link RContext}. Never {@code null}.
+     */
     private final Instrumenter instrumenter;
 
+    /**
+     * The {@link Profiler}, if any, associated with this {@link RContext}.
+     */
     private Profiler profiler;
 
+    /**
+     * The {@link RprofState} state, if any, associated with this {@link RContext}.
+     */
     private final RprofState rprofState;
 
+    private final TracememContext tracememContext;
+
+    /**
+     * State used by the {@code tracemem} built-in.
+     */
+    public static final class TracememContext {
+        private HashSet<Object> tracedObjects;
+
+        public HashSet<Object> getTracedObjects() {
+            if (tracedObjects == null) {
+                tracedObjects = new HashSet<>();
+            }
+            return tracedObjects;
+        }
+    }
+
+    /**
+     * The {@link BrowserState} state, if any, associated with this {@link RContext}.
+     */
+    private final BrowserState browserState;
+
+    /**
+     * Whether debugging is globally disabled in this {@link RContext}. Used to (temporarily)
+     * disable all debugging across calls that are used internally in the implementation.
+     *
+     */
+    private boolean debugGloballyDisabled;
+
     /**
      * State used by {@code Rprof}.
      *
      */
-    public static class RprofState {
+    public static final class RprofState {
         private PrintWriter out;
         private Thread profileThread;
         private ExecutionEventListener statementListener;
         private long intervalInMillis;
         private boolean lineProfiling;
 
-        public static RprofState newContext(@SuppressWarnings("unused") RContext context) {
-            return new RprofState();
-        }
-
         public void initialize(PrintWriter outA, Thread profileThreadA, ExecutionEventListener statementListenerA, long intervalInMillisA,
                         boolean lineProfilingA) {
             this.out = outA;
@@ -104,9 +138,32 @@ public final class InstrumentationState implements RContext.ContextState {
 
     }
 
+    public static class BrowserState {
+        private boolean inBrowser;
+        private String lastEmptyLineCommand = "n";
+
+        public void setInBrowser(boolean state) {
+            this.inBrowser = state;
+        }
+
+        public boolean inBrowser() {
+            return inBrowser;
+        }
+
+        public void setLastEmptyLineCommand(String s) {
+            lastEmptyLineCommand = s;
+        }
+
+        public String lastEmptyLineCommand() {
+            return lastEmptyLineCommand;
+        }
+    }
+
     private InstrumentationState(Instrumenter instrumenter) {
         this.instrumenter = instrumenter;
         this.rprofState = new RprofState();
+        this.tracememContext = new TracememContext();
+        this.browserState = new BrowserState();
     }
 
     public void putTraceBinding(SourceSection ss, EventBinding<?> binding) {
@@ -158,6 +215,24 @@ public final class InstrumentationState implements RContext.ContextState {
         return rprofState;
     }
 
+    public TracememContext getTracemem() {
+        return tracememContext;
+    }
+
+    public BrowserState getBrowserState() {
+        return browserState;
+    }
+
+    public boolean setDebugGloballyDisabled(boolean state) {
+        boolean current = debugGloballyDisabled;
+        this.debugGloballyDisabled = state;
+        return current;
+    }
+
+    public boolean debugGloballyDisabled() {
+        return debugGloballyDisabled;
+    }
+
     public static InstrumentationState newContext(@SuppressWarnings("unused") RContext context, Instrumenter instrumenter) {
         return new InstrumentationState(instrumenter);
     }
diff --git a/com.oracle.truffle.r.test.cran/r/install.cran.packages.R b/com.oracle.truffle.r.test.cran/r/install.cran.packages.R
index 21cd5a3d1eb5117ade53b4aa7b5dad141bee04f9..097eab15f6bf8feeb4576609efce8337a4fd018b 100644
--- a/com.oracle.truffle.r.test.cran/r/install.cran.packages.R
+++ b/com.oracle.truffle.r.test.cran/r/install.cran.packages.R
@@ -331,8 +331,27 @@ check.installed.pkgs <- function() {
 # requested set of candidate packages
 # sets global variables avail.pkgs and toinstall.pkgs, the latter being
 # of the same type as avail.pkgs but containing only those packages to install
+# returns a vector of package names to install/test
 get.pkgs <- function() {
-	avail.pkgs <<- available.packages(contriburl=contriburl, type="source")
+	my.warning <- function(war) {
+		if (!quiet) {
+			cat("Fatal error:", war$message, "\n")
+		}
+		quit(save="no", status=100)
+	}
+	tryCatch({
+	    avail.pkgs <<- available.packages(contriburl=contriburl, type="source")
+    }, warning=my.warning)
+
+    # Owing to a FastR bug, we may not invoke the handler above, but
+	# if length(avail.pkgs) == 0, that also means it failed
+	if (length(avail.pkgs) == 0) {
+		if (!quiet) {
+		  print("Fatal error: no packages found in repo")
+    	}
+		quit(save="no", status=100)
+	}
+
 	avail.pkgs.rownames <<- rownames(avail.pkgs)
 	# get/create the blacklist
 	blacklist <- get.blacklist()
@@ -371,7 +390,29 @@ get.pkgs <- function() {
 	}
 	matched.avail.pkgs <- apply(avail.pkgs, 1, match.fun)
 	toinstall.pkgs <<-avail.pkgs[matched.avail.pkgs, , drop=F]
-	toinstall.pkgs
+
+	if (!is.na(random.count)) {
+		# install random.count packages taken at random from toinstall.pkgs
+		test.avail.pkgnames <- rownames(toinstall.pkgs)
+		rands <- sample(1:length(test.avail.pkgnames))
+		test.pkgnames <- character(random.count)
+		for (i in (1:random.count)) {
+			test.pkgnames[[i]] <- test.avail.pkgnames[[rands[[i]]]]
+		}
+	} else {
+		test.pkgnames <- rownames(toinstall.pkgs)
+		if (!is.na(count.daily)) {
+			# extract count from index given by yday
+			npkgs <- length(test.pkgnames)
+			yday <- as.POSIXlt(Sys.Date())$yday
+			chunk <- as.integer(npkgs / count.daily)
+			start <- (yday %% chunk) * count.daily
+			end <- ifelse(start + count.daily > npkgs, npkgs, start + count.daily - 1)
+			test.pkgnames <- test.pkgnames[start:end]
+		}
+	}
+
+	test.pkgnames
 }
 
 # Serially install the packages in pkgnames.
@@ -476,36 +517,15 @@ get.blacklist <- function() {
 
 # performs the installation, or logs what it would install if dry.run = T
 do.it <- function() {
-	get.pkgs()
+	test.pkgnames <- get.pkgs()
 
 	if (list.versions) {
-		for (i in (1:length(rownames(toinstall.pkgs)))) {
-			pkg <- toinstall.pkgs[i, ]
+		for (pkgname in test.pkgnames) {
+			pkg <- toinstall.pkgs[pkgname, ]
 			cat(pkg["Package"], pkg["Version"], paste0(contriburl, "/", pkg["Version"], ".tar.gz"), "\n", sep=",")
 		}
 	}
 
-	if (!is.na(random.count)) {
-		# install random.count packages taken at random from toinstall.pkgs
-		test.avail.pkgnames <- rownames(toinstall.pkgs)
-		rands <- sample(1:length(test.avail.pkgnames))
-		test.pkgnames <- character(random.count)
-		for (i in (1:random.count)) {
-			test.pkgnames[[i]] <- test.avail.pkgnames[[rands[[i]]]]
-		}
-	} else {
-		test.pkgnames <- rownames(toinstall.pkgs)
-		if (!is.na(count.daily)) {
-			# extract count from index given by yday
-			npkgs <- length(test.pkgnames)
-			yday <- as.POSIXlt(Sys.Date())$yday
-			chunk <- as.integer(npkgs / count.daily)
-			start <- (yday %% chunk) * count.daily
-			end <- ifelse(start + count.daily > npkgs, npkgs, start + count.daily - 1)
-			test.pkgnames <- test.pkgnames[start:end]
-		}
-	}
-
 	if (install) {
 		cat("BEGIN package installation\n")
 		install.pkgs(test.pkgnames)
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 8bca99d985bc4f7cde543a0edf8814d21ddfa77a..cce7e0ea8f6adac97096e5d2ed610d0dd411bf97 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
@@ -9890,6 +9890,11 @@ $names
  z
  1 42
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testCombine
+#{ x<-c(a=42); y<-c(b=7); z<-c(x,y); w<-names(z); w[[1]]<-"c"; z }
+ a  b
+42  7
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testCombine
 #{ x<-c(y=1);  c(x, 42) }
  y
@@ -13214,6 +13219,11 @@ logical(0)
 #{ complex(3) }
 [1] 0+0i 0+0i 0+0i
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_complex.testComplex
+#{ complex(3, 3, new.env()) }
+Error in complex(3, 3, new.env()) :
+  environments cannot be coerced to other types
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_complex.testComplex
 #{ complex(3, c(1,2), c(4,5,6)) }
 [1] 1+4i 2+5i 1+6i
@@ -13226,6 +13236,15 @@ logical(0)
 #{ complex(3, c(1,2,3), c(4,5,6)) }
 [1] 1+4i 2+5i 3+6i
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_complex.testComplex
+#{ complex(3, new.env()) }
+Error in complex(3, new.env()) :
+  environments cannot be coerced to other types
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_complex.testComplex
+#{ complex(new.env()) }
+Error in complex(new.env()) : invalid length
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_complex.testComplex
 #{ complex(real=1,imag=2) }
 [1] 1+2i
@@ -15238,6 +15257,10 @@ a[a <- TRUE]
 #{ k <- 2 ; deparse(k) }
 [1] "2"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_deparse.testDeparse
+#{ x<-c(a=42, b=7); deparse(x) }
+[1] "structure(c(42, 7), .Names = c(\"a\", \"b\"))"
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_deparse.testDeparse
 #{ x<-expression(1); deparse(x) }
 [1] "expression(1)"
@@ -36745,6 +36768,21 @@ integer(0)
 #argv <- structure(list(pkgname = 'stats4', event = 'onLoad'),     .Names = c('pkgname', 'event'));do.call('packageEvent', argv)
 [1] "UserHook::stats4::onLoad"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_pairlist.testPairList
+#{ x<-7; y<-c(foo=42); z<-pairlist(x, y); list(z, typeof(z)) }
+[[1]]
+[[1]][[1]]
+[1] 7
+
+[[1]][[2]]
+foo
+ 42
+
+
+[[2]]
+[1] "pairlist"
+
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_pairlist.testpairlist1
 #argv <- list();do.call('pairlist', argv)
 NULL
@@ -40693,14 +40731,6 @@ logical(0)
 [145]  NA   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
 [163]   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_retracemem.testretracemem1
-#argv <- list(FALSE, FALSE);retracemem(argv[[1]],argv[[2]]);
-Error in retracemem(argv[[1]], argv[[2]]) : invalid 'previous' argument
-
-##com.oracle.truffle.r.test.builtins.TestBuiltin_retracemem.testretracemem2
-#argv <- list(structure(3.14159265358979, class = structure('3.14159265358979', class = 'testit')), structure(3.14159265358979, class = structure('3.14159265358979', class = 'testit')));retracemem(argv[[1]],argv[[2]]);
-Error in retracemem(argv[[1]], argv[[2]]) : invalid 'previous' argument
-
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rev.testRev
 #{ rev(1:3) }
 [1] 3 2 1
@@ -48848,6 +48878,39 @@ character(0)
 #argv <- structure(list(x = c('na', NA, 'banana')), .Names = 'x');do.call('toupper', argv)
 [1] "NA"     NA       "BANANA"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.argumentErrors
+#retracemem(NULL)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.argumentErrors
+#retracemem(c(1,10,100), 1:10)
+Error in retracemem(c(1, 10, 100), 1:10) : invalid 'previous' argument
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.argumentErrors
+#tracemem(NULL)
+Error in tracemem(NULL) : cannot trace NULL
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.list
+#v <- list(1,10,100); tracemem(v); x <- v; x[[1]]<-42;
+[1] "<0x112db18>"
+tracemem[0x112db18 -> 0x1699c30]:
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.retracemem
+#v <- c(1,10,100); tracemem(v); x <- v[-1]; retracemem(x, retracemem(v)); u <- x; u[[1]] <- 42;
+[1] "<0x17f8b18>"
+tracemem[<0x17f8b18> -> 0x251dd78]:
+tracemem[0x251dd78 -> 0x251ddb0]:
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.vectors
+#v <- c(1,10,100); tracemem(v); x <- v; y <- v; x[[1]]<-42; untracemem(v); y[[2]] <- 84
+[1] "<0x1b8eb18>"
+tracemem[0x1b8eb18 -> 0x20fabe8]:
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.vectors
+#v <- c(1,10,100); tracemem(v); x <- v; y <- v; x[[1]]<-42; y[[2]] <- 84
+[1] "<0x24b2b18>"
+tracemem[0x24b2b18 -> 0x2a1ebe8]:
+tracemem[0x24b2b18 -> 0x2a1ea80]:
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_trigamma.testtrigamma1
 #argv <- list(structure(c(9.16602362697115, 1.16602362697115, 3.16602362697115, 6.16602362697115, 6.16602362697115, 2.16602362697115, 8.16602362697115, 1.16602362697115, 7.16602362697115, 19.1660236269712, 2.16602362697115), .Names = c('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11')));trigamma(argv[[1]]);
          1          2          3          4          5          6          7
@@ -106806,31 +106869,31 @@ a b c d e
 [1] "123"
 
 ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions
-#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { { f<-function(x) fastr.refcountinfo(x); f(c(1,2)) } }
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { { f<-function(x) .fastr.refcountinfo(x); f(c(1,2)) } }
 [1] 1
 
 ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions
-#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2 } else { { f<-function(x) { y<-x; fastr.refcountinfo(y) }; f(c(1,2)) } }
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2 } else { { f<-function(x) { y<-x; .fastr.refcountinfo(y) }; f(c(1,2)) } }
 [1] 2
 
 ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions
-#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2 } else { { x<-c(1,2); f<-function(x) fastr.refcountinfo(x); f(x) } }
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2 } else { { x<-c(1,2); f<-function(x) .fastr.refcountinfo(x); f(x) } }
 [1] 2
 
 ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions
-#if (length(grep("FastR", R.Version()$version.string)) != 1) { FALSE } else { { f<-function(y) { x<-y; xi1<-fastr.identity(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }; f(c(1,2)) } }
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { FALSE } else { { f<-function(y) { x<-y; xi1<-.fastr.identity(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }; f(c(1,2)) } }
 [1] FALSE
 
 ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions
-#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { f<-function(x) { xi1<-fastr.identity(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }; f(c(1,2)) } }
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { f<-function(x) { xi1<-.fastr.identity(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }; f(c(1,2)) } }
 [1] TRUE
 
 ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions
-#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { x<-rep(1, 100); xi1<-fastr.identity(x); f<-function(x) { x }; f(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 } }
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { x<-rep(1, 100); xi1<-.fastr.identity(x); f<-function(x) { x }; f(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 } }
 [1] TRUE
 
 ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions
-#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { x<-rep(1, 100); xi1<-fastr.identity(x); f<-function(x) { y<-x; y }; f(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 } }
+#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { x<-rep(1, 100); xi1<-.fastr.identity(x); f<-function(x) { y<-x; y }; f(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 } }
 [1] TRUE
 
 ##com.oracle.truffle.r.test.library.stats.TestFitting.testLm
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
index b002045656a8214a91587222a65aedb82e056adf..257566d7e83fdf6d15a746ff079664c03fdd5138 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
@@ -22,6 +22,7 @@ import java.nio.file.Paths;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Map.Entry;
 import java.util.SortedMap;
 import java.util.TreeMap;
@@ -68,6 +69,7 @@ public class TestBase {
         IgnoreWarningContext, // the warning context is ignored
         MayIgnoreErrorContext,
         MayIgnoreWarningContext,
+        ContainsReferences, // replaces references in form of 0xbcdef1 for numbers
         IgnoreWhitespace;
     }
 
@@ -353,6 +355,11 @@ public class TestBase {
      */
     private static final boolean FULL_COMPARE_ERRORS = false;
 
+    /**
+     * To implement {@link Output#ContainsReferences}.
+     **/
+    private static final Pattern REFERENCE_PATTERN = Pattern.compile("(?<id>(0x[0-9abcdefx]+))");
+
     /**
      * Test a given string with R source against expected output. This is (currently) an exact
      * match, so any warnings or errors will cause a failure until FastR matches GnuR in that
@@ -459,6 +466,7 @@ public class TestBase {
         boolean mayContainError = TestTrait.contains(traits, Output.MayIgnoreErrorContext);
         boolean ambiguousError = TestTrait.contains(traits, Output.IgnoreErrorMessage);
         boolean ignoreWhitespace = TestTrait.contains(traits, Output.IgnoreWhitespace);
+        boolean containsReferences = TestTrait.contains(traits, Output.ContainsReferences);
         boolean nonSharedContext = TestTrait.contains(traits, Context.NonShared);
         boolean longTimeout = TestTrait.contains(traits, Context.LongTimeout);
 
@@ -477,7 +485,7 @@ public class TestBase {
                     result = result.replaceAll("\\s+", "");
                 }
 
-                CheckResult checkResult = checkResult(whiteLists, input, expected, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError);
+                CheckResult checkResult = checkResult(whiteLists, input, expected, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError, containsReferences);
 
                 result = checkResult.result;
                 expected = checkResult.expected;
@@ -539,14 +547,18 @@ public class TestBase {
     }
 
     private CheckResult checkResult(WhiteList[] whiteLists, String input, String originalExpected, String originalResult, boolean containsWarning, boolean mayContainWarning, boolean containsError,
-                    boolean mayContainError, boolean ambiguousError) {
+                    boolean mayContainError, boolean ambiguousError, boolean convertReferences) {
         boolean ok;
         String result = originalResult;
         String expected = originalExpected;
+        if (convertReferences) {
+            result = convertReferencesInOutput(result);
+            expected = convertReferencesInOutput(expected);
+        }
         if (input.equals("c(1i,1i,1i)/(-(1/0))")) {
             System.console();
         }
-        if (expected.equals(result) || searchWhiteLists(whiteLists, input, expected, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError)) {
+        if (expected.equals(result) || searchWhiteLists(whiteLists, input, expected, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError, convertReferences)) {
             ok = true;
             if (containsError && !ambiguousError) {
                 System.out.println("unexpected correct error message: " + getTestContext());
@@ -575,8 +587,23 @@ public class TestBase {
         return new CheckResult(ok, result, expected);
     }
 
+    private static String convertReferencesInOutput(String result) {
+        Matcher matcher = REFERENCE_PATTERN.matcher(result);
+        HashMap<String, Integer> idsMap = new HashMap<>();
+        int currentId = 1;
+        while (matcher.find()) {
+            if (idsMap.putIfAbsent(matcher.group("id"), currentId) == null) {
+                currentId++;
+            }
+        }
+        for (Entry<String, Integer> item : idsMap.entrySet()) {
+            result = result.replace(item.getKey(), item.getValue().toString());
+        }
+        return result;
+    }
+
     private boolean searchWhiteLists(WhiteList[] whiteLists, String input, String expected, String result, boolean containsWarning, boolean mayContainWarning, boolean containsError,
-                    boolean mayContainError, boolean ambiguousError) {
+                    boolean mayContainError, boolean ambiguousError, boolean convertReferences) {
         if (whiteLists == null) {
             return false;
         }
@@ -584,13 +611,13 @@ public class TestBase {
             WhiteList.Results wlr = list.get(input);
             if (wlr != null) {
                 // Sanity check that "expected" matches the entry in the WhiteList
-                CheckResult checkedResult = checkResult(null, input, wlr.expected, expected, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError);
+                CheckResult checkedResult = checkResult(null, input, wlr.expected, expected, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError, convertReferences);
                 if (!checkedResult.ok) {
                     System.out.println("expected output does not match: " + wlr.expected + " vs. " + expected);
                     return false;
                 }
                 // Substitute the FastR output and try to match that
-                CheckResult fastRResult = checkResult(null, input, wlr.fastR, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError);
+                CheckResult fastRResult = checkResult(null, input, wlr.fastR, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError, convertReferences);
                 if (fastRResult.ok) {
                     list.markUsed(input);
                     return true;
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java
index b3fe43da16d732f65ee0fda8883c1163fb5ac5fd..b972661904eccb4e49daa0755387d353cb8a4cef 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java
@@ -541,6 +541,9 @@ public class TestBuiltin_c extends TestBase {
         assertEval("{ setClass(\"foo\", representation(d=\"numeric\")); x<-new(\"foo\", d=42); y<-c(x, 7); y[[1]] }");
 
         assertEval("{ typeof(c(as.symbol(\"foo\"), 42)) }");
+
+        // names vector created by combine cannot be temporary
+        assertEval("{ x<-c(a=42); y<-c(b=7); z<-c(x,y); w<-names(z); w[[1]]<-\"c\"; z }");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_complex.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_complex.java
index 166495ab7772c50e59904a86b027f24455ac6a93..9698cfdb0b5fe5ac45effa9dbb8fc9bd044df5b3 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_complex.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_complex.java
@@ -24,13 +24,12 @@ public class TestBuiltin_complex extends TestBase {
 
     @Test
     public void testcomplex2() {
-        assertEval(Ignored.Unknown, "argv <- list(FALSE, FALSE, numeric(0)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(FALSE, FALSE, numeric(0)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
     public void testcomplex3() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(0L, 1:10, c(1, 1.4142135623731, 1.73205080756888, 2, 2.23606797749979, 2.44948974278318, 2.64575131106459, 2.82842712474619, 3, 3.16227766016838)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(0L, 1:10, c(1, 1.4142135623731, 1.73205080756888, 2, 2.23606797749979, 2.44948974278318, 2.64575131106459, 2.82842712474619, 3, 3.16227766016838)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
@@ -50,7 +49,7 @@ public class TestBuiltin_complex extends TestBase {
 
     @Test
     public void testcomplex7() {
-        assertEval(Ignored.Unknown, "argv <- list(0L, NULL, numeric(0)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))");
+        assertEval("argv <- list(0L, NULL, numeric(0)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))");
     }
 
     @Test
@@ -58,6 +57,9 @@ public class TestBuiltin_complex extends TestBase {
         assertEval("{ complex(real=1,imaginary=2) }");
         assertEval("{ complex(real=1,imag=2) }");
         assertEval("{ complex(3) }");
+        assertEval(Output.IgnoreErrorMessage, "{ complex(new.env()) }");
+        assertEval("{ complex(3, new.env()) }");
+        assertEval("{ complex(3, 3, new.env()) }");
         assertEval("{ complex(3, c(1,2,3), c(4,5,6)) }");
         assertEval("{ complex(3, c(1,2,3), c(4,5)) }");
         assertEval("{ complex(3, c(1,2), c(4,5,6)) }");
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java
index 8a8b2d5ef5f58711e052ff74d34266dc699895e1..1ad6c86052ab6784676a60143e735538dfdbbf4e 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java
@@ -319,6 +319,8 @@ public class TestBuiltin_deparse extends TestBase {
 
         assertEval("unserialize(serialize(quote(!(a <- TRUE)), NULL))");
         assertEval("unserialize(serialize(quote(a[a <- TRUE]), NULL))");
+
+        assertEval("{ x<-c(a=42, b=7); deparse(x) }");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pairlist.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pairlist.java
index bcf662251692789948b05cf944e737d65507f520..5c44cfe13b3b3ffc5126d1bea67ea46041fb5854 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pairlist.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pairlist.java
@@ -22,4 +22,10 @@ public class TestBuiltin_pairlist extends TestBase {
     public void testpairlist1() {
         assertEval("argv <- list();do.call('pairlist', argv)");
     }
+
+    @Test
+    public void testPairList() {
+        assertEval("{ x<-7; y<-c(foo=42); z<-pairlist(x, y); list(z, typeof(z)) }");
+    }
+
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_retracemem.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_retracemem.java
deleted file mode 100644
index ae260d0e65b227cb5ccdee90bea38ccda0e052c8..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_retracemem.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * This material is distributed under the GNU General Public License
- * Version 2. You may review the terms of this license at
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
- *
- * All rights reserved.
- */
-package com.oracle.truffle.r.test.builtins;
-
-import org.junit.Test;
-
-import com.oracle.truffle.r.test.TestBase;
-
-// Checkstyle: stop line length check
-public class TestBuiltin_retracemem extends TestBase {
-
-    @Test
-    public void testretracemem1() {
-        assertEval(Ignored.Unknown, "argv <- list(FALSE, FALSE);retracemem(argv[[1]],argv[[2]]);");
-    }
-
-    @Test
-    public void testretracemem2() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(structure(3.14159265358979, class = structure('3.14159265358979', class = 'testit')), structure(3.14159265358979, class = structure('3.14159265358979', class = 'testit')));retracemem(argv[[1]],argv[[2]]);");
-    }
-}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tracemem.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tracemem.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b4e4e6f413c56d80610c894335b45f40983ee96
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tracemem.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.truffle.r.test.builtins;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.test.TestBase;
+
+/**
+ * Tests tracemem and related builtins.
+ */
+public class TestBuiltin_tracemem extends TestBase {
+    @Test
+    public void argumentErrors() {
+        assertEval("tracemem(NULL)");
+        assertEval("retracemem(NULL)");
+        assertEval("retracemem(c(1,10,100), 1:10)");
+    }
+
+    @Test
+    public void vectors() {
+        assertEval(Output.ContainsReferences, "v <- c(1,10,100); tracemem(v); x <- v; y <- v; x[[1]]<-42; y[[2]] <- 84");
+        assertEval(Output.ContainsReferences, "v <- c(1,10,100); tracemem(v); x <- v; y <- v; x[[1]]<-42; untracemem(v); y[[2]] <- 84");
+    }
+
+    @Test
+    public void list() {
+        assertEval(Output.ContainsReferences, "v <- list(1,10,100); tracemem(v); x <- v; x[[1]]<-42;");
+    }
+
+    @Test
+    public void retracemem() {
+        // intended semantics of retracemem is not clear, this tests what is definitely intended:
+        // retracemem starts tracing of its first argument
+        assertEval(Output.ContainsReferences, "v <- c(1,10,100); tracemem(v); x <- v[-1]; retracemem(x, retracemem(v)); u <- x; u[[1]] <- 42;");
+    }
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestStateTrans.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestStateTrans.java
index ff68983f3f4a650650aac0055063dec408774959..d0dbbf9a5d425c504f77a51f7f00f71ff6384156 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestStateTrans.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestStateTrans.java
@@ -31,14 +31,14 @@ public class TestStateTrans extends TestBase {
 
     @Test
     public void testTransitions() {
-        assertEvalFastR("{ f<-function(x) fastr.refcountinfo(x); f(c(1,2)) }", "1");
-        assertEvalFastR("{ f<-function(x) { y<-x; fastr.refcountinfo(y) }; f(c(1,2)) }", "2");
-        assertEvalFastR("{ x<-c(1,2); f<-function(x) fastr.refcountinfo(x); f(x) }", "2");
-        assertEvalFastR("{ f<-function(x) { xi1<-fastr.identity(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }; f(c(1,2)) }", "TRUE");
-        assertEvalFastR("{ f<-function(y) { x<-y; xi1<-fastr.identity(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }; f(c(1,2)) }", "FALSE");
+        assertEvalFastR("{ f<-function(x) .fastr.refcountinfo(x); f(c(1,2)) }", "1");
+        assertEvalFastR("{ f<-function(x) { y<-x; .fastr.refcountinfo(y) }; f(c(1,2)) }", "2");
+        assertEvalFastR("{ x<-c(1,2); f<-function(x) .fastr.refcountinfo(x); f(x) }", "2");
+        assertEvalFastR("{ f<-function(x) { xi1<-.fastr.identity(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }; f(c(1,2)) }", "TRUE");
+        assertEvalFastR("{ f<-function(y) { x<-y; xi1<-.fastr.identity(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }; f(c(1,2)) }", "FALSE");
         // after returning from read-only functions, vector should be modifiable without
         // creating a copy
-        assertEvalFastR("{ x<-rep(1, 100); xi1<-fastr.identity(x); f<-function(x) { x }; f(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }", "TRUE");
-        assertEvalFastR("{ x<-rep(1, 100); xi1<-fastr.identity(x); f<-function(x) { y<-x; y }; f(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }", "TRUE");
+        assertEvalFastR("{ x<-rep(1, 100); xi1<-.fastr.identity(x); f<-function(x) { x }; f(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }", "TRUE");
+        assertEvalFastR("{ x<-rep(1, 100); xi1<-.fastr.identity(x); f<-function(x) { y<-x; y }; f(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }", "TRUE");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RBuiltinCheck.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RBuiltinCheck.java
index 2ce13c5c6a2a97403a8dfae84a64514e047f9e53..f34dc91c6beab8cfd78f4583140f10292d7622d7 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RBuiltinCheck.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RBuiltinCheck.java
@@ -28,10 +28,10 @@ import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
 import java.util.function.BiPredicate;
 import java.util.function.Function;
 import java.util.regex.Matcher;
@@ -44,6 +44,7 @@ import com.oracle.truffle.r.nodes.builtin.base.BasePackage;
 import com.oracle.truffle.r.runtime.RBuiltin;
 import com.oracle.truffle.r.runtime.RBuiltinKind;
 import com.oracle.truffle.r.runtime.RVisibility;
+import com.oracle.truffle.r.test.TestBase.Ignored;
 
 /**
  * Utility to analyze builtins implemented in FastR vs. builtins available in GNU R. The GNU R
@@ -62,6 +63,7 @@ import com.oracle.truffle.r.runtime.RVisibility;
 public final class RBuiltinCheck {
 
     private static final String DEFAULT_NAMESC = "com.oracle.truffle.r.native/gnur/R-3.2.4/src/main/names.c";
+    private static final String BUILTIN_TEST_PATH = "com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_%s.java";
 
     // old-style code annotation to get rid of javadoc error.
     /**
@@ -170,7 +172,7 @@ public final class RBuiltinCheck {
             return; // so that gnur can be final
         }
 
-        Set<String> both = new HashSet<>(fastr.keySet());
+        Set<String> both = new TreeSet<>(fastr.keySet());
         both.retainAll(gnur.keySet());
 
         Set<String> fastrOnly = keysWithout(fastr, both);
@@ -181,14 +183,14 @@ public final class RBuiltinCheck {
         both.removeAll(descriptorsDiff.keySet());
 
         // Print the results
-        printOutput(show, both, descriptorsDiff, fastrOnly, gnurOnly);
+        printOutput(suitePath, show, both, descriptorsDiff, fastrOnly, gnurOnly);
     }
 
-    private static void printOutput(EnumSet<FilterOption> show, Set<String> both, Map<String, BuiltinTuple> descriptorsDiff, Set<String> fastrOnly, Set<String> gnurOnly) {
+    private static void printOutput(String suitePath, EnumSet<FilterOption> show, Set<String> both, Map<String, BuiltinTuple> descriptorsDiff, Set<String> fastrOnly, Set<String> gnurOnly) {
         String prefix = "";
         if (show.contains(FilterOption.BOTH)) {
             prefix = printHeader(prefix, show, "Builtins in both GNU R and FastR with matching descriptors: " + both.size());
-            both.stream().forEach(System.out::println);
+            both.stream().forEach(b -> printBuiltinWithTest(b, suitePath));
         }
 
         if (show.contains(FilterOption.BOTH_DIFF)) {
@@ -220,6 +222,24 @@ public final class RBuiltinCheck {
         }
     }
 
+    private static void printBuiltinWithTest(String builtin, String suitePath) {
+        String name = builtin.replace(".", "");
+        name = name.replace("<-", "assign");
+        try {
+            String content = Files.lines(Paths.get(suitePath, String.format(BUILTIN_TEST_PATH, name))).collect(Collectors.joining("\n"));
+            int tests = content.split("assertEval").length - 1;
+            int ignoredTests = content.split(Ignored.class.getSimpleName()).length - 1;
+            if (tests > 0) {
+                String testDetails = String.format("%3d%% (%d/%d)", (tests - ignoredTests) * 100 / tests, tests - ignoredTests, tests);
+                System.out.printf("%-15s %s%n", builtin, testDetails);
+                return;
+            }
+        } catch (IOException e) {
+            // nothing to do
+        }
+        System.out.printf("%-20s (no tests found)%n", builtin);
+    }
+
     private static String formatTableCell(String format, BuiltinTuple tuple, Function<BuiltinInfo, Object> selector, BiPredicate<BuiltinInfo, BuiltinInfo> cmp) {
         String result = String.format(format, selector.apply(tuple.fastr), selector.apply(tuple.gnur));
         if (!cmp.test(tuple.fastr, tuple.gnur)) {
@@ -235,19 +255,18 @@ public final class RBuiltinCheck {
         if (show.size() > 1) {
             System.out.println(prefix + header);
         }
-
         return "\n\n";
     }
 
     private static Set<String> keysWithout(Map<String, BuiltinInfo> map, Set<String> both) {
-        Set<String> mapOnly = new HashSet<>(map.keySet());
+        Set<String> mapOnly = new TreeSet<>(map.keySet());
         mapOnly.removeAll(both);
         return mapOnly;
     }
 
     private static Map<String, BuiltinInfo> extractFastRBuiltins() {
         BasePackage base = new BasePackage();
-        HashMap<String, BuiltinInfo> result = new HashMap<>();
+        Map<String, BuiltinInfo> result = new TreeMap<>();
         for (Map.Entry<String, RBuiltinFactory> builtin : base.getBuiltins().entrySet()) {
             Class<?> clazz = builtin.getValue().getBuiltinNodeClass();
             RBuiltin annotation = clazz.getAnnotation(RBuiltin.class);
@@ -264,7 +283,7 @@ public final class RBuiltinCheck {
     private static Map<String, BuiltinInfo> extractGnuRBuiltins(String suiteDir) throws IOException {
         String content = Files.lines(Paths.get(suiteDir, DEFAULT_NAMESC)).collect(Collectors.joining("\n"));
         Matcher matcher = Pattern.compile(FUNTAB_REGEXP).matcher(content);
-        HashMap<String, BuiltinInfo> result = new HashMap<>();
+        Map<String, BuiltinInfo> result = new TreeMap<>();
         while (matcher.find()) {
             // normalize eval to three digits, e.g. '2' to '002'
             String eval = String.format("%1$3s", matcher.group("eval")).replace(' ', '0');
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index 573f4ba7708d8c65544061cb755aada2ce29520a..64a55c761c15eabae7c9761e45cb00f34680dfbf 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -572,7 +572,6 @@ com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_reg
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java,purdue.copyright
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java,purdue.copyright
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_repint.java,purdue.copyright
-com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_retracemem.java,purdue.copyright
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rev.java,purdue.copyright
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_round.java,purdue.copyright
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_row.java,purdue.copyright
diff --git a/mx.fastr/mx_fastr_pkgs.py b/mx.fastr/mx_fastr_pkgs.py
index eca0d4bf72f6bef420844c839831b5429417da48..334b4c3e9a4b935b38cb3e0ec3e621c681c5be02 100644
--- a/mx.fastr/mx_fastr_pkgs.py
+++ b/mx.fastr/mx_fastr_pkgs.py
@@ -133,7 +133,11 @@ def pkgtest(args):
 
     _log_step('BEGIN', 'install/test', 'FastR')
     # Currently installpkgs does not set a return code (in install.cran.packages.R)
-    mx_fastr._installpkgs(stacktrace_args + install_args, nonZeroIsFatal=False, env=env, out=out, err=out)
+    rc = mx_fastr._installpkgs(stacktrace_args + install_args, nonZeroIsFatal=False, env=env, out=out, err=out)
+    if rc == 100:
+        # fatal error connecting to package repo
+        mx.abort(rc)
+
     rc = 0
     for status in out.install_status.itervalues():
         if not status:
@@ -186,7 +190,7 @@ def _get_test_outputs(suite, pkg_name, test_info):
             test_info[pkg_name] = TestStatus()
         for f in files:
             ext = os.path.splitext(f)[1]
-            if ext == '.R' or ext == '.prev':
+            if f == 'test_time' or ext == '.R' or ext == '.prev':
                 continue
             # suppress .pdf's for now (we can't compare them)
             if ext == '.pdf':
@@ -265,26 +269,37 @@ def _set_test_status(fastr_test_info):
         gnur_outputs = gnur_test_status.testfile_outputs
         fastr_outputs = fastr_test_status.testfile_outputs
         if _failed_outputs(gnur_outputs):
+            # What this likely means is that some native package is not
+            # installed on the system so GNUR can't run the tests.
+            # Ideally this never happens.
             print "{0}: GnuR test had .fail outputs".format(pkg)
-            continue
 
         if _failed_outputs(fastr_outputs):
+            # In addition to the similar comment for GNU R, this can happen
+            # if, say, the JVM crashes (possible with native code packages)
             print "{0}: FastR test had .fail outputs".format(pkg)
             fastr_test_status.status = "FAILED"
-            continue
-
 
+        # Now for each successful GNU R output we compare content (assuming FastR didn't fail)
         for gnur_test_output_relpath, gnur_testfile_status in gnur_outputs.iteritems():
+            # Can't compare if either GNUR or FastR failed
+            if gnur_testfile_status.status == "FAILED":
+                break
+
             if not gnur_test_output_relpath in fastr_outputs:
+                # FastR crashed on this test
                 fastr_test_status.status = "FAILED"
                 print "{0}: FastR is missing output file: {1}".format(pkg, gnur_test_output_relpath)
                 break
 
+            fastr_testfile_status = fastr_outputs[gnur_test_output_relpath]
+            if fastr_testfile_status.status == "FAILED":
+                break
+
             gnur_content = None
             with open(gnur_testfile_status.abspath) as f:
                 gnur_content = f.readlines()
             fastr_content = None
-            fastr_testfile_status = fastr_outputs[gnur_test_output_relpath]
             with open(fastr_testfile_status.abspath) as f:
                 fastr_content = f.readlines()
 
@@ -295,11 +310,27 @@ def _set_test_status(fastr_test_info):
                 break
             if result != 0:
                 fastr_test_status.status = "FAILED"
+                fastr_testfile_status.status = "FAILED"
                 print "{0}: FastR output mismatch: {1}".format(pkg, gnur_test_output_relpath)
                 break
         # we started out as UNKNOWN
         if not (fastr_test_status.status == "INDETERMINATE" or fastr_test_status.status == "FAILED"):
             fastr_test_status.status = "OK"
+
+        # write out a file with the test status for each output (that exists)
+        with open(join(_pkg_testdir('fastr', pkg), 'testfile_status'), 'w') as f:
+            for fastr_relpath, fastr_testfile_status in fastr_outputs.iteritems():
+                if fastr_testfile_status.status == "FAILED":
+                    relpath = fastr_relpath + ".fail"
+                else:
+                    relpath = fastr_relpath
+
+                if os.path.exists(join(_pkg_testdir('fastr', pkg), relpath)):
+                    f.write(relpath)
+                    f.write(' ')
+                    f.write(fastr_testfile_status.status)
+                    f.write('\n')
+
         print 'END checking ' + pkg
 
 def _find_start(content):