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 2aee7bbaeef69511475db90a308ac8f440a828aa..5267b65c3b23ac7727aa16c60915587ba23389b8 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
@@ -47,6 +47,8 @@ import com.oracle.truffle.r.nodes.access.WriteVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinRootNode;
+import com.oracle.truffle.r.nodes.builtin.base.printer.ComplexVectorPrinter;
+import com.oracle.truffle.r.nodes.builtin.base.printer.DoubleVectorPrinter;
 import com.oracle.truffle.r.nodes.builtin.helpers.DebugHandling;
 import com.oracle.truffle.r.nodes.builtin.helpers.TraceHandling;
 import com.oracle.truffle.r.nodes.control.AbstractLoopNode;
@@ -71,6 +73,7 @@ import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributes;
+import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
@@ -714,4 +717,23 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
         return new IORedirect(in, out, newArgs, intern);
     }
 
+    @Override
+    public String encodeDouble(double x) {
+        return DoubleVectorPrinter.encodeReal(x);
+    }
+
+    @Override
+    public String encodeDouble(double x, int digits) {
+        return DoubleVectorPrinter.encodeReal(x, digits);
+    }
+
+    @Override
+    public String encodeComplex(RComplex x) {
+        return ComplexVectorPrinter.encodeComplex(x);
+    }
+
+    @Override
+    public String encodeComplex(RComplex x, int digits) {
+        return ComplexVectorPrinter.encodeComplex(x, digits);
+    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java
index 1cb213af8065802d15446d51a0093fe075200556..24a85cc03ca859cd643b520a2a2cbf5e50d267bb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java
@@ -11,7 +11,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
@@ -30,6 +30,7 @@ import com.oracle.truffle.r.nodes.unary.PrecedenceNodeGen;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -646,7 +647,15 @@ public abstract class Unlist extends RBuiltinNode {
     }
 
     private static String unlistValueString(Object cur) {
-        return RRuntime.toString(cur);
+        if (cur instanceof Double) {
+            Double d = (Double) cur;
+            return RRuntime.isNAorNaN(d) ? RRuntime.STRING_NA : RContext.getRRuntimeASTAccess().encodeDouble(d);
+        } else if (cur instanceof RComplex) {
+            RComplex c = (RComplex) cur;
+            return c.isNA() ? RRuntime.STRING_NA : RContext.getRRuntimeASTAccess().encodeComplex(c);
+        } else {
+            return RRuntime.toString(cur);
+        }
     }
 
     private static RComplex unlistValueComplex(Object dataAtAsObject) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
index 17d2397e93d1a4f6d8f7edc6d47285bca92f0fdb..1b9e62e6a76dad2cb79ff9cfaed48f74f2432fbe 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
@@ -70,7 +70,6 @@ import com.oracle.truffle.r.library.utils.ObjectSizeNodeGen;
 import com.oracle.truffle.r.library.utils.RprofNodeGen;
 import com.oracle.truffle.r.library.utils.RprofmemNodeGen;
 import com.oracle.truffle.r.library.utils.TypeConvertNodeGen;
-import com.oracle.truffle.r.library.utils.WriteTable;
 import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
 import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/WriteTable.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java
similarity index 96%
rename from com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/WriteTable.java
rename to com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java
index 0565887ef245b76273e32b4221d709b9a412a143..0ecf5afe88050f58b605bd30874151ae7e046d87 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/WriteTable.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java
@@ -9,12 +9,14 @@
  *
  * All rights reserved.
  */
-package com.oracle.truffle.r.library.utils;
+package com.oracle.truffle.r.nodes.builtin.base.foreign;
 
 import java.io.IOException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.base.printer.ComplexVectorPrinter;
+import com.oracle.truffle.r.nodes.builtin.base.printer.DoubleVectorPrinter;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -178,7 +180,7 @@ public final class WriteTable extends RExternalBuiltinNode {
             return RRuntime.isNA(v) ? cna : RRuntime.intToStringNoCheck(v);
         } else if (o instanceof Double) {
             double v = (double) o;
-            return RRuntime.isNA(v) ? cna : RRuntime.doubleToStringNoCheck(v);
+            return RRuntime.isNA(v) ? cna : DoubleVectorPrinter.encodeReal(v);
         } else if (o instanceof Byte) {
             byte v = (byte) o;
             return RRuntime.isNA(v) ? cna : RRuntime.logicalToStringNoCheck(v);
@@ -187,7 +189,7 @@ public final class WriteTable extends RExternalBuiltinNode {
             return RRuntime.isNA(v) ? cna : encodeStringElement(v, quote, qmethod);
         } else if (o instanceof Double) {
             RComplex v = (RComplex) o;
-            return RRuntime.isNA(v) ? cna : RRuntime.complexToStringNoCheck(v);
+            return RRuntime.isNA(v) ? cna : ComplexVectorPrinter.encodeComplex(v);
         } else if (o instanceof RRaw) {
             RRaw v = (RRaw) o;
             return RRuntime.rawToHexString(v);
@@ -217,7 +219,7 @@ public final class WriteTable extends RExternalBuiltinNode {
     private static String encodeElement(Object x, int indx, char quote, char dec) {
         if (x instanceof RAbstractDoubleVector) {
             RAbstractDoubleVector v = (RAbstractDoubleVector) x;
-            return RRuntime.doubleToString(v.getDataAt(indx));
+            return DoubleVectorPrinter.encodeReal(v.getDataAt(indx));
         }
         if (x instanceof RAbstractIntVector) {
             RAbstractIntVector v = (RAbstractIntVector) x;
@@ -229,7 +231,7 @@ public final class WriteTable extends RExternalBuiltinNode {
         }
         if (x instanceof RAbstractComplexVector) {
             RAbstractComplexVector v = (RAbstractComplexVector) x;
-            return RRuntime.complexToString(v.getDataAt(indx));
+            return ComplexVectorPrinter.encodeComplex(v.getDataAt(indx));
         }
         if (x instanceof RAbstractRawVector) {
             RAbstractRawVector v = (RAbstractRawVector) x;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
index 56d6c09685ce52d14ac9616075be31cdd5a6c7c9..15352ca9f5bdfa85d3835edf7446cacc1f9352bd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java
@@ -26,7 +26,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 
 //Transcribed from GnuR, src/main/printutils.c
 
-final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
+public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
 
     static final ComplexVectorPrinter INSTANCE = new ComplexVectorPrinter();
 
@@ -73,7 +73,13 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
         }
     }
 
+    @TruffleBoundary
     static ComplexVectorMetrics formatComplexVector(RAbstractComplexVector x, int offs, int n, int nsmall, PrintParameters pp) {
+        return formatComplexVector(x, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth());
+    }
+
+    @TruffleBoundary
+    static ComplexVectorMetrics formatComplexVector(RAbstractComplexVector x, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) {
 
         int wr;
         int dr;
@@ -129,7 +135,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
             } else {
                 /* real part */
 
-                tmp = zprecr(xi, pp.getDigits());
+                tmp = zprecr(xi, digits);
 
                 if (!RRuntime.isFinite(tmp.getRealPart())) {
                     if (RRuntime.isNAorNaN(tmp.getRealPart())) {
@@ -143,7 +149,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
                     if (xi.getRealPart() != 0) {
                         allReZero = false;
                     }
-                    ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getRealPart(), pp);
+                    ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getRealPart(), digits);
 
                     left = sd.kpower + 1;
                     if (sd.roundingwidens) {
@@ -187,7 +193,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
                     if (xi.getImaginaryPart() != 0) {
                         allImZero = false;
                     }
-                    ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getImaginaryPart(), pp);
+                    ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getImaginaryPart(), digits);
 
                     left = sd.kpower + 1;
                     if (sd.roundingwidens) {
@@ -221,7 +227,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
 
         /* overall format for real part */
 
-        if (pp.getDigits() == 0) {
+        if (digits == 0) {
             rt = 0;
         }
         if (mxl != RRuntime.INT_MIN_VALUE) {
@@ -245,7 +251,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
 
         /* overall format for imaginary part */
 
-        if (pp.getDigits() == 0) {
+        if (digits == 0) {
             irt = 0;
         }
         if (imxl != RRuntime.INT_MIN_VALUE) {
@@ -271,7 +277,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
         if (allReZero) {
             er = dr = 0;
             wr = wF;
-            if (iwF <= wi + pp.getScipen()) {
+            if (iwF <= wi + sciPen) {
                 ei = 0;
                 if (nsmall > irt) {
                     irt = nsmall;
@@ -281,7 +287,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
                 wi = iwF;
             }
         } else if (allImZero) {
-            if (wF <= wr + pp.getScipen()) {
+            if (wF <= wr + sciPen) {
                 er = 0;
                 if (nsmall > rt) {
                     rt = nsmall;
@@ -292,7 +298,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
             }
             ei = di = 0;
             wi = iwF;
-        } else if (wF + iwF < wr + wi + 2 * pp.getScipen()) {
+        } else if (wF + iwF < wr + wi + 2 * sciPen) {
             er = 0;
             if (nsmall > rt) {
                 rt = nsmall;
@@ -335,8 +341,8 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
 
         /* finally, ensure that there is space for NA */
 
-        if (naflag && wr + wi + 2 < pp.getNaWidth()) {
-            wr += (pp.getNaWidth() - (wr + wi + 2));
+        if (naflag && wr + wi + 2 < naWidth) {
+            wr += (naWidth - (wr + wi + 2));
         }
 
         return new ComplexVectorMetrics(wr, dr, er, wi, di, ei);
@@ -383,12 +389,33 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
         }
     }
 
+    @TruffleBoundary
+    public static String encodeComplex(RComplex x) {
+        return encodeComplex(x, 15, 0, RRuntime.STRING_NA);
+    }
+
+    @TruffleBoundary
+    public static String encodeComplex(RComplex x, int digits) {
+        return encodeComplex(x, digits, 0, RRuntime.STRING_NA);
+    }
+
+    @TruffleBoundary
+    public static String encodeComplex(RComplex x, int digits, int sciPen, String naString) {
+        ComplexVectorMetrics cvm = formatComplexVector(x, 0, 1, 0, digits, sciPen, naString.length());
+        return encodeComplex(x, cvm, digits, naString);
+    }
+
     @TruffleBoundary
     static String encodeComplex(RComplex x, ComplexVectorMetrics cvm, PrintParameters pp) {
+        return encodeComplex(x, cvm, pp.getDigits(), pp.getNaString());
+    }
+
+    @TruffleBoundary
+    static String encodeComplex(RComplex x, ComplexVectorMetrics cvm, int digits, String naString) {
         if (RRuntime.isNA(x.getRealPart()) || RRuntime.isNA(x.getImaginaryPart())) {
-            return DoubleVectorPrinter.encodeReal(RRuntime.DOUBLE_NA, cvm.maxWidth, 0, 0, '.', pp);
+            return DoubleVectorPrinter.encodeReal(RRuntime.DOUBLE_NA, cvm.maxWidth, 0, 0, '.', naString);
         } else {
-            String s = encodeComplex(x, cvm.wr, cvm.dr, cvm.er, cvm.wi, cvm.di, cvm.ei, '.', pp);
+            String s = encodeComplex(x, cvm.wr, cvm.dr, cvm.er, cvm.wi, cvm.di, cvm.ei, '.', digits, naString);
             int g = cvm.maxWidth - cvm.wr - cvm.wi - 2;
             if (g > 0) {
                 // fill the remaining space by blanks to fit the maxWidth
@@ -399,7 +426,8 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
         }
     }
 
-    private static String encodeComplex(RComplex x, int wr, int dr, int er, int wi, int di, int ei, char cdec, PrintParameters pp) {
+    @TruffleBoundary
+    private static String encodeComplex(RComplex x, int wr, int dr, int er, int wi, int di, int ei, char cdec, int digits, String naString) {
         String buff;
         String im;
         String re;
@@ -422,27 +450,27 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> {
             String fmt = "%" + Utils.asBlankArg(g) + "s";
             buff = Utils.snprintf(NB,
                             fmt, /* was "%*s%*s", R_print.gap, "", */
-                            pp.getNaString());
+                            naString);
         } else {
             /*
              * formatComplex rounded, but this does not, and we need to keep it that way so we don't
              * get strange trailing zeros. But we do want to avoid printing small exponentials that
              * are probably garbage.
              */
-            y = zprecr(x, pp.getDigits());
+            y = zprecr(x, digits);
             if (y.getRealPart() == 0.) {
-                re = DoubleVectorPrinter.encodeReal(y.getRealPart(), wr, dr, er, cdec, pp);
+                re = DoubleVectorPrinter.encodeReal(y.getRealPart(), wr, dr, er, cdec, naString);
             } else {
-                re = DoubleVectorPrinter.encodeReal(xr, wr, dr, er, cdec, pp);
+                re = DoubleVectorPrinter.encodeReal(xr, wr, dr, er, cdec, naString);
             }
             flagNegIm = xi < 0;
             if (flagNegIm) {
                 xi = -xi;
             }
             if (y.getImaginaryPart() == 0.) {
-                im = DoubleVectorPrinter.encodeReal(y.getImaginaryPart(), wi, di, ei, cdec, pp);
+                im = DoubleVectorPrinter.encodeReal(y.getImaginaryPart(), wi, di, ei, cdec, naString);
             } else {
-                im = DoubleVectorPrinter.encodeReal(xi, wi, di, ei, cdec, pp);
+                im = DoubleVectorPrinter.encodeReal(xi, wi, di, ei, cdec, naString);
             }
             buff = snprintf(NB, "%s%s%si", re, flagNegIm ? "-" : "+", im);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
index 9acc68d1a2382a4786ab5f8e528b1dd7bf1c0b02..3bec697593cce250ab55be0995abc261d476d914 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
@@ -19,11 +19,12 @@ import java.text.DecimalFormat;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 
 //Transcribed from GnuR, src/main/format.c
 
-final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
+public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
 
     static final DoubleVectorPrinter INSTANCE = new DoubleVectorPrinter();
 
@@ -70,7 +71,13 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
         }
     }
 
+    @TruffleBoundary
     static DoubleVectorMetrics formatDoubleVector(RAbstractDoubleVector x, int offs, int n, int nsmall, PrintParameters pp) {
+        return formatDoubleVector(x, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth());
+    }
+
+    @TruffleBoundary
+    static DoubleVectorMetrics formatDoubleVector(RAbstractDoubleVector x, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) {
         int left;
         int right;
         int sleft;
@@ -116,7 +123,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
                     neginf = true;
                 }
             } else {
-                ScientificDouble sd = scientific(xi, pp);
+                ScientificDouble sd = scientific(xi, digits);
                 sgn = sd.sgn;
                 nsig = sd.nsig;
                 kpower = sd.kpower;
@@ -167,7 +174,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
 
         /*-- These 'mxsl' & 'rgt' are used in F Format
          * AND in the ____ if(.) "F" else "E" ___ below: */
-        if (pp.getDigits() == 0) {
+        if (digits == 0) {
             rgt = 0;
         }
         if (mxl < 0) {
@@ -185,7 +192,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
         if (mxns != RRuntime.INT_MIN_VALUE) {
             d = mxns - 1;
             w = neg + (d != 0 ? 1 : 1) + d + 4 + e; /* width for E format */
-            if (wF <= w + pp.getScipen()) { /* Fixpoint if it needs less space */
+            if (wF <= w + sciPen) { /* Fixpoint if it needs less space */
                 e = 0;
                 if (nsmall > rgt) {
                     rgt = nsmall;
@@ -199,8 +206,8 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
             d = 0;
             e = 0;
         }
-        if (naflag && w < pp.getNaWidth()) {
-            w = pp.getNaWidth();
+        if (naflag && w < naWidth) {
+            w = naWidth;
         }
         if (nanflag && w < 3) {
             w = 3;
@@ -243,7 +250,13 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
         }
     }
 
+    @TruffleBoundary
     public static ScientificDouble scientific(double x, PrintParameters pp) {
+        return scientific(x, pp.getDigits());
+    }
+
+    @TruffleBoundary
+    public static ScientificDouble scientific(double x, int digits) {
         /*
          * for a number x , determine sgn = 1_{x < 0} {0/1} kpower = Exponent of 10; nsig =
          * min(R_print.digits, #{significant digits of alpha}) roundingwidens = 1 if rounding causes
@@ -277,7 +290,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
                 r = x;
             }
 
-            if (pp.getDigits() >= DBL_DIG + 1) {
+            if (digits >= DBL_DIG + 1) {
                 // TODO:
                 // format_via_sprintf(r, pp.getDigits(), kpower, nsig);
                 roundingwidens = false;
@@ -285,8 +298,8 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
                 throw new UnsupportedOperationException();
             }
 
-            kp = (int) Math.floor(Math.log10(r)) - pp.getDigits() + 1; // r = |x|;
-                                                                       // 10^(kp + digits - 1) <= r
+            kp = (int) Math.floor(Math.log10(r)) - digits + 1; // r = |x|;
+                                                               // 10^(kp + digits - 1) <= r
 
             double rPrec = r;
             /* use exact scaling factor in double precision, if possible */
@@ -307,7 +320,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
             } else {
                 rPrec /= Math.pow(10, kp);
             }
-            if (rPrec < tbl[pp.getDigits()]) {
+            if (rPrec < tbl[digits]) {
                 rPrec *= 10.0;
                 kp--;
             }
@@ -317,8 +330,8 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
              */
             alpha = Math.round(rPrec);
 
-            nsig = pp.getDigits();
-            for (j = 1; j <= pp.getDigits(); j++) {
+            nsig = digits;
+            for (j = 1; j <= digits; j++) {
                 alpha /= 10.0;
                 if (alpha == Math.floor(alpha)) {
                     nsig--;
@@ -326,11 +339,11 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
                     break;
                 }
             }
-            if (nsig == 0 && pp.getDigits() > 0) {
+            if (nsig == 0 && digits > 0) {
                 nsig = 1;
                 kp += 1;
             }
-            kpower = kp + pp.getDigits() - 1;
+            kpower = kp + digits - 1;
 
             /*
              * Scientific format may do more rounding than fixed format, e.g. 9996 with 3 digits is
@@ -339,7 +352,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
              * decimal place that will be cut off by rounding
              */
 
-            int rgt = pp.getDigits() - kpower;
+            int rgt = digits - kpower;
             /* bound rgt by 0 and KP_MAX */
             rgt = rgt < 0 ? 0 : rgt > KP_MAX ? KP_MAX : rgt;
             double fuzz = 0.5 / tbl[1 + rgt];
@@ -351,12 +364,34 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
         return new ScientificDouble(sgn, kpower, nsig, roundingwidens);
     }
 
+    @TruffleBoundary
+    public static String encodeReal(double x) {
+        return encodeReal(x, 15, '.', 0, RRuntime.STRING_NA);
+    }
+
+    @TruffleBoundary
+    public static String encodeReal(double x, int digits) {
+        return encodeReal(x, digits, '.', 0, RRuntime.STRING_NA);
+    }
+
+    @TruffleBoundary
+    public static String encodeReal(double x, int digits, char cdec, int sciPen, String naString) {
+        DoubleVectorMetrics dm = formatDoubleVector(RDataFactory.createDoubleVectorFromScalar(x), 0, 1, 0, digits, sciPen, naString.length());
+        return encodeReal(x, dm.maxWidth, dm.d, dm.e, cdec, naString);
+    }
+
+    @TruffleBoundary
+    static String encodeReal(double initialX, int w, int d, int e, char cdec, PrintParameters pp) {
+        return encodeReal(initialX, w, d, e, cdec, pp.getNaString());
+    }
+
+    @TruffleBoundary
     static String encodeReal(double x, DoubleVectorMetrics dm, PrintParameters pp) {
         return encodeReal(x, dm.maxWidth, dm.d, dm.e, '.', pp);
     }
 
     @TruffleBoundary
-    static String encodeReal(double initialX, int w, int d, int e, char cdec, PrintParameters pp) {
+    static String encodeReal(double initialX, int w, int d, int e, char cdec, String naString) {
         final String buff;
         String fmt;
 
@@ -367,7 +402,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> {
             int numBlanks = Math.min(w, (NB - 1));
             String naFmt = "%" + Utils.asBlankArg(numBlanks) + "s";
             if (RRuntime.isNA(x)) {
-                buff = snprintf(NB, naFmt, pp.getNaString());
+                buff = snprintf(NB, naFmt, naString);
             } else if (RRuntime.isNAorNaN(x)) {
                 buff = snprintf(NB, naFmt, "NaN");
             } else if (x > 0) {
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinterTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f95c7b59a40636b8746370280ca2a8a9c6c441a2
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinterTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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.nodes.builtin.base.printer;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+
+import static org.junit.Assert.*;
+
+public class ComplexVectorPrinterTest {
+
+    @Test
+    public void testEncodeComplex() {
+        assertEquals("3.14159265358979e-05+3.1415926535898e-06i", ComplexVectorPrinter.encodeComplex(RDataFactory.createComplex(Math.PI / 100000, Math.PI / 1000000)));
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinterTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4dcf54e8d8e3539e7734cc94ac10627e23c33c19
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinterTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.nodes.builtin.base.printer;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class DoubleVectorPrinterTest {
+
+    @Test
+    public void testEncodeReal() {
+        assertEquals("3.14159265358979e-06", DoubleVectorPrinter.encodeReal(Math.PI / 1000000));
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
index 6081c9cfc972e118a0cd72c5e199b6273d543e6a..32609b425ad8f99ae3bd140603ac9f9100b8df44 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
@@ -43,6 +43,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
+import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @TypeSystemReference(RTypes.class)
 public abstract class ToStringNode extends RBaseNode {
@@ -51,6 +52,8 @@ public abstract class ToStringNode extends RBaseNode {
 
     @Child private ToStringNode recursiveToString;
 
+    private final NACheck naCheck = NACheck.create();
+
     private String toStringRecursive(Object o, boolean quotes, String separator) {
         if (recursiveToString == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -95,7 +98,8 @@ public abstract class ToStringNode extends RBaseNode {
     @SuppressWarnings("unused")
     @Specialization
     protected String toString(RComplex complex, boolean quotes, String separator) {
-        return complex.toString();
+        naCheck.enable(complex);
+        return naCheck.convertComplexToString(complex);
     }
 
     @SuppressWarnings("unused")
@@ -113,7 +117,8 @@ public abstract class ToStringNode extends RBaseNode {
     @SuppressWarnings("unused")
     @Specialization
     protected String toString(double operand, boolean quotes, String separator) {
-        return RRuntime.doubleToString(operand);
+        naCheck.enable(operand);
+        return naCheck.convertDoubleToString(operand);
     }
 
     @SuppressWarnings("unused")
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
index 5c1ead393e4781b7f14daf8e95bec62ef923e2f9..3ebe4d8f547d127781d537a5912b168f64349e53 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
@@ -11,8 +11,6 @@
  */
 package com.oracle.truffle.r.runtime;
 
-import java.util.Locale;
-
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.Truffle;
@@ -555,55 +553,6 @@ public class RRuntime {
         return isNAorNaN(d) ? createComplexNA() : double2complexNoCheck(d);
     }
 
-    @TruffleBoundary
-    public static String doubleToString(double operand, int digitsBehindDot) {
-        return isNA(operand) ? STRING_NA : doubleToStringNoCheck(operand, digitsBehindDot);
-    }
-
-    @TruffleBoundary
-    public static String doubleToStringNoCheck(double operand, int digitsBehindDot) {
-        if (doubleIsInt(operand)) {
-            return intToStringNoCheck((int) operand);
-        }
-        if (operand == Double.POSITIVE_INFINITY) {
-            return "Inf";
-        }
-        if (operand == Double.NEGATIVE_INFINITY) {
-            return "-Inf";
-        }
-        if (Double.isNaN(operand)) {
-            return STRING_NaN;
-        }
-
-        if (operand < 1000000000000L && ((long) operand) == operand) {
-            return Long.toString((long) operand);
-        }
-        if (operand > 1000000000000L) {
-            return String.format((Locale) null, "%.6e", operand);
-        }
-        // if (true || operand < 0.0001) {
-        // // not quite correct but better than nothing for now...
-        // return String.format((Locale) null, "%.22e", new BigDecimal(operand));
-        // }
-
-        // We want to print the number without scientific notation and without trailing zeros after
-        // the decimal point. This is achieved by setting the maximum digits to a large enough
-        // number.
-        java.text.DecimalFormat format = new java.text.DecimalFormat();
-        format.setMaximumIntegerDigits(32);
-        format.setMaximumFractionDigits(digitsBehindDot == -1 ? 32 : digitsBehindDot);
-        format.setGroupingUsed(false);
-        return format.format(operand);
-    }
-
-    public static String doubleToStringNoCheck(double operand) {
-        return doubleToStringNoCheck(operand, -1);
-    }
-
-    public static String doubleToString(double operand) {
-        return isNA(operand) ? STRING_NA : doubleToStringNoCheck(operand);
-    }
-
     public static int double2rawIntValue(double operand) {
         return isNA(operand) ? 0 : ((int) operand) & 0xFF;
     }
@@ -638,16 +587,6 @@ public class RRuntime {
         return isNA(c) ? LOGICAL_NA : complex2doubleNoCheck(c);
     }
 
-    @TruffleBoundary
-    public static String complexToStringNoCheck(RComplex operand) {
-        return doubleToString(operand.getRealPart()) + "+" + doubleToString(operand.getImaginaryPart()) + "i";
-    }
-
-    @TruffleBoundary
-    public static String complexToString(RComplex operand) {
-        return isNA(operand) ? STRING_NA : complexToStringNoCheck(operand);
-    }
-
     public static int complex2rawIntValue(RComplex c) {
         return isNA(c) ? 0 : ((int) c.getRealPart() & 0xFF);
     }
@@ -675,7 +614,7 @@ public class RRuntime {
         if (object instanceof Integer) {
             return intToString((int) object);
         } else if (object instanceof Double) {
-            return doubleToString((double) object);
+            return Double.toString((double) object);
         } else if (object instanceof Byte) {
             return logicalToString((byte) object);
         }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
index 2f6eb61eecf44b90869c336d42a9e507de7161c5..8b082d88f35f86ed2c9f88c0631680d4b96c5cdc 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
@@ -26,6 +26,7 @@ import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.r.runtime.context.Engine;
 import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -189,4 +190,12 @@ public interface RRuntimeASTAccess {
 
     Object rscriptMain(String[] args, String[] env, boolean intern);
 
+    String encodeDouble(double x);
+
+    String encodeDouble(double x, int digits);
+
+    String encodeComplex(RComplex x);
+
+    String encodeComplex(RComplex x, int digits);
+
 }
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 430be1e43025c645c81ffbb1c59aa6f756c8bee6..7f5c274b1b9251a317aa29aa46350dc5af3d7264 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
@@ -95,7 +95,7 @@ public final class RComplex extends RScalarVector implements RAbstractComplexVec
     @TruffleBoundary
     public String toString() {
         CompilerAsserts.neverPartOfCompilation();
-        return toString(RRuntime.doubleToString(realPart), RRuntime.doubleToString(imaginaryPart));
+        return toString(Double.toString(realPart), Double.toString(imaginaryPart));
     }
 
     public String toString(String realPartString, String imaginaryPartString) {
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 2b4e628ef8416530303763ffca4fce869cb62368..585753ac6fe8858cc44a94668e42df1ff2c63b24 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
@@ -102,7 +102,7 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract
 
     @Override
     public String toString() {
-        return toString(i -> RRuntime.complexToString(getDataAt(i)));
+        return toString(i -> getDataAt(i).toString());
     }
 
     @Override
@@ -136,11 +136,6 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract
         return RDataFactory.createComplexVector(data, isComplete(), newDimensions);
     }
 
-    @Override
-    protected String getDataAtAsString(int index) {
-        return getDataAt(index).toString();
-    }
-
     private RComplexVector updateDataAt(int i, RComplex right, NACheck rightNACheck) {
         assert !this.isShared();
         int index = i << 1;
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 1dff2eea8b12fc648242ff07d855683a2be82bdc..be3aaec3c9c8f8b69eb6a5403c0050cbbb345ed9 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
@@ -109,7 +109,7 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD
 
     @Override
     public String toString() {
-        return toString(i -> RRuntime.doubleToString(getDataAt(i)));
+        return toString(i -> Double.toString(getDataAt(i)));
     }
 
     @Override
@@ -148,11 +148,6 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD
         return RDataFactory.createDoubleVector(data, isComplete(), newDimensions);
     }
 
-    @Override
-    protected String getDataAtAsString(int index) {
-        return RRuntime.doubleToString(data[index]);
-    }
-
     public RDoubleVector updateDataAt(int i, double right, NACheck valueNACheck) {
         assert !this.isShared();
         data[i] = right;
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 86815064d0156426a33bfeab77b202596f7a532c..c1a53a35f6249ef756e29261fc3d67d3332fd8d7 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
@@ -114,7 +114,7 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect
 
     @Override
     public String toString() {
-        return toString(i -> RRuntime.doubleToString(getDataAt(i)));
+        return toString(i -> Double.toString(getDataAt(i)));
     }
 
     @Override
@@ -148,11 +148,6 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect
         return RDataFactory.createIntVector(data, isComplete(), newDimensions);
     }
 
-    @Override
-    protected String getDataAtAsString(int index) {
-        return RRuntime.intToString(this.getDataAt(index));
-    }
-
     public RIntVector updateDataAt(int i, int right, NACheck valueNACheck) {
         assert !this.isShared();
         data[i] = right;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
index d314603acd206c3a1518bd4b19492fc1005b7648..4ed316e9098910dadca1a832ced61ce207fdfee0 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
@@ -121,11 +121,6 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi
         return data[i];
     }
 
-    @Override
-    protected final String getDataAtAsString(int index) {
-        return RRuntime.toString(getDataAt(index));
-    }
-
     public final RListBase updateDataAt(int i, Object right, @SuppressWarnings("unused") NACheck rightNACheck) {
         assert !this.isShared() : "data in shared list must not be updated, make a copy";
         data[i] = right;
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 ba99c8c7c13e7ca8ee8ab42b5ac0ecf74117b2d3..f35b7730df0d7c173f5d7e682d4576b6213135bf 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
@@ -131,11 +131,6 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo
         return data[i];
     }
 
-    @Override
-    protected String getDataAtAsString(int index) {
-        return RRuntime.logicalToString(this.getDataAt(index));
-    }
-
     private RLogicalVector updateDataAt(int index, byte right, NACheck valueNACheck) {
         assert !this.isShared();
         data[index] = right;
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 f8759c7fcd5f3345f3bdc82e62181f311f506d6e..6fdbf806bf2d4e258c6eeb0d133dd3dc0ae0be9c 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
@@ -133,11 +133,6 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec
         return RDataFactory.createRawVector(data, newDimensions);
     }
 
-    @Override
-    protected String getDataAtAsString(int index) {
-        return getDataAt(index).toString();
-    }
-
     @Override
     public RRawVector materialize() {
         return this;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java
index 4e14abc37f594f943838ddaf141ae2fc393861c7..b4110bd81af1e69378fa0eff2b77030a7ef682ff 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
@@ -127,11 +127,6 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS
         return data[i];
     }
 
-    @Override
-    protected String getDataAtAsString(int index) {
-        return getDataAt(index);
-    }
-
     public RStringVector updateDataAt(int i, String right, NACheck rightNACheck) {
         if (this.isShared()) {
             throw RInternalError.shouldNotReachHere("update shared vector");
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 b29519d63f01d76f980ccef8c11ea8dd15e21a08..2768eba5bde538d2410ea087faf6eed0ee447056 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
@@ -648,8 +648,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         return internalVerify();
     }
 
-    protected abstract String getDataAtAsString(int index);
-
     protected abstract boolean internalVerify();
 
     /**
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RComplexToStringVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RComplexToStringVectorClosure.java
index 260c400e3bce2ba9be279445876cb6e99cf8c27b..136d4e7653c752a161f7afc5af630da51b1b6341 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RComplexToStringVectorClosure.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RComplexToStringVectorClosure.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.runtime.data.closures;
 
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
@@ -39,6 +40,6 @@ final class RComplexToStringVectorClosure extends RToStringVectorClosure impleme
         if (!vector.isComplete() && RRuntime.isNA(data)) {
             return RRuntime.STRING_NA;
         }
-        return RRuntime.complexToString(data);
+        return RContext.getRRuntimeASTAccess().encodeComplex(data);
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RDoubleToStringVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RDoubleToStringVectorClosure.java
index c1de5e4bf033f20c6c5dc4bc249cb610911a6488..6a7ce849bbba683617452959e842f43d5c849f60 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RDoubleToStringVectorClosure.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RDoubleToStringVectorClosure.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.runtime.data.closures;
 
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
@@ -38,7 +39,7 @@ final class RDoubleToStringVectorClosure extends RToStringVectorClosure implemen
         if (!vector.isComplete() && RRuntime.isNA(data)) {
             return RRuntime.STRING_NA;
         } else {
-            return RRuntime.doubleToStringNoCheck(data);
+            return RContext.getRRuntimeASTAccess().encodeDouble(data);
         }
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java
index 0650ab020183526a1a439aaa01fec703128bfb54..c83d7f930d9a00ae91f6dfed3e1b65d78bc83437 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java
@@ -29,6 +29,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -273,14 +274,14 @@ public final class NACheck {
         if (check(value)) {
             return RRuntime.STRING_NA;
         }
-        return RRuntime.doubleToStringNoCheck(value);
+        return RContext.getRRuntimeASTAccess().encodeDouble(value);
     }
 
     public String convertComplexToString(RComplex value) {
         if (check(value)) {
             return RRuntime.STRING_NA;
         }
-        return RRuntime.complexToStringNoCheck(value);
+        return RContext.getRRuntimeASTAccess().encodeComplex(value);
     }
 
     public double convertComplexToDouble(RComplex value, boolean warning) {
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index 64b8ada44c441c5737594ee00d9aa7df896a4d16..a320da9b757b0b923f6a4db32d79e5bbcf7c729b 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -52,7 +52,7 @@ com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.jav
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/ToolsText.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Menu.java,gnu_r.copyright
-com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/WriteTable.java,gnu_r.copyright
+com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java,gnu_r.copyright
 com.oracle.truffle.r.native/fficall/src/common/arithmetic_fastr.c,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.native/fficall/src/common/coerce_fastr.c,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.native/fficall/src/common/errors_fastr.c,gnu_r.core.copyright