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 635ec096266e654196e0ba316bf4b1b073197384..1416ca77c41feada5d35aee74e388cf51f641710 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
@@ -427,27 +427,14 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe
 
     @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;
-        boolean flagNegIm = false;
-        RComplex y;
-
-        double xr = x.getRealPart();
-        double xi = x.getImaginaryPart();
-
         /* IEEE allows signed zeros; strip these here */
-        if (xr == 0.0) {
-            xr = 0.0;
-        }
-        if (xi == 0.0) {
-            xi = 0.0;
-        }
+        double xr = RRuntime.normalizeZero(x.getRealPart());
+        double xi = RRuntime.normalizeZero(x.getImaginaryPart());
 
         if (RRuntime.isNA(xr) || RRuntime.isNA(xi)) {
             int g = Math.min(wr + wi + 2, (NB - 1));
             String fmt = "%" + Utils.asBlankArg(g) + "s";
-            buff = Utils.snprintf(NB,
+            return Utils.snprintf(NB,
                             fmt, /* was "%*s%*s", R_print.gap, "", */
                             naString);
         } else {
@@ -456,24 +443,25 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe
              * get strange trailing zeros. But we do want to avoid printing small exponentials that
              * are probably garbage.
              */
-            y = zprecr(x, digits);
+            RComplex y = zprecr(x, digits);
+            String re;
             if (y.getRealPart() == 0.) {
                 re = DoubleVectorPrinter.encodeReal(y.getRealPart(), wr, dr, er, cdec, naString);
             } else {
                 re = DoubleVectorPrinter.encodeReal(xr, wr, dr, er, cdec, naString);
             }
-            flagNegIm = xi < 0;
+            boolean flagNegIm = xi < 0;
             if (flagNegIm) {
                 xi = -xi;
             }
+            String im;
             if (y.getImaginaryPart() == 0.) {
                 im = DoubleVectorPrinter.encodeReal(y.getImaginaryPart(), wi, di, ei, cdec, naString);
             } else {
                 im = DoubleVectorPrinter.encodeReal(xi, wi, di, ei, cdec, naString);
             }
-            buff = snprintf(NB, "%s%s%si", re, flagNegIm ? "-" : "+", im);
+            return snprintf(NB, "%s%s%si", re, flagNegIm ? "-" : "+", im);
         }
-        return buff;
     }
 
     public static String[] format(RAbstractComplexVector value, boolean trim, int nsmall, int width, char decimalMark, PrintParameters pp) {
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 9ee413f6e6f9a50696f92847f6361c4628c1038d..d3ebedd8fe3c597764ce73f4e78956df9d057640 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
@@ -11,11 +11,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base.printer;
 
-import static com.oracle.truffle.r.nodes.builtin.base.printer.Utils.snprintf;
-
 import java.io.IOException;
-import java.math.RoundingMode;
-import java.text.DecimalFormat;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -312,9 +308,9 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
                  * assumption that R_dec_min_exponent+303 is in range. Representation of 1e+303 has
                  * low error.
                  */
-                rPrec = (rPrec * 1e+303) / Math.pow(10, kp + 303);
+                rPrec = (rPrec * 1e+303) / DECIMAL_WEIGHTS[kp + 303 + DECIMAL_SHIFT];
             } else {
-                rPrec /= Math.pow(10, kp);
+                rPrec /= DECIMAL_WEIGHTS[kp + DECIMAL_SHIFT];
             }
             if (rPrec < tbl[digits]) {
                 rPrec *= 10.0;
@@ -354,7 +350,6 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
             double fuzz = 0.5 / tbl[1 + rgt];
             // kpower can be bigger than the table.
             roundingwidens = kpower > 0 && kpower <= KP_MAX && r < tbl[kpower + 1] - fuzz;
-
         }
 
         return new ScientificDouble(sgn, kpower, nsig, roundingwidens);
@@ -386,14 +381,27 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
         return encodeReal(x, dm.maxWidth, dm.d, dm.e, '.', pp);
     }
 
-    // caching some commonly used formats
-    private static final DecimalFormat[] CACHED_FORMATS = new DecimalFormat[32];
+    private static final int DECIMAL_SHIFT = 350;
+    private static final double[][] DECIMAL_VALUES = new double[700][10];
+    private static final double[] DECIMAL_WEIGHTS = new double[700];
+
+    static {
+        for (int i = 0; i < DECIMAL_WEIGHTS.length; i++) {
+            DECIMAL_WEIGHTS[i] = Math.pow(10, i - DECIMAL_SHIFT);
+        }
+        for (int i = 0; i < DECIMAL_VALUES.length; i++) {
+            for (int i2 = 0; i2 < 10; i2++) {
+                DECIMAL_VALUES[i][i2] = Math.pow(10, i - DECIMAL_SHIFT) * i2;
+            }
+        }
+    }
 
     @TruffleBoundary
     static String encodeReal(double initialX, int w, int d, int e, char cdec, String naString) {
         /* IEEE allows signed zeros (yuck!) */
         double x = RRuntime.normalizeZero(initialX);
 
+        StringBuilder str = new StringBuilder(w);
         if (!RRuntime.isFinite(x)) {
             String id;
             if (RRuntime.isNA(x)) {
@@ -403,49 +411,120 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
             } else {
                 id = x > 0 ? "Inf" : "-Inf";
             }
-            return prependBlanks(w, id);
-        } else if (e != 0) {
-            String fmt = String.format((d != 0) ? "%%#%d.%de" : "%%%d.%de", Math.min(w, (NB - 1)), d);
-            String result;
-            if (Math.abs(x) < 1e-300 && Math.abs(x) >= Double.MIN_VALUE) {
-                // work around java formatting bug for small numbers like 1.53160350210786e-322
-                result = snprintf(NB, fmt, x * 1e100);
-                StringBuilder str = new StringBuilder(result);
-                assert str.charAt(str.length() - 3) == '2';
-                str.setCharAt(str.length() - 3, '3');
-                result = str.toString();
-            } else {
-                result = snprintf(NB, fmt, x);
+            int blanks = w - id.length();
+            for (int i = 0; i < blanks; i++) {
+                str.append(' ');
             }
-            return result.replace('.', cdec);
-        } else { /* e = 0 */
-            DecimalFormat df = null;
-            if (d < CACHED_FORMATS.length) {
-                df = CACHED_FORMATS[d];
+            str.append(id);
+        } else {
+            boolean negated = x < 0;
+            if (negated) {
+                x = -x;
             }
-            if (df == null) {
-                df = new DecimalFormat("#.#");
-                df.setRoundingMode(RoundingMode.HALF_EVEN);
-                df.setDecimalSeparatorAlwaysShown(false);
-                df.setMinimumFractionDigits(d);
-                df.setMaximumFractionDigits(d);
-                if (d < CACHED_FORMATS.length) {
-                    CACHED_FORMATS[d] = df;
+            if (e != 0) {
+
+                boolean shifted = false;
+                int log10;
+                int adjustedE = e;
+                if (x == 0) {
+                    log10 = 0;
+                } else {
+                    if (x < 1e-300) {
+                        shifted = true;
+                        x *= 1e100;
+                    }
+                    log10 = (int) Math.log10(x);
+                    if (DECIMAL_WEIGHTS[log10 + DECIMAL_SHIFT] > x) {
+                        // log10 behaves differently for < 1.0
+                        log10--;
+                    }
+                    if (log10 <= -100 || log10 >= 100) {
+                        adjustedE = 3;
+                    }
+                }
+                int blanks = w // target width
+                                - (negated ? 1 : 0) // "-"
+                                - 1 // digits before "."
+                                - (d > 0 ? 1 : 0)  // "."
+                                - d // digits after "."
+                                - 1 // "e"
+                                - 1 // "+/-" for exponent
+                                - Math.max(2, adjustedE); // digits for exponent
+                for (int i = 0; i < blanks; i++) {
+                    str.append(' ');
+                }
+                // round towards next digit instead of truncating
+                double rounded = x + DECIMAL_VALUES[log10 - d - 1 + DECIMAL_SHIFT][5];
+                if (Double.isFinite(rounded)) {
+                    x = rounded;
+                    // the rounding might have modified the exponent
+                    if (DECIMAL_WEIGHTS[log10 + 1 + DECIMAL_SHIFT] <= x) {
+                        log10++;
+                    }
+                }
+                if (negated) {
+                    str.append('-');
+                }
+                x = appendDigit(x, log10, str);
+                if (d > 0) {
+                    str.append(cdec);
+                    for (int i = 1; i <= d; i++) {
+                        x = appendDigit(x, log10 - i, str);
+                    }
+                }
+                str.append('e');
+                if (log10 < 0) {
+                    str.append('-');
+                    log10 = -log10;
+                } else {
+                    str.append('+');
+                }
+                if (shifted) {
+                    log10 += 100;
+                }
+                if (adjustedE >= 3) {
+                    str.append((char) ('0' + (log10 / 100)));
+                    log10 = log10 % 100;
+                }
+                str.append((char) ('0' + (log10 / 10)));
+                str.append((char) ('0' + (log10 % 10)));
+            } else { /* e == 0 */
+                // round towards next digit instead of truncating
+                x += DECIMAL_VALUES[-d - 1 + DECIMAL_SHIFT][5];
+
+                int log10 = x == 0 ? 0 : Math.max((int) Math.log10(x), 0);
+                int blanks = w // target width
+                                - (negated ? 1 : 0) // "-"
+                                - (log10 + 1) // digits before "."
+                                - (d > 0 ? 1 : 0) // "."
+                                - d; // digits after "."
+
+                for (int i = 0; i < blanks; i++) {
+                    str.append(' ');
+                }
+                if (negated) {
+                    str.append('-');
+                }
+                for (int i = log10; i >= 0; i--) {
+                    x = appendDigit(x, i, str);
+                }
+                if (d > 0) {
+                    str.append(cdec);
+                    for (int i = 1; i <= d; i++) {
+                        x = appendDigit(x, -i, str);
+                    }
                 }
             }
-            return prependBlanks(w, df.format(x)).replace('.', cdec);
         }
+        assert str.length() >= w;
+        return str.toString();
     }
 
-    private static String prependBlanks(int width, String id) {
-        if (id.length() >= width) {
-            return id;
-        }
-        StringBuilder str = new StringBuilder(width);
-        for (int i = 0; i < width - id.length(); i++) {
-            str.append(' ');
-        }
-        return str.append(id).toString();
+    private static double appendDigit(double x, int digit, StringBuilder str) {
+        int c = (int) (x / DECIMAL_WEIGHTS[digit + DECIMAL_SHIFT]);
+        assert c >= 0 && c <= 9;
+        str.append((char) ('0' + c));
+        return x - DECIMAL_VALUES[digit + DECIMAL_SHIFT][c];
     }
 
     public static String[] format(RAbstractDoubleVector value, boolean trim, int nsmall, int width, char decimalMark, PrintParameters pp) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FormatMetrics.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FormatMetrics.java
index 052d4675874c6853669d8229963763e069e200ca..c0f020d91e9eaba2f3b4519c7d60493d2ef0c40b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FormatMetrics.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FormatMetrics.java
@@ -25,7 +25,7 @@ package com.oracle.truffle.r.nodes.builtin.base.printer;
 /**
  * The generic formatting metrics. N.B. This class is public since it is used in the PrettyWriter
  * public API.
- * 
+ *
  * @see PrettyWriter
  */
 public class FormatMetrics {
@@ -34,7 +34,6 @@ public class FormatMetrics {
     int maxWidth;
 
     FormatMetrics(int maxWidth) {
-        super();
         this.originalMaxWidth = maxWidth;
         this.maxWidth = maxWidth;
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java
index 5453a2fa40ab27cf826ab8da4ca2a6f58cda10b8..f9d0ea7c4f89cb0cf9b1470a644d0615fee0eed6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java
@@ -46,7 +46,7 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector
 
         @Override
         protected FormatMetrics formatVector(int offs, int len) {
-            return formatIntVector(vector, offs, len, printCtx.parameters().getNaWidth());
+            return new FormatMetrics(formatIntVectorInternal(vector, offs, len, printCtx.parameters().getNaWidth()));
         }
 
         @Override
@@ -66,7 +66,7 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector
         }
     }
 
-    public static FormatMetrics formatIntVector(RAbstractIntVector x, int offs, int n, int naWidth) {
+    static int formatIntVectorInternal(RAbstractIntVector x, int offs, int n, int naWidth) {
         int xmin = RRuntime.INT_MAX_VALUE;
         int xmax = RRuntime.INT_MIN_VALUE;
         boolean naflag = false;
@@ -105,21 +105,62 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector
                 fieldwidth = l;
             }
         }
+        return fieldwidth;
+    }
+
+    private static final int[][] DECIMAL_VALUES = new int[10][10];
+    private static final int[] DECIMAL_WEIGHTS = new int[10];
 
-        return new FormatMetrics(fieldwidth);
+    static {
+        for (int i = 0; i < DECIMAL_WEIGHTS.length; i++) {
+            DECIMAL_WEIGHTS[i] = (int) Math.pow(10, i);
+        }
+        for (int i = 0; i < DECIMAL_VALUES.length; i++) {
+            for (int i2 = 0; i2 < 10; i2++) {
+                DECIMAL_VALUES[i][i2] = (int) (Math.pow(10, i) * i2);
+            }
+        }
     }
 
-    /*
-     * There is no documented (or enforced) limit on 'w' here, so use snprintf
-     */
-    static int NB = 1000;
+    public static String encodeInteger(int initialX, int w, PrintParameters pp) {
+        StringBuilder str = new StringBuilder(w);
 
-    public static String encodeInteger(int x, int w, PrintParameters pp) {
-        if (x == RRuntime.INT_NA) {
-            return Utils.snprintf(NB, "%" + Utils.asBlankArg(Math.min(w, (NB - 1))) + "s", pp.getNaString());
+        int x = initialX;
+        if (RRuntime.isNA(x)) {
+            String id = pp.getNaString();
+            for (int i = w - id.length(); i > 0; i--) {
+                str.append(' ');
+            }
+            str.append(id);
         } else {
-            return Utils.snprintf(NB, "%" + Utils.asBlankArg(Math.min(w, (NB - 1))) + "d", x);
+            boolean negated = false;
+            if (x < 0) {
+                negated = true;
+                x = -x;
+            }
+            int log10 = x == 0 ? 0 : (int) Math.log10(x);
+            int blanks = w // target width
+                            - (negated ? 1 : 0) // "-"
+                            - (log10 + 1); // digits
+
+            for (int i = 0; i < blanks; i++) {
+                str.append(' ');
+            }
+            if (negated) {
+                str.append('-');
+            }
+            for (int i = log10; i >= 0; i--) {
+                x = appendDigit(x, i, str);
+            }
         }
+        return str.toString();
+    }
+
+    private static int appendDigit(int x, int digit, StringBuilder str) {
+        int c = x / DECIMAL_WEIGHTS[digit];
+        assert c >= 0 && c <= 9;
+        str.append((char) ('0' + c));
+        return x - DECIMAL_VALUES[digit][c];
     }
 
     public static String[] format(RAbstractIntVector value, boolean trim, int width, PrintParameters pp) {
@@ -127,8 +168,7 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector
         if (trim) {
             w = 1;
         } else {
-            FormatMetrics metrics = formatIntVector(value, 0, value.getLength(), pp.getNaWidth());
-            w = metrics.maxWidth;
+            w = formatIntVectorInternal(value, 0, value.getLength(), pp.getNaWidth());
         }
         w = Math.max(w, width);
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
index 3cde3e059f0377c95c9090efa054f8b38b05f3e0..143286861af82a99f79bd35bbf5d0f5d780dacc7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
@@ -78,8 +78,8 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
             } else if (tmp instanceof RAbstractLogicalVector) {
                 RAbstractLogicalVector lv = (RAbstractLogicalVector) tmp;
                 if (lv.getLength() == 1) {
-                    FormatMetrics fm = LogicalVectorPrinter.formatLogicalVector(lv, 0, 1, pp.getNaWidth());
-                    pbuf = LogicalVectorPrinter.encodeLogical(lv.getDataAt(0), fm.maxWidth, pp);
+                    int width = LogicalVectorPrinter.formatLogicalVectorInternal(lv, 0, 1, pp.getNaWidth());
+                    pbuf = LogicalVectorPrinter.encodeLogical(lv.getDataAt(0), width, pp);
                 } else {
                     pbuf = "Logical," + lv.getLength();
                 }
@@ -90,8 +90,8 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
                     pbuf = "factor," + iv.getLength();
                 } else {
                     if (iv.getLength() == 1) {
-                        FormatMetrics fm = IntegerVectorPrinter.formatIntVector(iv, 0, 1, pp.getNaWidth());
-                        pbuf = IntegerVectorPrinter.encodeInteger(iv.getDataAt(0), fm.maxWidth, pp);
+                        int width = IntegerVectorPrinter.formatIntVectorInternal(iv, 0, 1, pp.getNaWidth());
+                        pbuf = IntegerVectorPrinter.encodeInteger(iv.getDataAt(0), width, pp);
                     } else {
                         pbuf = "Integer," + iv.getLength();
                     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java
index 29231624992cce41ae975e5c03bbc1b88038f6fa..3421a15d5b01f989d577a8e5b274bea67a117002 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java
@@ -11,9 +11,6 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base.printer;
 
-import static com.oracle.truffle.r.nodes.builtin.base.printer.IntegerVectorPrinter.NB;
-import static com.oracle.truffle.r.nodes.builtin.base.printer.Utils.snprintf;
-
 import java.io.IOException;
 
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -47,13 +44,12 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe
 
         @Override
         protected FormatMetrics formatVector(int offs, int len) {
-            return formatLogicalVector(vector, offs, len, printCtx.parameters().getNaWidth());
+            return new FormatMetrics(formatLogicalVectorInternal(vector, offs, len, printCtx.parameters().getNaWidth()));
         }
 
         @Override
         protected void printElement(int i, FormatMetrics fm) throws IOException {
-            String v = encodeLogical(vector.getDataAt(i), fm.maxWidth, printCtx.parameters());
-            out.print(v);
+            out.print(encodeLogical(vector.getDataAt(i), fm.maxWidth, printCtx.parameters()));
         }
 
         @Override
@@ -67,7 +63,7 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe
         }
     }
 
-    static FormatMetrics formatLogicalVector(RAbstractLogicalVector x, int offs, int n, int naWidth) {
+    static int formatLogicalVectorInternal(RAbstractLogicalVector x, int offs, int n, int naWidth) {
         int fieldwidth = 1;
         for (int i = 0; i < n; i++) {
             byte xi = x.getDataAt(offs + i);
@@ -83,18 +79,29 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe
                 /* this is the widest it can be, so stop */
             }
         }
-        return new FormatMetrics(fieldwidth);
+        return fieldwidth;
     }
 
     static String encodeLogical(byte x, int w, PrintParameters pp) {
-        final String fmt = "%" + Utils.asBlankArg(Math.min(w, (NB - 1))) + "s";
+        String id;
         if (x == RRuntime.LOGICAL_NA) {
-            return snprintf(NB, fmt, pp.getNaString());
-        } else if (x != 0) {
-            return snprintf(NB, fmt, "TRUE");
+            id = pp.getNaString();
+        } else if (x != RRuntime.LOGICAL_FALSE) {
+            id = "TRUE";
         } else {
-            return snprintf(NB, fmt, "FALSE");
+            id = "FALSE";
+        }
+        if (id.length() == w) {
+            return id;
+        }
+        int blanks = w // target width
+                        - id.length(); // text
+        StringBuilder str = new StringBuilder();
+        for (int i = 0; i < blanks; i++) {
+            str.append(' ');
         }
+        str.append(id);
+        return str.toString();
     }
 
     public static String[] format(RAbstractLogicalVector value, boolean trim, int width, PrintParameters pp) {
@@ -102,8 +109,7 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe
         if (trim) {
             w = 1;
         } else {
-            FormatMetrics metrics = formatLogicalVector(value, 0, value.getLength(), pp.getNaWidth());
-            w = metrics.maxWidth;
+            w = formatLogicalVectorInternal(value, 0, value.getLength(), pp.getNaWidth());
         }
         w = Math.max(w, width);
 
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
index 94f637415f1fe568928a9a04b078e6e1ded0cad0..e7e235f3364dccf7ef83477e84354303437ac3d4 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
@@ -91,6 +91,7 @@ public class ParserGeneration {
         "different warning for hex and dec integer literals",
         "raise ZERO_LENGTH_VARIABLE errors in parser",
         "support for file delimiter",
-        "pass along TruffleRLanguage"
+        "pass along TruffleRLanguage",
+        "convert line endings"
     };
 }
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
index 9d70c927cee394c83f6d886ab6b652d75fea877f..2cfda4f041a34406cae79c0440ec0ed04bab8790 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
@@ -29,6 +29,10 @@ package com.oracle.truffle.r.parser;
 import java.util.ArrayList;
 import java.util.List;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.net.URISyntaxException;
 
 import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.api.frame.MaterializedFrame;
@@ -149,9 +153,15 @@ import com.oracle.truffle.r.runtime.RError;
 	    		if(q0 != -1 && q1 != -1) {
 	    			String path = commentLine.substring(q0+1, q1);
 	    			try {
-                        source = RSource.fromFileName(path, false);
+	    			    String content = new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8);
+	    			    String lineEnding = detectLineEnding(initialSource.getCode());
+	    			    content = convertToLineEnding(content, lineEnding);
+                        source = RSource.fromFileName(content, path, false);
                         fileStartOffset = commentToken.getStopIndex() + 1;
                     } catch (IOException e) {
+                    	resetSource();
+                    } catch (URISyntaxException e) {
+                    	resetSource();
                     }
 	    		} else {
 	    			// fall back and use the initial source (the file being parsed)
@@ -165,6 +175,25 @@ import com.oracle.truffle.r.runtime.RError;
 		fileStartOffset = 0;
 	}
 
+	private String detectLineEnding(String code) {
+		int lf = code.indexOf("\n");
+		int crlf = code.indexOf("\r\n");
+		
+		if(crlf != -1 && crlf < lf) {
+			return "\r\n";
+		}
+		return "\n";
+	}
+	
+	private String convertToLineEnding(String content, String lineEnding) {
+		if("\n".equals(lineEnding)) {
+			return content.replaceAll("\\r\\n", "\n");
+		} else if("\r\n".equals(lineEnding)) {
+			return content.replaceAll("\\n", "\r\n");
+		}
+		return content;
+	}
+
 	// without this override, the parser will not throw exceptions if it can recover    
     @Override
     protected Object recoverFromMismatchedToken(IntStream input, int expected, BitSet follow) throws RecognitionException {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateRConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateRConnection.java
index d43eeb8e783e736fc98265c4972b04c6e6cd8f68..79911c2ea1a89f89c83829060c0a7021336f1895 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateRConnection.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateRConnection.java
@@ -54,26 +54,40 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
  * </p>
  */
 abstract class DelegateRConnection implements RConnection, ByteChannel {
-    private static final int DEFAULT_CACHE_SIZE = 16 * 1024;
+    public static final int DEFAULT_CACHE_SIZE = 16 * 1024;
     protected final BaseRConnection base;
     private final ByteBuffer cache;
+    private final boolean readCache;
 
     DelegateRConnection(BaseRConnection base) {
-        this(base, DEFAULT_CACHE_SIZE);
+        this(base, DEFAULT_CACHE_SIZE, true);
     }
 
-    DelegateRConnection(BaseRConnection base, int cacheSize) {
+    DelegateRConnection(BaseRConnection base, int cacheSize, boolean readCache) {
         this.base = Objects.requireNonNull(base);
+        this.readCache = readCache;
 
         if (cacheSize > 0) {
             cache = ByteBuffer.allocate(cacheSize);
-            // indicate that there are no remaining bytes in the buffer
-            cache.flip();
+
+            // indicate that there are no remaining bytes in the buffer to read
+            if (readCache) {
+                cache.flip();
+            }
         } else {
             cache = null;
         }
     }
 
+    private static int transfer(ByteBuffer from, ByteBuffer to) {
+        int nbytes = Math.min(to.remaining(), from.remaining());
+        if (nbytes > 0) {
+            to.put(from.array(), from.arrayOffset() + from.position(), nbytes);
+            from.position(from.position() + nbytes);
+        }
+        return nbytes;
+    }
+
     @Override
     public int getDescriptor() {
         return base.getDescriptor();
@@ -438,7 +452,7 @@ abstract class DelegateRConnection implements RConnection, ByteChannel {
     @Override
     @TruffleBoundary
     public int read(ByteBuffer dst) throws IOException {
-        if (cache != null) {
+        if (readCache && cache != null) {
             final int bytesRequested = dst.remaining();
             int totalBytesRead = 0;
             int bytesToRead = 0;
@@ -459,7 +473,19 @@ abstract class DelegateRConnection implements RConnection, ByteChannel {
     @Override
     @TruffleBoundary
     public int write(ByteBuffer src) throws IOException {
-        return getChannel().write(src);
+        if (!readCache && cache != null) {
+            int total = 0;
+            while (src.hasRemaining()) {
+                total += transfer(src, cache);
+                if (!cache.hasRemaining()) {
+                    flush();
+                }
+            }
+            return total;
+        } else {
+            invalidateCache();
+            return getChannel().write(src);
+        }
     }
 
     /**
@@ -471,7 +497,7 @@ abstract class DelegateRConnection implements RConnection, ByteChannel {
      * </p>
      */
     protected int readInternal() throws IOException {
-        if (cache != null) {
+        if (readCache && cache != null) {
             ensureDataAvailable(1);
             if (!cache.hasRemaining()) {
                 return -1;
@@ -567,7 +593,11 @@ abstract class DelegateRConnection implements RConnection, ByteChannel {
 
     @Override
     public void flush() throws IOException {
-        // nothing to do for channels
+        if (!readCache && cache != null) {
+            cache.flip();
+            getChannel().write(cache);
+            cache.clear();
+        }
     }
 
     @Override
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadRConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadRConnection.java
index d4b11c2d5723c037e1839c5f26b05f31b6e98bb5..ba4245207dd183a0c38d76259ca6c078a764431e 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadRConnection.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadRConnection.java
@@ -38,7 +38,7 @@ public abstract class DelegateReadRConnection extends DelegateRConnection {
     }
 
     protected DelegateReadRConnection(BaseRConnection base, int cacheSize) {
-        super(base, cacheSize);
+        super(base, cacheSize, true);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadWriteRConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadWriteRConnection.java
index c445251b02495f80207f0c2507bcc046e64eadb9..01c2464bd6523b45e5ddf7ff394780b0c061a387 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadWriteRConnection.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateReadWriteRConnection.java
@@ -31,7 +31,7 @@ abstract class DelegateReadWriteRConnection extends DelegateRConnection {
     }
 
     protected DelegateReadWriteRConnection(BaseRConnection base, int cacheSize) {
-        super(base, cacheSize);
+        super(base, cacheSize, true);
     }
 
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateWriteRConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateWriteRConnection.java
index 16503501a0914f0e299d5e7c06f1eda99d0d4e88..f436a0a2f12b44520dafa0c0a63caff6467bde1a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateWriteRConnection.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/DelegateWriteRConnection.java
@@ -33,7 +33,11 @@ import com.oracle.truffle.r.runtime.conn.ConnectionSupport.BaseRConnection;
 abstract class DelegateWriteRConnection extends DelegateRConnection {
 
     protected DelegateWriteRConnection(BaseRConnection base) {
-        super(base, 0);
+        super(base, 0, false);
+    }
+
+    protected DelegateWriteRConnection(BaseRConnection base, int cacheSize) {
+        super(base, cacheSize, false);
     }
 
     @Override
@@ -75,4 +79,10 @@ abstract class DelegateWriteRConnection extends DelegateRConnection {
     public boolean canWrite() {
         return true;
     }
+
+    @Override
+    public void close() throws IOException {
+        flush();
+        super.close();
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java
index b14529c998dfd7df4fa202a0df4e432724a99b7c..36e4f8e3fc6c6f19d8ecf941678405190e11214c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java
@@ -324,7 +324,7 @@ public class FileConnections {
         private final FileChannel channel;
 
         FileWriteBinaryConnection(BasePathRConnection base, boolean append) throws IOException {
-            super(base);
+            super(base, 0);
             List<OpenOption> opts = new ArrayList<>();
             opts.add(StandardOpenOption.WRITE);
             opts.add(StandardOpenOption.CREATE);