diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java
index 217e5a92c015d088d6a94eff1c2b277a406dec3d..d79dbf56e66b9051831aae725ea8b5dea27ca9ec 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridColorUtils.java
@@ -18,8 +18,8 @@ import java.util.Map;
 import com.oracle.truffle.r.library.fastrGrid.GridState.GridPalette;
 import com.oracle.truffle.r.library.fastrGrid.device.GridColor;
 import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
@@ -96,10 +96,20 @@ public final class GridColorUtils {
     }
 
     public static String gridColorToRString(GridColor color) {
+        int size = color.getAlpha() == GridColor.OPAQUE_ALPHA ? 7 : 9;
+        char[] value = new char[size];
+        value[0] = '#';
+        value[1] = getHexDigit(color.getRed() >> 4);
+        value[2] = getHexDigit(color.getRed());
+        value[3] = getHexDigit(color.getGreen() >> 4);
+        value[4] = getHexDigit(color.getGreen());
+        value[5] = getHexDigit(color.getBlue() >> 4);
+        value[6] = getHexDigit(color.getBlue());
         if (color.getAlpha() == GridColor.OPAQUE_ALPHA) {
-            return String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue());
+            value[7] = getHexDigit((color.getAlpha()) >> 4);
+            value[8] = getHexDigit(color.getAlpha());
         }
-        return String.format("#%02x%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
+        return new String(value);
     }
 
     public static GridColor parseHex(String value) {
@@ -114,6 +124,12 @@ public final class GridColorUtils {
         return new GridColor(red, green, blue, alpha);
     }
 
+    private static final char[] HEX_DIGITS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+    public static char getHexDigit(int digit) {
+        return HEX_DIGITS[digit & 0xf];
+    }
+
     private static GridColor findByName(String synonym) {
         return (GridColor) NamesHolder.NAMES.get(normalizeColorName(synonym));
     }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridColor.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridColor.java
index ec11023ea1248c6471f9a92947c56543c8f91882..2472e266ca50ff0858821f00543dd620011c3ade 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridColor.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/GridColor.java
@@ -30,6 +30,7 @@ public final class GridColor {
     public static final int OPAQUE_ALPHA = 0xff;
     private static final int TRANSPARENT_ALPHA = 0;
     public static final GridColor TRANSPARENT = new GridColor(0, 0, 0, TRANSPARENT_ALPHA);
+    public static final GridColor BLACK = new GridColor(0, 0, 0, OPAQUE_ALPHA);
 
     private final int value;
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java
index 88bd8ff6fd6705e8f59eb7147063fb9be2182f0a..cd82ccda80a24cb1e6dbd302072400114130362b 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/SVGDevice.java
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.library.fastrGrid.device;
 
 import static com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.GRID_LINE_BLANK;
 import static com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.INCH_TO_POINTS_FACTOR;
+import static java.lang.Math.round;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -33,6 +34,7 @@ import java.text.DecimalFormat;
 import java.util.Base64;
 import java.util.Collections;
 
+import com.oracle.truffle.r.library.fastrGrid.GridColorUtils;
 import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.GridFontStyle;
 import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.GridLineEnd;
 import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.GridLineJoin;
@@ -67,11 +69,11 @@ public class SVGDevice implements GridDevice, FileGridDevice {
         // saving it anywhere.
         data.setLength(0);
         cachedCtx = null;
-        append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
-        append("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">");
-        append("<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' viewBox='0 0 %.3f %.3f'>",
-                        width * COORD_FACTOR,
-                        height * COORD_FACTOR);
+        data.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+        data.append("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
+        append("<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' viewBox='0 0 %d %d' style='fill:transparent'>\n",
+                        trRound(width),
+                        trRound(height));
     }
 
     @Override
@@ -89,47 +91,52 @@ public class SVGDevice implements GridDevice, FileGridDevice {
     @Override
     public void drawRect(DrawingContext ctx, double leftX, double bottomY, double newWidth, double newHeight, double rotationAnticlockWise) {
         appendStyle(ctx);
-        append("<rect x='%.3f' y='%.3f' width='%.3f' height='%.3f'", leftX * COORD_FACTOR, transY(bottomY + newHeight) * COORD_FACTOR, newWidth * COORD_FACTOR, newHeight * COORD_FACTOR);
+        data.append("<rect x='").append(trRound(leftX)).append("' y='").append(trRound(transY(bottomY + newHeight))).append("' width='").append(trRound(newWidth)).append("' height='").append(
+                        trRound(newHeight)).append('\'');
         if (rotationAnticlockWise != 0) {
-            append("transform='rotate(%.3f %.3f,%.3f)'", toDegrees(rotationAnticlockWise), (leftX + newWidth / 2.) * COORD_FACTOR, transY(bottomY + newHeight / 2.) * COORD_FACTOR);
+            appendTransform((int) round(toDegrees(rotationAnticlockWise)), trRound(leftX + newWidth / 2.), trRound(transY(bottomY + newHeight / 2.)));
         }
-        data.append("/>"); // end of 'rect' tag
+        appendColorStyle(ctx);
+        data.append("/>\n"); // end of 'rect' tag
     }
 
     @Override
     public void drawPolyLines(DrawingContext ctx, double[] x, double[] y, int startIndex, int length) {
-        drawPoly(ctx, x, y, startIndex, length, "style='fill:transparent'");
+        drawPoly(ctx, x, y, startIndex, length, true);
     }
 
     @Override
     public void drawPolygon(DrawingContext ctx, double[] x, double[] y, int startIndex, int length) {
-        drawPoly(ctx, x, y, startIndex, length, "");
+        drawPoly(ctx, x, y, startIndex, length, false);
     }
 
     @Override
     public void drawCircle(DrawingContext ctx, double centerX, double centerY, double radius) {
         appendStyle(ctx);
-        append("<circle cx='%.3f' cy='%.3f' r='%.3f'/>", centerX * COORD_FACTOR, transY(centerY) * COORD_FACTOR, radius * COORD_FACTOR);
+        data.append("<circle cx='").append(trRound(centerX)).append("' cy='").append(trRound(transY(centerY))).append("' r='").append(trRound(radius)).append('\'');
+        appendColorStyle(ctx);
+        data.append("/>\n");
     }
 
     @Override
     public void drawRaster(double leftX, double bottomY, double width, double height, int[] pixels, int pixelsColumnsCount, ImageInterpolation interpolation) {
         byte[] bitmap = Bitmap.create(pixels, pixelsColumnsCount);
         String base64 = Base64.getEncoder().encodeToString(bitmap);
-        append("<image x='%.3f' y='%.3f' width='%.3f' height='%.3f' preserveAspectRatio='none' xlink:href='data:image/bmp;base64,%s'/>", leftX * COORD_FACTOR, transY(bottomY + height) * COORD_FACTOR,
-                        width * COORD_FACTOR, height * COORD_FACTOR, base64);
+        data.append("<image x='").append(round(leftX * COORD_FACTOR)).append("' y='").append(trRound(transY(bottomY + height)));
+        data.append("' width='").append(round(width * COORD_FACTOR)).append("' height='").append(trRound(height));
+        data.append("' preserveAspectRatio='none' xlink:href='data:image/bmp;base64,").append(base64).append("'/>\n");
     }
 
     @Override
     public void drawString(DrawingContext ctx, double leftX, double bottomY, double rotationAnticlockWise, String text) {
         closeStyle();
-        append("<text x='%.3f' y='%.3f' textLength='%.3fpx' lengthAdjust='spacingAndGlyphs' ", leftX * COORD_FACTOR, transY(bottomY) * COORD_FACTOR, getStringWidth(ctx, text) * COORD_FACTOR);
-        // SVG interprets the "fill" as the color of the text
-        data.append("style='").append(getStyleColor("fill", ctx.getColor())).append('\'');
+        data.append("<text x='").append(round(leftX * COORD_FACTOR)).append("' y='").append(trRound(transY(bottomY)));
+        data.append("' lengthAdjust='spacingAndGlyphs' textLength='").append(round(getStringWidth(ctx, text) * COORD_FACTOR)).append("px'");
+        appendFontStyle(ctx);
         if (rotationAnticlockWise != 0) {
-            append(" transform='rotate(%.3f %.3f,%.3f)'", toDegrees(rotationAnticlockWise), leftX * COORD_FACTOR, transY(bottomY) * COORD_FACTOR);
+            appendTransform((int) round(toDegrees(rotationAnticlockWise)), trRound(leftX), trRound(transY(bottomY)));
         }
-        data.append(">").append(text).append("</text>");
+        data.append(">").append(text).append("</text>\n");
     }
 
     @Override
@@ -173,16 +180,20 @@ public class SVGDevice implements GridDevice, FileGridDevice {
         return 0.7 * (ctx.getFontSize() / INCH_TO_POINTS_FACTOR);
     }
 
-    private void drawPoly(DrawingContext ctx, double[] x, double[] y, int startIndex, int length, String attributes) {
+    private void drawPoly(DrawingContext ctx, double[] x, double[] y, int startIndex, int length, boolean noFill) {
         appendStyle(ctx);
         data.append("<polyline points='");
         for (int i = 0; i < length; i++) {
-            data.append(DECIMAL_FORMAT.format(x[i + startIndex] * COORD_FACTOR));
+            data.append(trRound(x[i + startIndex]));
             data.append(',');
-            data.append(DECIMAL_FORMAT.format(transY(y[i + startIndex]) * COORD_FACTOR));
-            data.append(' ');
+            data.append(trRound(transY(y[i + startIndex])));
+            if (i != length - 1) {
+                data.append(' ');
+            }
         }
-        data.append("' ").append(attributes).append(" />");
+        data.append('\'');
+        appendColorStyle(ctx, noFill);
+        data.append("/>\n");
     }
 
     private void saveFile() throws DeviceCloseException {
@@ -200,40 +211,34 @@ public class SVGDevice implements GridDevice, FileGridDevice {
         }
         if (cachedCtx != null) {
             // see #appendStyle
-            append("</g>");
+            data.append("</g>");
         }
-        append("</svg>");
+        data.append("</svg>");
     }
 
     // closes opened <g> tag if necessary
     private void closeStyle() {
         if (cachedCtx != null) {
             cachedCtx = null;
-            append("</g>");
+            data.append("</g>");
         }
     }
 
     private void appendStyle(DrawingContext ctx) {
-        if (cachedCtx == null || !DrawingContext.areSame(cachedCtx, ctx)) {
+        if (cachedCtx == null || !areSameGlobalStyles(cachedCtx, ctx)) {
             if (cachedCtx != null) {
-                append("</g>"); // close the previous style definition
+                data.append("</g>"); // close the previous style definition
             }
-            append("<g style='");
+            data.append("<g");
             appendStyleUncached(ctx);
-            append("'>");
+            data.append('>').append('\n');
         }
         cachedCtx = ctx;
     }
 
     private void appendStyleUncached(DrawingContext ctx) {
         byte[] lineType = ctx.getLineType();
-        if (lineType == GRID_LINE_BLANK) {
-            append("stroke:transparent");
-        } else {
-            append(getStyleColor("stroke", ctx.getColor()));
-        }
-        data.append(';').append(getStyleColor("fill", ctx.getFillColor()));
-        data.append(";stroke-width:").append(ctx.getLineWidth());
+        data.append(" style='stroke-width:").append(ctx.getLineWidth());
         if (lineType != DrawingContext.GRID_LINE_SOLID && lineType != DrawingContext.GRID_LINE_BLANK) {
             data.append(";stroke-dasharray:");
             for (int i = 0; i < lineType.length; i++) {
@@ -248,7 +253,33 @@ public class SVGDevice implements GridDevice, FileGridDevice {
         if (ctx.getLineJoin() == GridLineJoin.MITRE) {
             data.append(";stroke-miterlimit:").append(ctx.getLineMitre());
         }
-        data.append(";font-size:").append(ctx.getFontSize()).append("px");
+        data.append('\'');
+    }
+
+    private void appendColorStyle(DrawingContext ctx) {
+        appendColorStyle(ctx, false);
+    }
+
+    private void appendColorStyle(DrawingContext ctx, boolean noFill) {
+        byte[] lineType = ctx.getLineType();
+        if (lineType == GRID_LINE_BLANK) {
+            data.append(" style='stroke:transparent");
+        } else {
+            data.append(" style='");
+            appendStyleColorAttrs("stroke", ctx.getColor());
+        }
+        if (!noFill && !ctx.getFillColor().equals(GridColor.TRANSPARENT)) {
+            data.append(';');
+            appendStyleColorAttrs("fill", ctx.getFillColor());
+            data.append('\'');
+        }
+        data.append('\'');
+    }
+
+    private void appendFontStyle(DrawingContext ctx) {
+        // Note: SVG interprets the "fill" as the color of the text
+        data.append(" style='font-size:").append(ctx.getFontSize()).append("px;");
+        appendStyleColorAttrs("fill", ctx.getColor());
         if (!ctx.getFontFamily().isEmpty()) {
             // Font-family strings 'mono', 'sans', and 'serif' are OK for us
             data.append(";font-family:").append(ctx.getFontFamily());
@@ -259,6 +290,7 @@ public class SVGDevice implements GridDevice, FileGridDevice {
         if (ctx.getFontStyle().isItalic()) {
             data.append(";font-style:italic");
         }
+        data.append('\'');
     }
 
     private static String getSVGLineCap(GridLineEnd lineEnd) {
@@ -287,12 +319,28 @@ public class SVGDevice implements GridDevice, FileGridDevice {
         }
     }
 
-    private static String getStyleColor(String prefix, GridColor color) {
-        return Utils.stringFormat("%s:rgb(%d,%d,%d);%s-opacity:%.3f", prefix, color.getRed(), color.getGreen(), color.getBlue(), prefix, color.getAlpha() / 255d);
+    private void appendStyleColorAttrs(String prefix, GridColor color) {
+        data.append(prefix).append(':');
+        if (color.getAlpha() == GridColor.OPAQUE_ALPHA) {
+            data.append('#');
+            data.append(GridColorUtils.getHexDigit(color.getRed() >> 4));
+            data.append(GridColorUtils.getHexDigit(color.getRed()));
+            data.append(GridColorUtils.getHexDigit(color.getGreen() >> 4));
+            data.append(GridColorUtils.getHexDigit(color.getGreen()));
+            data.append(GridColorUtils.getHexDigit(color.getBlue() >> 4));
+            data.append(GridColorUtils.getHexDigit(color.getBlue()));
+        } else {
+            data.append("rgb(").append(color.getRed()).append(',').append(color.getGreen()).append(',').append(color.getBlue()).append(')').append(';');
+            data.append(prefix).append("-opacity:").append(DECIMAL_FORMAT.format(color.getAlpha() / 255d));
+        }
     }
 
     private void append(String fmt, Object... args) {
-        data.append(Utils.stringFormat(fmt + "\n", args));
+        data.append(Utils.stringFormat(fmt, args));
+    }
+
+    private void appendTransform(int a, int b, int c) {
+        data.append(" transform='rotate(").append(a).append(',').append(b).append(',').append(c).append(")'");
     }
 
     private double transY(double y) {
@@ -303,6 +351,19 @@ public class SVGDevice implements GridDevice, FileGridDevice {
         return (180. / Math.PI) * -rotationAnticlockWise;
     }
 
+    private int trRound(double value) {
+        return (int) Math.round(value * COORD_FACTOR);
+    }
+
+    static boolean areSameGlobalStyles(DrawingContext ctx1, DrawingContext ctx2) {
+        return ctx1 == ctx2 || (ctx1.getLineEnd() == ctx2.getLineEnd() &&
+                        ctx1.getLineJoin() == ctx2.getLineJoin() &&
+                        ctx1.getLineType() == ctx2.getLineType() &&
+                        ctx1.getLineHeight() == ctx2.getLineHeight() &&
+                        ctx1.getLineWidth() == ctx2.getLineWidth() &&
+                        ctx1.getLineMitre() == ctx2.getLineMitre());
+    }
+
     private static final class Bitmap {
         private static final int FILE_HEADER_SIZE = 14;
         private static final int IMAGE_HEADER_SIZE = 40;
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java
index b9834220b64f3f7ccacf8ebf69a617ba4c1f3243..47726633f390b1329da8da3d9255a426543b73b4 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/Graphics2DDevice.java
@@ -23,7 +23,6 @@
 package com.oracle.truffle.r.library.fastrGrid.device.awt;
 
 import static com.oracle.truffle.r.library.fastrGrid.device.DrawingContext.INCH_TO_POINTS_FACTOR;
-import static java.awt.geom.Path2D.WIND_EVEN_ODD;
 
 import java.awt.BasicStroke;
 import java.awt.Color;
@@ -33,13 +32,10 @@ import java.awt.Graphics2D;
 import java.awt.GraphicsEnvironment;
 import java.awt.Image;
 import java.awt.Paint;
+import java.awt.Rectangle;
 import java.awt.RenderingHints;
-import java.awt.Shape;
 import java.awt.Toolkit;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.Path2D;
-import java.awt.geom.Rectangle2D;
 import java.awt.image.MemoryImageSource;
 
 import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext;
@@ -72,6 +68,7 @@ public class Graphics2DDevice implements GridDevice {
     private Graphics2D graphics;
     private final boolean graphicsIsExclusive;
     private DrawingContext cachedContext;
+    private BasicStroke stokeCache;
 
     /**
      * @param graphics Object that should be used for the drawing.
@@ -96,59 +93,76 @@ public class Graphics2DDevice implements GridDevice {
 
     @Override
     public void openNewPage() {
-        ensureOpen();
         graphics.clearRect(0, 0, getWidthAwt(), getHeightAwt());
         cachedContext = null;
     }
 
     @Override
     public void drawRect(DrawingContext ctx, double leftXIn, double bottomYIn, double widthIn, double heightIn, double rotationAnticlockWise) {
-        ensureOpen();
         double leftXReal = transX(leftXIn);
         double topYReal = transY(bottomYIn + heightIn);
         int rectWidth = transDim(widthIn, leftXReal);
         int rectHeight = transDim(heightIn, topYReal);
         int leftX = iround(leftXReal);
         int topY = iround(topYReal);
-        setContext(ctx);
+        setStroke(ctx);
         if (rotationAnticlockWise == 0.) {
-            drawShape(ctx, new Rectangle2D.Double(leftX, topY, rectWidth, rectHeight));
+            drawRectInternal(ctx, new Rectangle(leftX, topY, rectWidth, rectHeight));
         } else {
             int halfWidth = iround(rectWidth / 2.);
             int halfHeight = iround(rectHeight / 2.);
-            transformed(iround(leftX + halfWidth), iround(topY + halfHeight), rotationAnticlockWise, () -> drawShape(ctx, new Rectangle2D.Double(-halfWidth, -halfHeight, rectWidth, rectHeight)));
+            transformed(iround(leftX + halfWidth), iround(topY + halfHeight), rotationAnticlockWise, () -> drawRectInternal(ctx, new Rectangle(-halfWidth, -halfHeight, rectWidth, rectHeight)));
         }
     }
 
     @Override
     public void drawPolyLines(DrawingContext ctx, double[] x, double[] y, int startIndex, int length) {
-        ensureOpen();
-        Path2D.Double path = getPath2D(x, y, startIndex, length);
-        setContext(ctx);
-        graphics.draw(path);
+        int[] xi = new int[length];
+        int[] yi = new int[length];
+        getPath2D(x, y, xi, yi, startIndex, length);
+        setStroke(ctx);
+        setColor(ctx.getColor());
+        graphics.drawPolyline(xi, yi, length);
     }
 
     @Override
     public void drawPolygon(DrawingContext ctx, double[] x, double[] y, int startIndex, int length) {
-        ensureOpen();
-        Path2D.Double path = getPath2D(x, y, startIndex, length);
-        setContext(ctx);
-        drawShape(ctx, path);
+        int[] xi = new int[length];
+        int[] yi = new int[length];
+        getPath2D(x, y, xi, yi, startIndex, length);
+        setStroke(ctx);
+        GridColor fillColor = ctx.getFillColor();
+        if (!fillColor.equals(GridColor.TRANSPARENT)) {
+            setColor(fillColor);
+            graphics.fillPolygon(xi, yi, length);
+        }
+        if (!fillColor.equals(ctx.getColor())) {
+            setColor(ctx.getColor());
+            graphics.drawPolygon(xi, yi, length);
+        }
     }
 
     @Override
     public void drawCircle(DrawingContext ctx, double centerXIn, double centerYIn, double radiusIn) {
-        ensureOpen();
-        setContext(ctx);
+        setStroke(ctx);
         double xRel = transX(centerXIn - radiusIn);
         double yRel = transY(centerYIn + radiusIn);
         int diameter = transDim(radiusIn * 2d, Math.max(xRel % 1, yRel % 1));
-        drawShape(ctx, new Ellipse2D.Double(iround(xRel), iround(yRel), diameter, diameter));
+        int xi = iround(xRel);
+        int yi = iround(yRel);
+        GridColor fillColor = ctx.getFillColor();
+        if (!fillColor.equals(GridColor.TRANSPARENT)) {
+            setColor(fillColor);
+            graphics.fillOval(xi, yi, diameter, diameter);
+        }
+        if (!fillColor.equals(ctx.getColor())) {
+            setColor(ctx.getColor());
+            graphics.drawOval(xi, yi, diameter, diameter);
+        }
     }
 
     @Override
     public void drawRaster(double leftX, double bottomY, double width, double height, int[] pixels, int pixelsColumnsCount, ImageInterpolation interpolation) {
-        ensureOpen();
         graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, fromInterpolation(interpolation));
         Image image = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(pixelsColumnsCount, pixels.length / pixelsColumnsCount, pixels, 0, pixelsColumnsCount));
         double yRel = transY(bottomY + height);
@@ -158,8 +172,7 @@ public class Graphics2DDevice implements GridDevice {
 
     @Override
     public void drawString(DrawingContext ctx, double leftXIn, double bottomYIn, double rotationAnticlockWise, String text) {
-        ensureOpen();
-        setContextAndFont(ctx);
+        setStrokeAndFont(ctx);
         int leftX = iround(transX(leftXIn));
         FontMetrics fontMetrics = graphics.getFontMetrics(graphics.getFont());
         int bottomY = iround(transY(bottomYIn)) - fontMetrics.getDescent();
@@ -178,14 +191,14 @@ public class Graphics2DDevice implements GridDevice {
 
     @Override
     public double getStringWidth(DrawingContext ctx, String text) {
-        setContextAndFont(ctx);
+        setStrokeAndFont(ctx);
         int swingUnits = graphics.getFontMetrics(graphics.getFont()).stringWidth(text);
         return swingUnits / AWT_POINTS_IN_INCH;
     }
 
     @Override
     public double getStringHeight(DrawingContext ctx, String text) {
-        setContextAndFont(ctx);
+        setStrokeAndFont(ctx);
         FontMetrics fontMetrics = graphics.getFontMetrics(graphics.getFont());
         double swingUnits = fontMetrics.getAscent() + fontMetrics.getDescent();
         return swingUnits / AWT_POINTS_IN_INCH;
@@ -205,15 +218,6 @@ public class Graphics2DDevice implements GridDevice {
         return height;
     }
 
-    /**
-     * If the device can be closed by an action outside of the R interpreter (not e.g. dev.close()),
-     * then the device should be able to re-open itself if any drawing happens after it was closed
-     * in such way.
-     */
-    void ensureOpen() {
-        // nop
-    }
-
     void setGraphics2D(Graphics2D newGraphics) {
         assert newGraphics != null;
         graphics = newGraphics;
@@ -253,39 +257,51 @@ public class Graphics2DDevice implements GridDevice {
         graphics.setTransform(oldTransform);
     }
 
-    private Path2D.Double getPath2D(double[] x, double[] y, int startIndex, int length) {
+    private void getPath2D(double[] x, double[] y, int[] xi, int[] yi, int startIndex, int length) {
         assert startIndex >= 0 && startIndex < x.length && startIndex < y.length : "startIndex out of bounds";
         assert length > 0 && (startIndex + length) <= Math.min(x.length, y.length) : "length out of bounds";
-        Path2D.Double path = new Path2D.Double(WIND_EVEN_ODD, x.length);
-        path.moveTo(transX(x[startIndex]), transY(y[startIndex]));
-        for (int i = startIndex + 1; i < length; i++) {
-            path.lineTo(transX(x[i]), transY(y[i]));
+        for (int i = 0; i < length; i++) {
+            xi[i] = iround(transX(x[i + startIndex]));
+            yi[i] = iround(transY(y[i + startIndex]));
         }
-        return path;
     }
 
-    private void drawShape(DrawingContext drawingCtx, Shape shape) {
+    private void drawRectInternal(DrawingContext drawingCtx, Rectangle shape) {
+        GridColor fillColor = drawingCtx.getFillColor();
+        if (!fillColor.equals(GridColor.TRANSPARENT)) {
+            setColor(fillColor);
+            graphics.fill(shape);
+        }
+        if (!fillColor.equals(drawingCtx.getColor())) {
+            setColor(drawingCtx.getColor());
+            graphics.draw(shape);
+        }
+    }
+
+    private void setColor(GridColor color) {
+        Color awtColor = fromGridColor(color);
         Paint paint = graphics.getPaint();
-        graphics.setPaint(fromGridColor(drawingCtx.getFillColor()));
-        graphics.fill(shape);
-        graphics.setPaint(paint);
-        graphics.draw(shape);
+        // Note: setting different color intance (even if equal to the original) causes graphical
+        // pipeline invalidation in Graphics2D implementation
+        if (!(paint instanceof Color && ((Color) paint).equals(awtColor))) {
+            graphics.setColor(awtColor);
+        }
     }
 
-    private void setContext(DrawingContext ctx) {
+    private void setStroke(DrawingContext ctx) {
         if (graphicsIsExclusive && cachedContext == ctx) {
             return;
         }
-        graphics.setColor(fromGridColor(ctx.getColor()));
         graphics.setStroke(getStrokeFromCtx(ctx));
         cachedContext = ctx;
     }
 
-    private void setContextAndFont(DrawingContext ctx) {
+    private void setStrokeAndFont(DrawingContext ctx) {
         if (graphicsIsExclusive && cachedContext == ctx) {
             return;
         }
-        setContext(ctx);
+        setStroke(ctx);
+        setColor(ctx.getColor());
         float fontSize = (float) ((ctx.getFontSize() / INCH_TO_POINTS_FACTOR) * AWT_POINTS_IN_INCH);
         Font font = new Font(getFontName(ctx.getFontFamily()), getAwtFontStyle(ctx.getFontStyle()), 1).deriveFont(fontSize);
         graphics.setFont(font);
@@ -329,7 +345,7 @@ public class Graphics2DDevice implements GridDevice {
         return new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
     }
 
-    private static BasicStroke getStrokeFromCtx(DrawingContext ctx) {
+    private BasicStroke getStrokeFromCtx(DrawingContext ctx) {
         byte[] type = ctx.getLineType();
         double width = ctx.getLineWidth();
         int lineJoin = fromGridLineJoin(ctx.getLineJoin());
@@ -338,7 +354,10 @@ public class Graphics2DDevice implements GridDevice {
         if (type == DrawingContext.GRID_LINE_BLANK) {
             return blankStroke;
         } else if (type == DrawingContext.GRID_LINE_SOLID) {
-            return new BasicStroke((float) (width), endCap, lineJoin, lineMitre);
+            if (stokeCache == null || !areEqual(stokeCache, (float) width, endCap, lineJoin, lineMitre)) {
+                stokeCache = new BasicStroke((float) (width), endCap, lineJoin, lineMitre);
+            }
+            return stokeCache;
         }
         float[] pattern = new float[type.length];
         for (int i = 0; i < pattern.length; i++) {
@@ -383,4 +402,11 @@ public class Graphics2DDevice implements GridDevice {
     private static int iround(double val) {
         return (int) Math.round(val);
     }
+
+    private static boolean areEqual(BasicStroke s, float width, int endCap, int lineJoin, float lineMitre) {
+        return s.getLineWidth() == width &&
+                        s.getEndCap() == endCap &&
+                        s.getLineJoin() == lineJoin &&
+                        s.getMiterLimit() == lineMitre;
+    }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCurr.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCurr.java
index 5c9046e35dc561a4f13b74eb43bc67676f16c48c..b386e039569651b90c0ca863c61b8edb240a4ca8 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCurr.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCurr.java
@@ -23,10 +23,8 @@
 package com.oracle.truffle.r.library.fastrGrid.grDevices;
 
 import com.oracle.truffle.r.library.fastrGrid.GridContext;
-import com.oracle.truffle.r.library.fastrGrid.graphics.RGridGraphicsAdapter;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 public final class DevCurr extends RExternalBuiltinNode.Arg0 {
@@ -37,7 +35,6 @@ public final class DevCurr extends RExternalBuiltinNode.Arg0 {
     @Override
     public RAbstractIntVector execute() {
         int index = GridContext.getContext().getCurrentDeviceIndex();
-        RStringVector names = RDataFactory.createStringVectorFromScalar(RGridGraphicsAdapter.getDeviceName(index));
-        return RDataFactory.createIntVector(new int[]{index + 1}, RDataFactory.COMPLETE_VECTOR, names);
+        return RDataFactory.createIntVector(new int[]{index + 1}, RDataFactory.COMPLETE_VECTOR);
     }
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
index cb21b7d4024ae51fc7e398f75664c70bcc9a12b2..9dc397d6325f20785a4450402e83f32fb513b555 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
@@ -66,6 +66,15 @@
 
 #include <rffiutils.h>
 
+// these two functions are here just to handle casting void* to void function pointers...
+DL_FUNC R_ExternalPtrAddrFn(SEXP s) {
+    return (DL_FUNC) R_ExternalPtrAddr(s);
+}
+
+SEXP R_MakeExternalPtrFn(DL_FUNC p, SEXP tag, SEXP prot) {
+    return R_MakeExternalPtr((void *) p, tag, prot);
+}
+
 // R_GlobalEnv et al are not a variables in FASTR as they are RContext specific
 SEXP FASTR_R_GlobalEnv() {
     TRACE0();
@@ -1391,6 +1400,7 @@ SEXP R_MakeExternalPtr(void *p, SEXP tag, SEXP prot) {
 }
 
 void *R_ExternalPtrAddr(SEXP s) {
+
     TRACE0();
     SEXP result = ((call_R_ExternalPtrAddr) callbacks[R_ExternalPtrAddr_x])(s);
     checkExitCall();