Merge latest Skia into master (7 commits)

https://skia.googlesource.com/skia.git/+log/f87e2b9..86a4340

Test: Presubmit checks will test this change.
Change-Id: I05cfd6da34feb9f8339394dce3811c0c5875fa5b
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index a61f732..ed33c50 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -31,6 +31,8 @@
     'bsalomon@google.com',
     'djsollen@chromium.org',
     'djsollen@google.com',
+    'hcm@chromium.org',
+    'hcm@google.com',
 )
 
 AUTHORS_FILE_NAME = 'AUTHORS'
diff --git a/gm/all_bitmap_configs.cpp b/gm/all_bitmap_configs.cpp
index e954fc3..0d9c2c5 100644
--- a/gm/all_bitmap_configs.cpp
+++ b/gm/all_bitmap_configs.cpp
@@ -260,27 +260,37 @@
             *pm.writable_addr32(x, y) = make_pixel(x, y, alphaType);
         }
     }
+    bm->setImmutable();
 }
 
-DEF_SIMPLE_GM(all_variants_8888, canvas, 4 * SCALE + 30, 2 * SCALE + 10) {
+DEF_SIMPLE_GM(all_variants_8888, canvas, 4 * SCALE + 30, 4 * SCALE + 30) {
     sk_tool_utils::draw_checkerboard(canvas, SK_ColorLTGRAY, SK_ColorWHITE, 8);
 
     sk_sp<SkColorSpace> colorSpaces[] {
         SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named),
         nullptr,
     };
+
+    SkPaint rectPaint;
+    rectPaint.setColor(0x8000FF00);
+    SkRect r = { 0, 0, SCALE, SCALE };
+
     for (auto colorSpace : colorSpaces) {
         canvas->save();
+        // unpremul is expected to *not* draw anything
         for (auto alphaType : {kPremul_SkAlphaType, kUnpremul_SkAlphaType}) {
             canvas->save();
             for (auto colorType : {kRGBA_8888_SkColorType, kBGRA_8888_SkColorType}) {
                 SkBitmap bm;
                 make_color_test_bitmap_variant(colorType, alphaType, colorSpace, &bm);
+                canvas->drawRect(r, rectPaint);
                 canvas->drawBitmap(bm, 0.0f, 0.0f);
+                canvas->drawRect(r.makeOffset(0, SCALE + 10), rectPaint);
+                canvas->drawImage(SkImage::MakeFromBitmap(bm), 0, SCALE + 10, nullptr);
                 canvas->translate(SCALE + 10, 0.0f);
             }
             canvas->restore();
-            canvas->translate(0.0f, SCALE + 10);
+            canvas->translate(0.0f, (SCALE + 10) * 2);
         }
         canvas->restore();
         canvas->translate(2 * (SCALE + 10), 0.0f);
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 47dd47b..c259477 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -1321,6 +1321,8 @@
      */
     void temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds);
 
+    void temporary_internal_getRgnClip(SkRegion*);
+
 protected:
 #ifdef SK_EXPERIMENTAL_SHADOWING
     /** Returns the current (cumulative) draw depth of the canvas.
@@ -1555,7 +1557,6 @@
 
     friend class SkDrawIter;        // needs setupDrawForLayerDevice()
     friend class AutoDrawLooper;
-    friend class SkLua;             // needs top layer size and offset
     friend class SkDebugCanvas;     // needs experimental fAllowSimplifyClip
     friend class SkSurface_Raster;  // needs getDevice()
     friend class SkRecorder;        // resetForNextPicture
@@ -1611,9 +1612,6 @@
                                     const char text[], size_t byteLength,
                                     SkScalar x, SkScalar y);
 
-    // only for canvasutils
-    const SkRegion& internal_private_getTotalClip() const;
-
     /*
      *  Returns true if drawing the specified rect (or all if it is null) with the specified
      *  paint (or default if null) would overwrite the entire root device of the canvas
diff --git a/include/core/SkImageInfo.h b/include/core/SkImageInfo.h
index 4a8c286..2dea479 100644
--- a/include/core/SkImageInfo.h
+++ b/include/core/SkImageInfo.h
@@ -40,8 +40,8 @@
      *  All pixels have their color components stored without any regard to the
      *  alpha. e.g. this is the default configuration for PNG images.
      *
-     *  This alpha-type is ONLY supported for input images. Rendering cannot
-     *  generate this on output.
+     *  This alpha-type is ONLY supported for readPixels/writePixels operations,
+     *  and is not supported for drawing.
      */
     kUnpremul_SkAlphaType,
 
diff --git a/include/utils/SkLua.h b/include/utils/SkLua.h
index ad6f996..ea3e166 100644
--- a/include/utils/SkLua.h
+++ b/include/utils/SkLua.h
@@ -8,7 +8,6 @@
 #ifndef SkLua_DEFINED
 #define SkLua_DEFINED
 
-#include "SkClipStack.h"
 #include "SkColor.h"
 #include "SkPathEffect.h"
 #include "SkScalar.h"
@@ -59,13 +58,8 @@
     void pushPaint(const SkPaint&, const char tableKey[] = NULL);
     void pushPath(const SkPath&, const char tableKey[] = NULL);
     void pushCanvas(SkCanvas*, const char tableKey[] = NULL);
-    void pushClipStack(const SkClipStack&, const char tableKey[] = NULL);
-    void pushClipStackElement(const SkClipStack::Element& element, const char tableKey[] = NULL);
     void pushTextBlob(const SkTextBlob*, const char tableKey[] = NULL);
 
-    // This SkCanvas lua methods is declared here to benefit from SkLua's friendship with SkCanvas.
-    static int lcanvas_getReducedClipStack(lua_State* L);
-
 private:
     lua_State*  fL;
     SkString    fTermCode;
diff --git a/infra/bots/assets/skimage/VERSION b/infra/bots/assets/skimage/VERSION
index 25bf17f..dec2bf5 100644
--- a/infra/bots/assets/skimage/VERSION
+++ b/infra/bots/assets/skimage/VERSION
@@ -1 +1 @@
-18
\ No newline at end of file
+19
\ No newline at end of file
diff --git a/infra/bots/tasks.json b/infra/bots/tasks.json
index 8b2e7cc..4ca00b0 100644
--- a/infra/bots/tasks.json
+++ b/infra/bots/tasks.json
@@ -3577,7 +3577,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -3626,7 +3626,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -3675,7 +3675,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -3724,7 +3724,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -3773,7 +3773,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -3822,7 +3822,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -3871,7 +3871,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -3920,7 +3920,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -3969,7 +3969,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4018,7 +4018,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4067,7 +4067,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4116,7 +4116,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4165,7 +4165,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4214,7 +4214,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4263,7 +4263,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4312,7 +4312,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4361,7 +4361,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4410,7 +4410,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4459,7 +4459,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4508,7 +4508,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4557,7 +4557,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4606,7 +4606,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4655,7 +4655,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4704,7 +4704,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4753,7 +4753,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4802,7 +4802,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4851,7 +4851,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4900,7 +4900,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4949,7 +4949,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -4998,7 +4998,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5047,7 +5047,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5174,7 +5174,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5222,7 +5222,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5270,7 +5270,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5319,7 +5319,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5368,7 +5368,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5416,7 +5416,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5464,7 +5464,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5512,7 +5512,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5561,7 +5561,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5615,7 +5615,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5669,7 +5669,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5718,7 +5718,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5767,7 +5767,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5820,7 +5820,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5869,7 +5869,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5918,7 +5918,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -5967,7 +5967,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6066,7 +6066,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6114,7 +6114,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6162,7 +6162,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6210,7 +6210,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6258,7 +6258,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6306,7 +6306,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6354,7 +6354,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6402,7 +6402,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6450,7 +6450,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6498,7 +6498,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6546,7 +6546,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6594,7 +6594,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6642,7 +6642,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6690,7 +6690,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6738,7 +6738,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6786,7 +6786,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6834,7 +6834,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6882,7 +6882,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6930,7 +6930,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -6978,7 +6978,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7026,7 +7026,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7074,7 +7074,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7122,7 +7122,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7170,7 +7170,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7218,7 +7218,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7266,7 +7266,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7314,7 +7314,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7362,7 +7362,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7410,7 +7410,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7458,7 +7458,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7506,7 +7506,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7554,7 +7554,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7602,7 +7602,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7650,7 +7650,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7698,7 +7698,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7746,7 +7746,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7794,7 +7794,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7843,7 +7843,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7892,7 +7892,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7941,7 +7941,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -7990,7 +7990,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8038,7 +8038,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8086,7 +8086,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8135,7 +8135,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8184,7 +8184,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8233,7 +8233,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8282,7 +8282,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8331,7 +8331,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8380,7 +8380,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8429,7 +8429,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8478,7 +8478,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8527,7 +8527,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8576,7 +8576,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8625,7 +8625,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8674,7 +8674,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8723,7 +8723,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8772,7 +8772,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8821,7 +8821,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8870,7 +8870,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8919,7 +8919,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -8968,7 +8968,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9017,7 +9017,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9066,7 +9066,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9115,7 +9115,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9164,7 +9164,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9213,7 +9213,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9262,7 +9262,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9311,7 +9311,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9360,7 +9360,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9409,7 +9409,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9458,7 +9458,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9507,7 +9507,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9556,7 +9556,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9605,7 +9605,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9654,7 +9654,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9703,7 +9703,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9751,7 +9751,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9799,7 +9799,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9848,7 +9848,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9897,7 +9897,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9945,7 +9945,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -9993,7 +9993,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10041,7 +10041,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10090,7 +10090,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10144,7 +10144,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10198,7 +10198,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10247,7 +10247,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10296,7 +10296,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10350,7 +10350,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10403,7 +10403,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10456,7 +10456,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10505,7 +10505,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10629,7 +10629,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10678,7 +10678,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10727,7 +10727,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10776,7 +10776,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10824,7 +10824,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10872,7 +10872,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10920,7 +10920,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -10968,7 +10968,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11016,7 +11016,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11064,7 +11064,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11112,7 +11112,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11160,7 +11160,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11208,7 +11208,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11256,7 +11256,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11304,7 +11304,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11352,7 +11352,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11400,7 +11400,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11448,7 +11448,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11496,7 +11496,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11544,7 +11544,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11592,7 +11592,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11640,7 +11640,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11688,7 +11688,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11736,7 +11736,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11784,7 +11784,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11832,7 +11832,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11880,7 +11880,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11928,7 +11928,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -11976,7 +11976,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12024,7 +12024,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12072,7 +12072,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12120,7 +12120,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12168,7 +12168,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12216,7 +12216,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12264,7 +12264,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12312,7 +12312,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12360,7 +12360,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12408,7 +12408,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12456,7 +12456,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12505,7 +12505,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12554,7 +12554,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12603,7 +12603,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12652,7 +12652,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12701,7 +12701,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12750,7 +12750,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
@@ -12798,7 +12798,7 @@
         {
           "name": "skia/bots/skimage",
           "path": "skimage",
-          "version": "version:18"
+          "version": "version:19"
         },
         {
           "name": "skia/bots/skp",
diff --git a/public.bzl b/public.bzl
index 307544a..14d0c53 100644
--- a/public.bzl
+++ b/public.bzl
@@ -590,7 +590,6 @@
     "SK_NO_ANALYTIC_AA",
     "SK_SUPPORT_LEGACY_BITMAP_SETPIXELREF",
     "SK_SUPPORT_LEGACY_CLIPOP_EXOTIC_NAMES",
-    "SK_SUPPORT_LEGACY_CANVAS_GETCLIPSTACK",
 ]
 
 ################################################################################
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index e3374dd..367a348 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -53,6 +53,12 @@
 
 #define RETURN_ON_NULL(ptr)     do { if (nullptr == (ptr)) return; } while (0)
 
+#define RETURN_ON_UNPREMUL_IMAGE(image) \
+    do { if (as_IB(image)->onAlphaType() == kUnpremul_SkAlphaType) return; } while (0)
+
+#define RETURN_ON_UNPREMUL_BITMAP(bitmap) \
+    do { if (bitmap.alphaType() == kUnpremul_SkAlphaType) return; } while (0)
+
 /*
  *  Return true if the drawing this rect would hit every pixels in the canvas.
  *
@@ -1819,8 +1825,16 @@
     return fMCRec->fMatrix;
 }
 
-const SkRegion& SkCanvas::internal_private_getTotalClip() const {
-    return fMCRec->fRasterClip.forceGetBW();
+void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
+    // we know that ganesh doesn't track the rgn, so ask for its clipstack
+    if (this->getGrContext()) {
+        SkPath path;
+        this->getClipStack()->asPath(&path);
+        SkISize size = this->getBaseLayerSize();
+        rgn->setPath(path, SkRegion(SkIRect::MakeWH(size.width(), size.height())));
+    } else {
+        *rgn = fMCRec->fRasterClip.forceGetBW();
+    }
 }
 
 GrRenderTargetContext* SkCanvas::internal_private_accessTopLayerRenderTargetContext() {
@@ -1901,12 +1915,14 @@
 
 void SkCanvas::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint* paint) {
     RETURN_ON_NULL(image);
+    RETURN_ON_UNPREMUL_IMAGE(image);
     this->onDrawImage(image, x, y, paint);
 }
 
 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
                              const SkPaint* paint, SrcRectConstraint constraint) {
     RETURN_ON_NULL(image);
+    RETURN_ON_UNPREMUL_IMAGE(image);
     if (dst.isEmpty() || src.isEmpty()) {
         return;
     }
@@ -1916,12 +1932,14 @@
 void SkCanvas::drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
                              const SkPaint* paint, SrcRectConstraint constraint) {
     RETURN_ON_NULL(image);
+    RETURN_ON_UNPREMUL_IMAGE(image);
     this->drawImageRect(image, SkRect::Make(isrc), dst, paint, constraint);
 }
 
 void SkCanvas::drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint,
                              SrcRectConstraint constraint) {
     RETURN_ON_NULL(image);
+    RETURN_ON_UNPREMUL_IMAGE(image);
     this->drawImageRect(image, SkRect::MakeIWH(image->width(), image->height()), dst, paint,
                         constraint);
 }
@@ -1929,6 +1947,7 @@
 void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
                              const SkPaint* paint) {
     RETURN_ON_NULL(image);
+    RETURN_ON_UNPREMUL_IMAGE(image);
     if (dst.isEmpty()) {
         return;
     }
@@ -1942,6 +1961,7 @@
 void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
                                 const SkPaint* paint) {
     RETURN_ON_NULL(image);
+    RETURN_ON_UNPREMUL_IMAGE(image);
     if (dst.isEmpty()) {
         return;
     }
@@ -1964,6 +1984,7 @@
     if (bitmap.drawsNothing()) {
         return;
     }
+    RETURN_ON_UNPREMUL_BITMAP(bitmap);
     this->onDrawBitmap(bitmap, dx, dy, paint);
 }
 
@@ -1972,6 +1993,7 @@
     if (bitmap.drawsNothing() || dst.isEmpty() || src.isEmpty()) {
         return;
     }
+    RETURN_ON_UNPREMUL_BITMAP(bitmap);
     this->onDrawBitmapRect(bitmap, &src, dst, paint, constraint);
 }
 
@@ -1991,6 +2013,7 @@
     if (bitmap.drawsNothing() || dst.isEmpty()) {
         return;
     }
+    RETURN_ON_UNPREMUL_BITMAP(bitmap);
     if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
         this->onDrawBitmapNine(bitmap, center, dst, paint);
     } else {
@@ -2003,6 +2026,7 @@
     if (bitmap.drawsNothing() || dst.isEmpty()) {
         return;
     }
+    RETURN_ON_UNPREMUL_BITMAP(bitmap);
 
     SkIRect bounds;
     Lattice latticePlusBounds = lattice;
@@ -2022,10 +2046,10 @@
                          const SkColor colors[], int count, SkBlendMode mode,
                          const SkRect* cull, const SkPaint* paint) {
     RETURN_ON_NULL(atlas);
+    RETURN_ON_UNPREMUL_IMAGE(atlas);
     if (count <= 0) {
         return;
     }
-    SkASSERT(atlas);
     SkASSERT(tex);
     this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
 }
diff --git a/src/image/SkImageShader.cpp b/src/image/SkImageShader.cpp
index 5b79fb1..5cb1c24 100644
--- a/src/image/SkImageShader.cpp
+++ b/src/image/SkImageShader.cpp
@@ -103,6 +103,10 @@
 sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, TileMode tx, TileMode ty,
                                     const SkMatrix* localMatrix,
                                     SkTBlitterAllocator* allocator) {
+    if (image && as_IB(image)->onAlphaType() == kUnpremul_SkAlphaType) {
+        return nullptr;
+    }
+
     SkShader* shader;
     if (!image || bitmap_is_too_big(image->width(), image->height())) {
         if (nullptr == allocator) {
diff --git a/src/sksl/SkSLCFGGenerator.cpp b/src/sksl/SkSLCFGGenerator.cpp
index 964a8dc..31bace9 100644
--- a/src/sksl/SkSLCFGGenerator.cpp
+++ b/src/sksl/SkSLCFGGenerator.cpp
@@ -54,8 +54,8 @@
         printf("Block %d\n-------\nBefore: ", (int) i);
         const char* separator = "";
         for (auto iter = fBlocks[i].fBefore.begin(); iter != fBlocks[i].fBefore.end(); iter++) {
-            printf("%s%s = %s", separator, iter->first->description().c_str(), 
-                   iter->second ? iter->second->description().c_str() : "<undefined>");
+            printf("%s%s = %s", separator, iter->first->description().c_str(),
+                   *iter->second ? (*iter->second)->description().c_str() : "<undefined>");
             separator = ", ";
         }
         printf("\nEntrances: ");
@@ -66,7 +66,10 @@
         }
         printf("\n");
         for (size_t j = 0; j < fBlocks[i].fNodes.size(); j++) {
-            printf("Node %d: %s\n", (int) j, fBlocks[i].fNodes[j].fNode->description().c_str());
+            BasicBlock::Node& n = fBlocks[i].fNodes[j];
+            printf("Node %d: %s\n", (int) j, n.fKind == BasicBlock::Node::kExpression_Kind
+                                                           ? (*n.fExpression)->description().c_str()
+                                                           : n.fStatement->description().c_str());
         }
         printf("Exits: ");
         separator = "";
@@ -78,96 +81,109 @@
     }
 }
 
-void CFGGenerator::addExpression(CFG& cfg, const Expression* e) {
-    switch (e->fKind) {
+void CFGGenerator::addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate) {
+    ASSERT(e);
+    switch ((*e)->fKind) {
         case Expression::kBinary_Kind: {
-            const BinaryExpression* b = (const BinaryExpression*) e;
+            BinaryExpression* b = (BinaryExpression*) e->get();
             switch (b->fOperator) {
                 case Token::LOGICALAND: // fall through
                 case Token::LOGICALOR: {
                     // this isn't as precise as it could be -- we don't bother to track that if we
                     // early exit from a logical and/or, we know which branch of an 'if' we're going
                     // to hit -- but it won't make much difference in practice.
-                    this->addExpression(cfg, b->fLeft.get());
+                    this->addExpression(cfg, &b->fLeft, constantPropagate);
                     BlockId start = cfg.fCurrent;
                     cfg.newBlock();
-                    this->addExpression(cfg, b->fRight.get());
+                    this->addExpression(cfg, &b->fRight, constantPropagate);
                     cfg.newBlock();
                     cfg.addExit(start, cfg.fCurrent);
                     break;
                 }
                 case Token::EQ: {
-                    this->addExpression(cfg, b->fRight.get());
-                    this->addLValue(cfg, b->fLeft.get());
-                    cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ 
-                        BasicBlock::Node::kExpression_Kind, 
-                        b 
+                    this->addExpression(cfg, &b->fRight, constantPropagate);
+                    this->addLValue(cfg, &b->fLeft);
+                    cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
+                        BasicBlock::Node::kExpression_Kind,
+                        constantPropagate,
+                        e,
+                        nullptr
                     });
                     break;
                 }
                 default:
-                    this->addExpression(cfg, b->fLeft.get());
-                    this->addExpression(cfg, b->fRight.get());
-                    cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ 
-                        BasicBlock::Node::kExpression_Kind, 
-                        b 
+                    this->addExpression(cfg, &b->fLeft, !Token::IsAssignment(b->fOperator));
+                    this->addExpression(cfg, &b->fRight, constantPropagate);
+                    cfg.fBlocks[cfg.fCurrent].fNodes.push_back({
+                        BasicBlock::Node::kExpression_Kind,
+                        constantPropagate,
+                        e,
+                        nullptr
                     });
             }
             break;
         }
         case Expression::kConstructor_Kind: {
-            const Constructor* c = (const Constructor*) e;
-            for (const auto& arg : c->fArguments) {
-                this->addExpression(cfg, arg.get());
+            Constructor* c = (Constructor*) e->get();
+            for (auto& arg : c->fArguments) {
+                this->addExpression(cfg, &arg, constantPropagate);
             }
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, c });
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
+                                                         constantPropagate, e, nullptr });
             break;
         }
         case Expression::kFunctionCall_Kind: {
-            const FunctionCall* c = (const FunctionCall*) e;
-            for (const auto& arg : c->fArguments) {
-                this->addExpression(cfg, arg.get());
+            FunctionCall* c = (FunctionCall*) e->get();
+            for (auto& arg : c->fArguments) {
+                this->addExpression(cfg, &arg, constantPropagate);
             }
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, c });
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
+                                                         constantPropagate, e, nullptr });
             break;
         }
         case Expression::kFieldAccess_Kind:
-            this->addExpression(cfg, ((const FieldAccess*) e)->fBase.get());
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, e });
+            this->addExpression(cfg, &((FieldAccess*) e->get())->fBase, constantPropagate);
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
+                                                         constantPropagate, e, nullptr });
             break;
         case Expression::kIndex_Kind:
-            this->addExpression(cfg, ((const IndexExpression*) e)->fBase.get());
-            this->addExpression(cfg, ((const IndexExpression*) e)->fIndex.get());
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, e });
+            this->addExpression(cfg, &((IndexExpression*) e->get())->fBase, constantPropagate);
+            this->addExpression(cfg, &((IndexExpression*) e->get())->fIndex, constantPropagate);
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
+                                                         constantPropagate, e, nullptr });
             break;
         case Expression::kPrefix_Kind:
-            this->addExpression(cfg, ((const PrefixExpression*) e)->fOperand.get());
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, e });
+            this->addExpression(cfg, &((PrefixExpression*) e->get())->fOperand, constantPropagate);
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
+                                                         constantPropagate, e, nullptr });
             break;
         case Expression::kPostfix_Kind:
-            this->addExpression(cfg, ((const PostfixExpression*) e)->fOperand.get());
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, e });
+            this->addExpression(cfg, &((PostfixExpression*) e->get())->fOperand, constantPropagate);
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
+                                                         constantPropagate, e, nullptr });
             break;
         case Expression::kSwizzle_Kind:
-            this->addExpression(cfg, ((const Swizzle*) e)->fBase.get());
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, e });
+            this->addExpression(cfg, &((Swizzle*) e->get())->fBase, constantPropagate);
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
+                                                         constantPropagate, e, nullptr });
             break;
         case Expression::kBoolLiteral_Kind:  // fall through
         case Expression::kFloatLiteral_Kind: // fall through
         case Expression::kIntLiteral_Kind:   // fall through
         case Expression::kVariableReference_Kind:
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind, e });
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kExpression_Kind,
+                                                         constantPropagate, e, nullptr });
             break;
         case Expression::kTernary_Kind: {
-            const TernaryExpression* t = (const TernaryExpression*) e;
-            this->addExpression(cfg, t->fTest.get());
+            TernaryExpression* t = (TernaryExpression*) e->get();
+            this->addExpression(cfg, &t->fTest, constantPropagate);
             BlockId start = cfg.fCurrent;
             cfg.newBlock();
-            this->addExpression(cfg, t->fIfTrue.get());
+            this->addExpression(cfg, &t->fIfTrue, constantPropagate);
             BlockId next = cfg.newBlock();
             cfg.fCurrent = start;
             cfg.newBlock();
-            this->addExpression(cfg, t->fIfFalse.get());
+            this->addExpression(cfg, &t->fIfFalse, constantPropagate);
             cfg.addExit(cfg.fCurrent, next);
             cfg.fCurrent = next;
             break;
@@ -181,17 +197,17 @@
 }
 
 // adds expressions that are evaluated as part of resolving an lvalue
-void CFGGenerator::addLValue(CFG& cfg, const Expression* e) {
-    switch (e->fKind) {
+void CFGGenerator::addLValue(CFG& cfg, std::unique_ptr<Expression>* e) {
+    switch ((*e)->fKind) {
         case Expression::kFieldAccess_Kind:
-            this->addLValue(cfg, ((const FieldAccess*) e)->fBase.get());
+            this->addLValue(cfg, &((FieldAccess&) **e).fBase);
             break;
         case Expression::kIndex_Kind:
-            this->addLValue(cfg, ((const IndexExpression*) e)->fBase.get());
-            this->addExpression(cfg, ((const IndexExpression*) e)->fIndex.get());
+            this->addLValue(cfg, &((IndexExpression&) **e).fBase);
+            this->addExpression(cfg, &((IndexExpression&) **e).fIndex, true);
             break;
         case Expression::kSwizzle_Kind:
-            this->addLValue(cfg, ((const Swizzle*) e)->fBase.get());
+            this->addLValue(cfg, &((Swizzle&) **e).fBase);
             break;
         case Expression::kVariableReference_Kind:
             break;
@@ -210,8 +226,8 @@
             }
             break;
         case Statement::kIf_Kind: {
-            const IfStatement* ifs = (const IfStatement*) s;
-            this->addExpression(cfg, ifs->fTest.get());
+            IfStatement* ifs = (IfStatement*) s;
+            this->addExpression(cfg, &ifs->fTest, true);
             BlockId start = cfg.fCurrent;
             cfg.newBlock();
             this->addStatement(cfg, ifs->fIfTrue.get());
@@ -228,49 +244,54 @@
             break;
         }
         case Statement::kExpression_Kind: {
-            this->addExpression(cfg, ((ExpressionStatement&) *s).fExpression.get());
+            this->addExpression(cfg, &((ExpressionStatement&) *s).fExpression, true);
             break;
         }
         case Statement::kVarDeclarations_Kind: {
-            const VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) *s);
-            for (const auto& vd : decls.fDeclaration->fVars) {
+            VarDeclarationsStatement& decls = ((VarDeclarationsStatement&) *s);
+            for (auto& vd : decls.fDeclaration->fVars) {
                 if (vd.fValue) {
-                    this->addExpression(cfg, vd.fValue.get());
+                    this->addExpression(cfg, &vd.fValue, true);
                 }
             }
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, s });
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
+                                                         nullptr, s });
             break;
         }
         case Statement::kDiscard_Kind:
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, s });
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
+                                                         nullptr, s });
             cfg.fCurrent = cfg.newIsolatedBlock();
             break;
         case Statement::kReturn_Kind: {
-            const ReturnStatement& r = ((ReturnStatement&) *s);
+            ReturnStatement& r = ((ReturnStatement&) *s);
             if (r.fExpression) {
-                this->addExpression(cfg, r.fExpression.get());
+                this->addExpression(cfg, &r.fExpression, true);
             }
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, s });
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
+                                                         nullptr, s });
             cfg.fCurrent = cfg.newIsolatedBlock();
             break;
         }
         case Statement::kBreak_Kind:
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, s });
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
+                                                         nullptr, s });
             cfg.addExit(cfg.fCurrent, fLoopExits.top());
             cfg.fCurrent = cfg.newIsolatedBlock();
             break;
         case Statement::kContinue_Kind:
-            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, s });
+            cfg.fBlocks[cfg.fCurrent].fNodes.push_back({ BasicBlock::Node::kStatement_Kind, false,
+                                                         nullptr, s });
             cfg.addExit(cfg.fCurrent, fLoopContinues.top());
             cfg.fCurrent = cfg.newIsolatedBlock();
             break;
         case Statement::kWhile_Kind: {
-            const WhileStatement* w = (const WhileStatement*) s;
+            WhileStatement* w = (WhileStatement*) s;
             BlockId loopStart = cfg.newBlock();
             fLoopContinues.push(loopStart);
             BlockId loopExit = cfg.newIsolatedBlock();
             fLoopExits.push(loopExit);
-            this->addExpression(cfg, w->fTest.get());
+            this->addExpression(cfg, &w->fTest, true);
             BlockId test = cfg.fCurrent;
             cfg.addExit(test, loopExit);
             cfg.newBlock();
@@ -282,13 +303,13 @@
             break;
         }
         case Statement::kDo_Kind: {
-            const DoStatement* d = (const DoStatement*) s;
+            DoStatement* d = (DoStatement*) s;
             BlockId loopStart = cfg.newBlock();
             fLoopContinues.push(loopStart);
             BlockId loopExit = cfg.newIsolatedBlock();
             fLoopExits.push(loopExit);
             this->addStatement(cfg, d->fStatement.get());
-            this->addExpression(cfg, d->fTest.get());
+            this->addExpression(cfg, &d->fTest, true);
             cfg.addExit(cfg.fCurrent, loopExit);
             cfg.addExit(cfg.fCurrent, loopStart);
             fLoopContinues.pop();
@@ -297,7 +318,7 @@
             break;
         }
         case Statement::kFor_Kind: {
-            const ForStatement* f = (const ForStatement*) s;
+            ForStatement* f = (ForStatement*) s;
             if (f->fInitializer) {
                 this->addStatement(cfg, f->fInitializer.get());
             }
@@ -307,7 +328,7 @@
             BlockId loopExit = cfg.newIsolatedBlock();
             fLoopExits.push(loopExit);
             if (f->fTest) {
-                this->addExpression(cfg, f->fTest.get());
+                this->addExpression(cfg, &f->fTest, true);
                 BlockId test = cfg.fCurrent;
                 cfg.addExit(test, loopExit);
             }
@@ -316,9 +337,9 @@
             cfg.addExit(cfg.fCurrent, next);
             cfg.fCurrent = next;
             if (f->fNext) {
-                this->addExpression(cfg, f->fNext.get());
+                this->addExpression(cfg, &f->fNext, true);
             }
-            cfg.addExit(next, loopStart);
+            cfg.addExit(cfg.fCurrent, loopStart);
             fLoopContinues.pop();
             fLoopExits.pop();
             cfg.fCurrent = loopExit;
diff --git a/src/sksl/SkSLCFGGenerator.h b/src/sksl/SkSLCFGGenerator.h
index c378501..337fdfa 100644
--- a/src/sksl/SkSLCFGGenerator.h
+++ b/src/sksl/SkSLCFGGenerator.h
@@ -27,14 +27,23 @@
         };
 
         Kind fKind;
-        const IRNode* fNode;
+        // if false, this node should not be subject to constant propagation. This happens with
+        // compound assignment (i.e. x *= 2), in which the value x is used as an rvalue for
+        // multiplication by 2 and then as an lvalue for assignment purposes. Since there is only
+        // one "x" node, replacing it with a constant would break the assignment and we suppress
+        // it. Down the road, we should handle this more elegantly by substituting a regular
+        // assignment if the target is constant (i.e. x = 1; x *= 2; should become x = 1; x = 1 * 2;
+        // and then collapse down to a simple x = 2;).
+        bool fConstantPropagation;
+        std::unique_ptr<Expression>* fExpression;
+        const Statement* fStatement;
     };
-    
+
     std::vector<Node> fNodes;
     std::set<BlockId> fEntrances;
     std::set<BlockId> fExits;
     // variable definitions upon entering this basic block (null expression = undefined)
-    std::unordered_map<const Variable*, const Expression*> fBefore;
+    DefinitionMap fBefore;
 };
 
 struct CFG {
@@ -77,9 +86,9 @@
 private:
     void addStatement(CFG& cfg, const Statement* s);
 
-    void addExpression(CFG& cfg, const Expression* e);
+    void addExpression(CFG& cfg, std::unique_ptr<Expression>* e, bool constantPropagate);
 
-    void addLValue(CFG& cfg, const Expression* e);
+    void addLValue(CFG& cfg, std::unique_ptr<Expression>* e);
 
     std::stack<BlockId> fLoopContinues;
     std::stack<BlockId> fLoopExits;
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 9faf836..743745a 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -156,8 +156,8 @@
 }
 
 // add the definition created by assigning to the lvalue to the definition set
-void Compiler::addDefinition(const Expression* lvalue, const Expression* expr,
-                           std::unordered_map<const Variable*, const Expression*>* definitions) {
+void Compiler::addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
+                             DefinitionMap* definitions) {
     switch (lvalue->fKind) {
         case Expression::kVariableReference_Kind: {
             const Variable& var = ((VariableReference*) lvalue)->fVariable;
@@ -174,19 +174,19 @@
             // but since we pass foo as a whole it is flagged as an error) unless we perform a much
             // more complicated whole-program analysis. This is probably good enough.
             this->addDefinition(((Swizzle*) lvalue)->fBase.get(),
-                                fContext.fDefined_Expression.get(),
+                                (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
                                 definitions);
             break;
         case Expression::kIndex_Kind:
             // see comments in Swizzle
             this->addDefinition(((IndexExpression*) lvalue)->fBase.get(),
-                                fContext.fDefined_Expression.get(),
+                                (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
                                 definitions);
             break;
         case Expression::kFieldAccess_Kind:
             // see comments in Swizzle
             this->addDefinition(((FieldAccess*) lvalue)->fBase.get(),
-                                fContext.fDefined_Expression.get(),
+                                (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
                                 definitions);
             break;
         default:
@@ -197,25 +197,58 @@
 
 // add local variables defined by this node to the set
 void Compiler::addDefinitions(const BasicBlock::Node& node,
-                              std::unordered_map<const Variable*, const Expression*>* definitions) {
+                              DefinitionMap* definitions) {
     switch (node.fKind) {
         case BasicBlock::Node::kExpression_Kind: {
-            const Expression* expr = (Expression*) node.fNode;
-            if (expr->fKind == Expression::kBinary_Kind) {
-                const BinaryExpression* b = (BinaryExpression*) expr;
-                if (b->fOperator == Token::EQ) {
-                    this->addDefinition(b->fLeft.get(), b->fRight.get(), definitions);
+            ASSERT(node.fExpression);
+            const Expression* expr = (Expression*) node.fExpression->get();
+            switch (expr->fKind) {
+                case Expression::kBinary_Kind: {
+                    BinaryExpression* b = (BinaryExpression*) expr;
+                    if (b->fOperator == Token::EQ) {
+                        this->addDefinition(b->fLeft.get(), &b->fRight, definitions);
+                    } else if (Token::IsAssignment(b->fOperator)) {
+                        this->addDefinition(
+                                       b->fLeft.get(),
+                                       (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
+                                       definitions);
+
+                    }
+                    break;
                 }
+                case Expression::kPrefix_Kind: {
+                    const PrefixExpression* p = (PrefixExpression*) expr;
+                    if (p->fOperator == Token::MINUSMINUS || p->fOperator == Token::PLUSPLUS) {
+                        this->addDefinition(
+                                       p->fOperand.get(),
+                                       (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
+                                       definitions);
+                    }
+                    break;
+                }
+                case Expression::kPostfix_Kind: {
+                    const PostfixExpression* p = (PostfixExpression*) expr;
+                    if (p->fOperator == Token::MINUSMINUS || p->fOperator == Token::PLUSPLUS) {
+                        this->addDefinition(
+                                       p->fOperand.get(),
+                                       (std::unique_ptr<Expression>*) &fContext.fDefined_Expression,
+                                       definitions);
+
+                    }
+                    break;
+                }
+                default:
+                    break;
             }
             break;
         }
         case BasicBlock::Node::kStatement_Kind: {
-            const Statement* stmt = (Statement*) node.fNode;
+            const Statement* stmt = (Statement*) node.fStatement;
             if (stmt->fKind == Statement::kVarDeclarations_Kind) {
-                const VarDeclarationsStatement* vd = (VarDeclarationsStatement*) stmt;
-                for (const VarDeclaration& decl : vd->fDeclaration->fVars) {
+                VarDeclarationsStatement* vd = (VarDeclarationsStatement*) stmt;
+                for (VarDeclaration& decl : vd->fDeclaration->fVars) {
                     if (decl.fValue) {
-                        (*definitions)[decl.fVar] = decl.fValue.get();
+                        (*definitions)[decl.fVar] = &decl.fValue;
                     }
                 }
             }
@@ -228,7 +261,7 @@
     BasicBlock& block = cfg->fBlocks[blockId];
 
     // compute definitions after this block
-    std::unordered_map<const Variable*, const Expression*> after = block.fBefore;
+    DefinitionMap after = block.fBefore;
     for (const BasicBlock::Node& n : block.fNodes) {
         this->addDefinitions(n, &after);
     }
@@ -237,19 +270,20 @@
     for (BlockId exitId : block.fExits) {
         BasicBlock& exit = cfg->fBlocks[exitId];
         for (const auto& pair : after) {
-            const Expression* e1 = pair.second;
-            if (exit.fBefore.find(pair.first) == exit.fBefore.end()) {
+            std::unique_ptr<Expression>* e1 = pair.second;
+            auto found = exit.fBefore.find(pair.first);
+            if (found == exit.fBefore.end()) {
+                // exit has no definition for it, just copy it
+                workList->insert(exitId);
                 exit.fBefore[pair.first] = e1;
             } else {
-                const Expression* e2 = exit.fBefore[pair.first];
+                // exit has a (possibly different) value already defined
+                std::unique_ptr<Expression>* e2 = exit.fBefore[pair.first];
                 if (e1 != e2) {
                     // definition has changed, merge and add exit block to worklist
                     workList->insert(exitId);
-                    if (!e1 || !e2) {
-                        exit.fBefore[pair.first] = nullptr;
-                    } else {
-                        exit.fBefore[pair.first] = fContext.fDefined_Expression.get();
-                    }
+                    exit.fBefore[pair.first] =
+                                       (std::unique_ptr<Expression>*) &fContext.fDefined_Expression;
                 }
             }
         }
@@ -258,12 +292,13 @@
 
 // returns a map which maps all local variables in the function to null, indicating that their value
 // is initially unknown
-static std::unordered_map<const Variable*, const Expression*> compute_start_state(const CFG& cfg) {
-    std::unordered_map<const Variable*, const Expression*> result;
+static DefinitionMap compute_start_state(const CFG& cfg) {
+    DefinitionMap result;
     for (const auto& block : cfg.fBlocks) {
         for (const auto& node : block.fNodes) {
             if (node.fKind == BasicBlock::Node::kStatement_Kind) {
-                const Statement* s = (Statement*) node.fNode;
+                ASSERT(node.fStatement);
+                const Statement* s = node.fStatement;
                 if (s->fKind == Statement::kVarDeclarations_Kind) {
                     const VarDeclarationsStatement* vd = (const VarDeclarationsStatement*) s;
                     for (const VarDeclaration& decl : vd->fDeclaration->fVars) {
@@ -295,19 +330,37 @@
     for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
         if (i != cfg.fStart && !cfg.fBlocks[i].fEntrances.size() &&
             cfg.fBlocks[i].fNodes.size()) {
-            this->error(cfg.fBlocks[i].fNodes[0].fNode->fPosition, SkString("unreachable"));
+            Position p;
+            switch (cfg.fBlocks[i].fNodes[0].fKind) {
+                case BasicBlock::Node::kStatement_Kind:
+                    p = cfg.fBlocks[i].fNodes[0].fStatement->fPosition;
+                    break;
+                case BasicBlock::Node::kExpression_Kind:
+                    p = (*cfg.fBlocks[i].fNodes[0].fExpression)->fPosition;
+                    break;
+            }
+            this->error(p, SkString("unreachable"));
         }
     }
     if (fErrorCount) {
         return;
     }
 
-    // check for undefined variables
-    for (const BasicBlock& b : cfg.fBlocks) {
-        std::unordered_map<const Variable*, const Expression*> definitions = b.fBefore;
-        for (const BasicBlock::Node& n : b.fNodes) {
+    // check for undefined variables, perform constant propagation
+    for (BasicBlock& b : cfg.fBlocks) {
+        DefinitionMap definitions = b.fBefore;
+        for (BasicBlock::Node& n : b.fNodes) {
             if (n.fKind == BasicBlock::Node::kExpression_Kind) {
-                const Expression* expr = (const Expression*) n.fNode;
+                ASSERT(n.fExpression);
+                Expression* expr = n.fExpression->get();
+                if (n.fConstantPropagation) {
+                    std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
+                                                                                    definitions);
+                    if (optimized) {
+                        n.fExpression->reset(optimized.release());
+                        expr = n.fExpression->get();
+                    }
+                }
                 if (expr->fKind == Expression::kVariableReference_Kind) {
                     const Variable& var = ((VariableReference*) expr)->fVariable;
                     if (var.fStorage == Variable::kLocal_Storage &&
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index 0f893f7..fdca12d 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -60,11 +60,10 @@
     }
 
 private:
-    void addDefinition(const Expression* lvalue, const Expression* expr,
-                       std::unordered_map<const Variable*, const Expression*>* definitions);
+    void addDefinition(const Expression* lvalue, std::unique_ptr<Expression>* expr,
+                       DefinitionMap* definitions);
 
-    void addDefinitions(const BasicBlock::Node& node,
-                        std::unordered_map<const Variable*, const Expression*>* definitions);
+    void addDefinitions(const BasicBlock::Node& node, DefinitionMap* definitions);
 
     void scanCFG(CFG* cfg, BlockId block, std::set<BlockId>* workList);
 
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 9f06c97..55d9d2c 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -551,11 +551,11 @@
         }
     }
     Type* type = new Type(intf.fPosition, intf.fInterfaceName, fields);
-    fSymbolTable->takeOwnership(type);
+    old->takeOwnership(type);
     SkString name = intf.fValueName.size() > 0 ? intf.fValueName : intf.fInterfaceName;
     Variable* var = new Variable(intf.fPosition, intf.fModifiers, name, *type,
                                  Variable::kGlobal_Storage);
-    fSymbolTable->takeOwnership(var);
+    old->takeOwnership(var);
     if (intf.fValueName.size()) {
         old->addWithoutOwnership(intf.fValueName, var);
     } else {
@@ -624,19 +624,22 @@
                                                                             f->fFunctions));
         }
         case Symbol::kVariable_Kind: {
-            const Variable* var = (const Variable*) result;
-            this->markReadFrom(*var);
+            Variable* var = (Variable*) result;
             if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
                 fSettings->fFlipY &&
                 (!fSettings->fCaps || !fSettings->fCaps->fragCoordConventionsExtensionString())) {
                 fInputs.fRTHeight = true;
             }
-            return std::unique_ptr<VariableReference>(new VariableReference(identifier.fPosition,
-                                                                            *var));
+            // default to kRead_RefKind; this will be corrected later if the variable is written to
+            return std::unique_ptr<VariableReference>(new VariableReference(
+                                                                 identifier.fPosition,
+                                                                 *var,
+                                                                 VariableReference::kRead_RefKind));
         }
         case Symbol::kField_Kind: {
             const Field* field = (const Field*) result;
-            VariableReference* base = new VariableReference(identifier.fPosition, field->fOwner);
+            VariableReference* base = new VariableReference(identifier.fPosition, field->fOwner,
+                                                            VariableReference::kRead_RefKind);
             return std::unique_ptr<Expression>(new FieldAccess(
                                                   std::unique_ptr<Expression>(base),
                                                   field->fFieldIndex,
@@ -690,28 +693,6 @@
     return left.kind() == Type::kVector_Kind && right.kind() == Type::kMatrix_Kind;
 }
 
-static bool is_assignment(Token::Kind op) {
-    switch (op) {
-        case Token::EQ:           // fall through
-        case Token::PLUSEQ:       // fall through
-        case Token::MINUSEQ:      // fall through
-        case Token::STAREQ:       // fall through
-        case Token::SLASHEQ:      // fall through
-        case Token::PERCENTEQ:    // fall through
-        case Token::SHLEQ:        // fall through
-        case Token::SHREQ:        // fall through
-        case Token::BITWISEOREQ:  // fall through
-        case Token::BITWISEXOREQ: // fall through
-        case Token::BITWISEANDEQ: // fall through
-        case Token::LOGICALOREQ:  // fall through
-        case Token::LOGICALXOREQ: // fall through
-        case Token::LOGICALANDEQ:
-            return true;
-        default:
-            return false;
-    }
-}
-
 /**
  * Determines the operand and result types of a binary expression. Returns true if the expression is
  * legal, false otherwise. If false, the values of the out parameters are undefined.
@@ -842,14 +823,9 @@
     return false;
 }
 
-/**
- * If both operands are compile-time constants and can be folded, returns an expression representing
- * the folded value. Otherwise, returns null. Note that unlike most other functions here, null does
- * not represent a compilation error.
- */
 std::unique_ptr<Expression> IRGenerator::constantFold(const Expression& left,
                                                       Token::Kind op,
-                                                      const Expression& right) {
+                                                      const Expression& right) const {
     // Note that we expressly do not worry about precision and overflow here -- we use the maximum
     // precision to calculate the results and hope the result makes sense. The plan is to move the
     // Skia caps into SkSL, so we have access to all of them including the precisions of the various
@@ -943,15 +919,16 @@
     const Type* rightType;
     const Type* resultType;
     if (!determine_binary_type(fContext, expression.fOperator, left->fType, right->fType, &leftType,
-                               &rightType, &resultType, !is_assignment(expression.fOperator))) {
+                               &rightType, &resultType,
+                               !Token::IsAssignment(expression.fOperator))) {
         fErrors.error(expression.fPosition, "type mismatch: '" +
                                             Token::OperatorName(expression.fOperator) +
                                             "' cannot operate on '" + left->fType.fName +
                                             "', '" + right->fType.fName + "'");
         return nullptr;
     }
-    if (is_assignment(expression.fOperator)) {
-        this->markWrittenTo(*left);
+    if (Token::IsAssignment(expression.fOperator)) {
+        this->markWrittenTo(*left, expression.fOperator != Token::EQ);
     }
     left = this->coerce(std::move(left), *leftType);
     right = this->coerce(std::move(right), *rightType);
@@ -1051,7 +1028,7 @@
             return nullptr;
         }
         if (arguments[i] && (function.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag)) {
-            this->markWrittenTo(*arguments[i]);
+            this->markWrittenTo(*arguments[i], true);
         }
     }
     return std::unique_ptr<FunctionCall>(new FunctionCall(position, *returnType, function,
@@ -1261,7 +1238,7 @@
                               "' cannot operate on '" + base->fType.description() + "'");
                 return nullptr;
             }
-            this->markWrittenTo(*base);
+            this->markWrittenTo(*base, true);
             break;
         case Token::MINUSMINUS:
             if (!base->fType.isNumber()) {
@@ -1270,7 +1247,7 @@
                               "' cannot operate on '" + base->fType.description() + "'");
                 return nullptr;
             }
-            this->markWrittenTo(*base);
+            this->markWrittenTo(*base, true);
             break;
         case Token::LOGICALNOT:
             if (base->fType != *fContext.fBool_Type) {
@@ -1464,7 +1441,7 @@
                               "'++' cannot operate on '" + base->fType.description() + "'");
                 return nullptr;
             }
-            this->markWrittenTo(*base);
+            this->markWrittenTo(*base, true);
             return std::unique_ptr<Expression>(new PostfixExpression(std::move(base),
                                                                      Token::PLUSPLUS));
         case ASTSuffix::kPostDecrement_Kind:
@@ -1473,7 +1450,7 @@
                               "'--' cannot operate on '" + base->fType.description() + "'");
                 return nullptr;
             }
-            this->markWrittenTo(*base);
+            this->markWrittenTo(*base, true);
             return std::unique_ptr<Expression>(new PostfixExpression(std::move(base),
                                                                      Token::MINUSMINUS));
         default:
@@ -1496,10 +1473,6 @@
     }
 }
 
-void IRGenerator::markReadFrom(const Variable& var) {
-    var.fIsReadFrom = true;
-}
-
 static bool has_duplicates(const Swizzle& swizzle) {
     int bits = 0;
     for (int idx : swizzle.fComponents) {
@@ -1513,7 +1486,7 @@
     return false;
 }
 
-void IRGenerator::markWrittenTo(const Expression& expr) {
+void IRGenerator::markWrittenTo(const Expression& expr, bool readWrite) {
     switch (expr.fKind) {
         case Expression::kVariableReference_Kind: {
             const Variable& var = ((VariableReference&) expr).fVariable;
@@ -1521,21 +1494,22 @@
                 fErrors.error(expr.fPosition,
                               "cannot modify immutable variable '" + var.fName + "'");
             }
-            var.fIsWrittenTo = true;
+            ((VariableReference&) expr).setRefKind(readWrite ? VariableReference::kReadWrite_RefKind
+                                                             : VariableReference::kWrite_RefKind);
             break;
         }
         case Expression::kFieldAccess_Kind:
-            this->markWrittenTo(*((FieldAccess&) expr).fBase);
+            this->markWrittenTo(*((FieldAccess&) expr).fBase, readWrite);
             break;
         case Expression::kSwizzle_Kind:
             if (has_duplicates((Swizzle&) expr)) {
                 fErrors.error(expr.fPosition,
                               "cannot write to the same swizzle field more than once");
             }
-            this->markWrittenTo(*((Swizzle&) expr).fBase);
+            this->markWrittenTo(*((Swizzle&) expr).fBase, readWrite);
             break;
         case Expression::kIndex_Kind:
-            this->markWrittenTo(*((IndexExpression&) expr).fBase);
+            this->markWrittenTo(*((IndexExpression&) expr).fBase, readWrite);
             break;
         default:
             fErrors.error(expr.fPosition, "cannot assign to '" + expr.description() + "'");
diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h
index 13b20fb..2ffcb0d 100644
--- a/src/sksl/SkSLIRGenerator.h
+++ b/src/sksl/SkSLIRGenerator.h
@@ -88,7 +88,16 @@
     std::unique_ptr<ModifiersDeclaration> convertModifiersDeclaration(
                                                                   const ASTModifiersDeclaration& m);
 
+    /**
+     * If both operands are compile-time constants and can be folded, returns an expression
+     * representing the folded value. Otherwise, returns null. Note that unlike most other functions
+     * here, null does not represent a compilation error.
+     */
+    std::unique_ptr<Expression> constantFold(const Expression& left,
+                                             Token::Kind op,
+                                             const Expression& right) const;
     Program::Inputs fInputs;
+    const Context& fContext;
 
 private:
     /**
@@ -124,11 +133,6 @@
     std::unique_ptr<Statement> convertDiscard(const ASTDiscardStatement& d);
     std::unique_ptr<Statement> convertDo(const ASTDoStatement& d);
     std::unique_ptr<Expression> convertBinaryExpression(const ASTBinaryExpression& expression);
-    // Returns null if it cannot fold the expression. Note that unlike most other functions here, a
-    // null return does not represent a compilation error.
-    std::unique_ptr<Expression> constantFold(const Expression& left,
-                                             Token::Kind op,
-                                             const Expression& right);
     std::unique_ptr<Extension> convertExtension(const ASTExtension& e);
     std::unique_ptr<Statement> convertExpressionStatement(const ASTExpressionStatement& s);
     std::unique_ptr<Statement> convertFor(const ASTForStatement& f);
@@ -151,10 +155,8 @@
     std::unique_ptr<Statement> convertWhile(const ASTWhileStatement& w);
 
     void checkValid(const Expression& expr);
-    void markReadFrom(const Variable& var);
-    void markWrittenTo(const Expression& expr);
+    void markWrittenTo(const Expression& expr, bool readWrite);
 
-    const Context& fContext;
     const FunctionDeclaration* fCurrentFunction;
     const Program::Settings* fSettings;
     std::unordered_map<SkString, CapValue> fCapsMap;
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp
index 8afd136..d43e4c4 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp
@@ -2540,7 +2540,7 @@
             kind != Program::kFragment_Kind) {
             continue;
         }
-        if (!var->fIsReadFrom && !var->fIsWrittenTo &&
+        if (!var->fReadCount && !var->fWriteCount &&
                 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
                                             Modifiers::kOut_Flag |
                                             Modifiers::kUniform_Flag))) {
diff --git a/src/sksl/SkSLToken.h b/src/sksl/SkSLToken.h
index 5c8c2bd..197781f 100644
--- a/src/sksl/SkSLToken.h
+++ b/src/sksl/SkSLToken.h
@@ -160,6 +160,28 @@
     , fKind(kind)
     , fText(std::move(text)) {}
 
+    static bool IsAssignment(Token::Kind op) {
+        switch (op) {
+            case Token::EQ:           // fall through
+            case Token::PLUSEQ:       // fall through
+            case Token::MINUSEQ:      // fall through
+            case Token::STAREQ:       // fall through
+            case Token::SLASHEQ:      // fall through
+            case Token::PERCENTEQ:    // fall through
+            case Token::SHLEQ:        // fall through
+            case Token::SHREQ:        // fall through
+            case Token::BITWISEOREQ:  // fall through
+            case Token::BITWISEXOREQ: // fall through
+            case Token::BITWISEANDEQ: // fall through
+            case Token::LOGICALOREQ:  // fall through
+            case Token::LOGICALXOREQ: // fall through
+            case Token::LOGICALANDEQ:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     Position fPosition;
     Kind fKind;
     // will be the empty string unless the token has variable text content (identifiers, numeric
diff --git a/src/sksl/ir/SkSLBinaryExpression.h b/src/sksl/ir/SkSLBinaryExpression.h
index 132513e..de85e48 100644
--- a/src/sksl/ir/SkSLBinaryExpression.h
+++ b/src/sksl/ir/SkSLBinaryExpression.h
@@ -4,17 +4,19 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_BINARYEXPRESSION
 #define SKSL_BINARYEXPRESSION
 
 #include "SkSLExpression.h"
+#include "SkSLExpression.h"
+#include "../SkSLIRGenerator.h"
 #include "../SkSLToken.h"
 
 namespace SkSL {
 
 /**
- * A binary operation. 
+ * A binary operation.
  */
 struct BinaryExpression : public Expression {
     BinaryExpression(Position position, std::unique_ptr<Expression> left, Token::Kind op,
@@ -24,14 +26,22 @@
     , fOperator(op)
     , fRight(std::move(right)) {}
 
+    virtual std::unique_ptr<Expression> constantPropagate(
+                                                        const IRGenerator& irGenerator,
+                                                        const DefinitionMap& definitions) override {
+        return irGenerator.constantFold(*fLeft,
+                                        fOperator,
+                                        *fRight);
+    }
+
     virtual SkString description() const override {
         return "(" + fLeft->description() + " " + Token::OperatorName(fOperator) + " " +
                fRight->description() + ")";
     }
 
-    const std::unique_ptr<Expression> fLeft;
+    std::unique_ptr<Expression> fLeft;
     const Token::Kind fOperator;
-    const std::unique_ptr<Expression> fRight;
+    std::unique_ptr<Expression> fRight;
 
     typedef Expression INHERITED;
 };
diff --git a/src/sksl/ir/SkSLBlock.h b/src/sksl/ir/SkSLBlock.h
index f975d16..17970fd 100644
--- a/src/sksl/ir/SkSLBlock.h
+++ b/src/sksl/ir/SkSLBlock.h
@@ -20,8 +20,8 @@
     Block(Position position, std::vector<std::unique_ptr<Statement>> statements,
           const std::shared_ptr<SymbolTable> symbols)
     : INHERITED(position, kBlock_Kind)
-    , fStatements(std::move(statements))
-    , fSymbols(std::move(symbols)) {}
+    , fSymbols(std::move(symbols))
+    , fStatements(std::move(statements)) {}
 
     SkString description() const override {
         SkString result("{");
@@ -33,8 +33,10 @@
         return result;
     }
 
-    const std::vector<std::unique_ptr<Statement>> fStatements;
+    // it's important to keep fStatements defined after (and thus destroyed before) fSymbols,
+    // because destroying statements can modify reference counts in symbols
     const std::shared_ptr<SymbolTable> fSymbols;
+    const std::vector<std::unique_ptr<Statement>> fStatements;
 
     typedef Statement INHERITED;
 };
diff --git a/src/sksl/ir/SkSLConstructor.h b/src/sksl/ir/SkSLConstructor.h
index 63c692b..691bea1 100644
--- a/src/sksl/ir/SkSLConstructor.h
+++ b/src/sksl/ir/SkSLConstructor.h
@@ -9,6 +9,9 @@
 #define SKSL_CONSTRUCTOR
 
 #include "SkSLExpression.h"
+#include "SkSLFloatLiteral.h"
+#include "SkSLIntLiteral.h"
+#include "SkSLIRGenerator.h"
 
 namespace SkSL {
 
@@ -21,6 +24,20 @@
     : INHERITED(position, kConstructor_Kind, type)
     , fArguments(std::move(arguments)) {}
 
+    virtual std::unique_ptr<Expression> constantPropagate(
+                                                        const IRGenerator& irGenerator,
+                                                        const DefinitionMap& definitions) override {
+        if (fArguments.size() == 1 && fArguments[0]->fKind == Expression::kIntLiteral_Kind &&
+            // promote float(1) to 1.0
+            fType == *irGenerator.fContext.fFloat_Type) {
+            int64_t intValue = ((IntLiteral&) *fArguments[0]).fValue;
+            return std::unique_ptr<Expression>(new FloatLiteral(irGenerator.fContext,
+                                                                fPosition,
+                                                                intValue));
+        }
+        return nullptr;
+    }
+
     SkString description() const override {
         SkString result = fType.description() + "(";
         SkString separator;
@@ -42,7 +59,7 @@
         return true;
     }
 
-    const std::vector<std::unique_ptr<Expression>> fArguments;
+    std::vector<std::unique_ptr<Expression>> fArguments;
 
     typedef Expression INHERITED;
 };
diff --git a/src/sksl/ir/SkSLDoStatement.h b/src/sksl/ir/SkSLDoStatement.h
index 78c0a1b..e26d3dc 100644
--- a/src/sksl/ir/SkSLDoStatement.h
+++ b/src/sksl/ir/SkSLDoStatement.h
@@ -28,7 +28,7 @@
     }
 
     const std::unique_ptr<Statement> fStatement;
-    const std::unique_ptr<Expression> fTest;
+    std::unique_ptr<Expression> fTest;
 
     typedef Statement INHERITED;
 };
diff --git a/src/sksl/ir/SkSLExpression.h b/src/sksl/ir/SkSLExpression.h
index b4ed37c..f87d810 100644
--- a/src/sksl/ir/SkSLExpression.h
+++ b/src/sksl/ir/SkSLExpression.h
@@ -4,17 +4,24 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_EXPRESSION
 #define SKSL_EXPRESSION
 
-#include "SkSLIRNode.h"
 #include "SkSLType.h"
+#include "SkSLVariable.h"
+
+#include <unordered_map>
 
 namespace SkSL {
 
+struct Expression;
+class IRGenerator;
+
+typedef std::unordered_map<const Variable*, std::unique_ptr<Expression>*> DefinitionMap;
+
 /**
- * Abstract supertype of all expressions. 
+ * Abstract supertype of all expressions.
  */
 struct Expression : public IRNode {
     enum Kind {
@@ -45,6 +52,18 @@
         return false;
     }
 
+    /**
+     * Given a map of known constant variable values, substitute them in for references to those
+     * variables occurring in this expression and its subexpressions.  Similar simplifications, such
+     * as folding a constant binary expression down to a single value, may also be performed.
+     * Returns a new expression which replaces this expression, or null if no replacements were
+     * made. If a new expression is returned, this expression is no longer valid.
+     */
+    virtual std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
+                                                          const DefinitionMap& definitions) {
+        return nullptr;
+    }
+
     const Kind fKind;
     const Type& fType;
 
diff --git a/src/sksl/ir/SkSLExpressionStatement.h b/src/sksl/ir/SkSLExpressionStatement.h
index 677c647..088b1c9 100644
--- a/src/sksl/ir/SkSLExpressionStatement.h
+++ b/src/sksl/ir/SkSLExpressionStatement.h
@@ -25,7 +25,7 @@
         return fExpression->description() + ";";
     }
 
-    const std::unique_ptr<Expression> fExpression;
+    std::unique_ptr<Expression> fExpression;
 
     typedef Statement INHERITED;
 };
diff --git a/src/sksl/ir/SkSLFieldAccess.h b/src/sksl/ir/SkSLFieldAccess.h
index fb727e0..de26a3f 100644
--- a/src/sksl/ir/SkSLFieldAccess.h
+++ b/src/sksl/ir/SkSLFieldAccess.h
@@ -35,7 +35,7 @@
         return fBase->description() + "." + fBase->fType.fields()[fFieldIndex].fName;
     }
 
-    const std::unique_ptr<Expression> fBase;
+    std::unique_ptr<Expression> fBase;
     const int fFieldIndex;
     const OwnerKind fOwnerKind;
 
diff --git a/src/sksl/ir/SkSLForStatement.h b/src/sksl/ir/SkSLForStatement.h
index ff03d0d..f2bf880 100644
--- a/src/sksl/ir/SkSLForStatement.h
+++ b/src/sksl/ir/SkSLForStatement.h
@@ -22,11 +22,11 @@
                  std::unique_ptr<Expression> test, std::unique_ptr<Expression> next, 
                  std::unique_ptr<Statement> statement, std::shared_ptr<SymbolTable> symbols)
     : INHERITED(position, kFor_Kind)
+    , fSymbols(symbols)
     , fInitializer(std::move(initializer))
     , fTest(std::move(test))
     , fNext(std::move(next))
-    , fStatement(std::move(statement))
-    , fSymbols(symbols) {}
+    , fStatement(std::move(statement)) {}
 
     SkString description() const override {
         SkString result("for (");
@@ -45,11 +45,13 @@
         return result;
     }
 
-    const std::unique_ptr<Statement> fInitializer;
-    const std::unique_ptr<Expression> fTest;
-    const std::unique_ptr<Expression> fNext;
-    const std::unique_ptr<Statement> fStatement;
+    // it's important to keep fSymbols defined first (and thus destroyed last) because destroying
+    // the other fields can update symbol reference counts
     const std::shared_ptr<SymbolTable> fSymbols;
+    const std::unique_ptr<Statement> fInitializer;
+    std::unique_ptr<Expression> fTest;
+    std::unique_ptr<Expression> fNext;
+    const std::unique_ptr<Statement> fStatement;
 
     typedef Statement INHERITED;
 };
diff --git a/src/sksl/ir/SkSLFunctionCall.h b/src/sksl/ir/SkSLFunctionCall.h
index 971af36..1838076 100644
--- a/src/sksl/ir/SkSLFunctionCall.h
+++ b/src/sksl/ir/SkSLFunctionCall.h
@@ -36,7 +36,7 @@
     }
 
     const FunctionDeclaration& fFunction;
-    const std::vector<std::unique_ptr<Expression>> fArguments;
+    std::vector<std::unique_ptr<Expression>> fArguments;
 
     typedef Expression INHERITED;
 };
diff --git a/src/sksl/ir/SkSLIfStatement.h b/src/sksl/ir/SkSLIfStatement.h
index f8beded..8667e93 100644
--- a/src/sksl/ir/SkSLIfStatement.h
+++ b/src/sksl/ir/SkSLIfStatement.h
@@ -32,7 +32,7 @@
         return result;
     }
 
-    const std::unique_ptr<Expression> fTest;
+    std::unique_ptr<Expression> fTest;
     const std::unique_ptr<Statement> fIfTrue;
     const std::unique_ptr<Statement> fIfFalse;
 
diff --git a/src/sksl/ir/SkSLIndexExpression.h b/src/sksl/ir/SkSLIndexExpression.h
index 079dde5..d255c7d 100644
--- a/src/sksl/ir/SkSLIndexExpression.h
+++ b/src/sksl/ir/SkSLIndexExpression.h
@@ -55,8 +55,8 @@
         return fBase->description() + "[" + fIndex->description() + "]";
     }
 
-    const std::unique_ptr<Expression> fBase;
-    const std::unique_ptr<Expression> fIndex;
+    std::unique_ptr<Expression> fBase;
+    std::unique_ptr<Expression> fIndex;
 
     typedef Expression INHERITED;
 };
diff --git a/src/sksl/ir/SkSLPostfixExpression.h b/src/sksl/ir/SkSLPostfixExpression.h
index 01671b5..6c9fafe 100644
--- a/src/sksl/ir/SkSLPostfixExpression.h
+++ b/src/sksl/ir/SkSLPostfixExpression.h
@@ -25,7 +25,7 @@
         return fOperand->description() + Token::OperatorName(fOperator);
     }
 
-    const std::unique_ptr<Expression> fOperand;
+    std::unique_ptr<Expression> fOperand;
     const Token::Kind fOperator;
 
     typedef Expression INHERITED;
diff --git a/src/sksl/ir/SkSLPrefixExpression.h b/src/sksl/ir/SkSLPrefixExpression.h
index 790c5ab..b7db99a 100644
--- a/src/sksl/ir/SkSLPrefixExpression.h
+++ b/src/sksl/ir/SkSLPrefixExpression.h
@@ -25,7 +25,7 @@
         return Token::OperatorName(fOperator) + fOperand->description();
     }
 
-    const std::unique_ptr<Expression> fOperand;
+    std::unique_ptr<Expression> fOperand;
     const Token::Kind fOperator;
 
     typedef Expression INHERITED;
diff --git a/src/sksl/ir/SkSLProgram.h b/src/sksl/ir/SkSLProgram.h
index ac49d6d..6a73be6 100644
--- a/src/sksl/ir/SkSLProgram.h
+++ b/src/sksl/ir/SkSLProgram.h
@@ -59,8 +59,8 @@
     , fSettings(settings)
     , fDefaultPrecision(defaultPrecision)
     , fContext(context)
-    , fElements(std::move(elements))
     , fSymbols(symbols)
+    , fElements(std::move(elements))
     , fInputs(inputs) {}
 
     Kind fKind;
@@ -68,8 +68,10 @@
     // FIXME handle different types; currently it assumes this is for floats
     Modifiers::Flag fDefaultPrecision;
     Context* fContext;
-    std::vector<std::unique_ptr<ProgramElement>> fElements;
+    // it's important to keep fElements defined after (and thus destroyed before) fSymbols,
+    // because destroying elements can modify reference counts in symbols
     std::shared_ptr<SymbolTable> fSymbols;
+    std::vector<std::unique_ptr<ProgramElement>> fElements;
     Inputs fInputs;
 };
 
diff --git a/src/sksl/ir/SkSLReturnStatement.h b/src/sksl/ir/SkSLReturnStatement.h
index c83b450..dc5ec9a 100644
--- a/src/sksl/ir/SkSLReturnStatement.h
+++ b/src/sksl/ir/SkSLReturnStatement.h
@@ -32,7 +32,7 @@
         }
     }
 
-    const std::unique_ptr<Expression> fExpression;
+    std::unique_ptr<Expression> fExpression;
 
     typedef Statement INHERITED;
 };
diff --git a/src/sksl/ir/SkSLSwizzle.h b/src/sksl/ir/SkSLSwizzle.h
index c9397ae..8ad9001 100644
--- a/src/sksl/ir/SkSLSwizzle.h
+++ b/src/sksl/ir/SkSLSwizzle.h
@@ -76,7 +76,7 @@
         return result;
     }
 
-    const std::unique_ptr<Expression> fBase;
+    std::unique_ptr<Expression> fBase;
     const std::vector<int> fComponents;
 
     typedef Expression INHERITED;
diff --git a/src/sksl/ir/SkSLTernaryExpression.h b/src/sksl/ir/SkSLTernaryExpression.h
index 4a35253..0275004 100644
--- a/src/sksl/ir/SkSLTernaryExpression.h
+++ b/src/sksl/ir/SkSLTernaryExpression.h
@@ -31,9 +31,9 @@
                fIfFalse->description() + ")";
     }
 
-    const std::unique_ptr<Expression> fTest;
-    const std::unique_ptr<Expression> fIfTrue;
-    const std::unique_ptr<Expression> fIfFalse;
+    std::unique_ptr<Expression> fTest;
+    std::unique_ptr<Expression> fIfTrue;
+    std::unique_ptr<Expression> fIfFalse;
 
     typedef Expression INHERITED;
 };
diff --git a/src/sksl/ir/SkSLVarDeclarations.h b/src/sksl/ir/SkSLVarDeclarations.h
index 295c0b6..490259a 100644
--- a/src/sksl/ir/SkSLVarDeclarations.h
+++ b/src/sksl/ir/SkSLVarDeclarations.h
@@ -72,7 +72,7 @@
     }
 
     const Type& fBaseType;
-    const std::vector<VarDeclaration> fVars;
+    std::vector<VarDeclaration> fVars;
 
     typedef ProgramElement INHERITED;
 };
diff --git a/src/sksl/ir/SkSLVarDeclarationsStatement.h b/src/sksl/ir/SkSLVarDeclarationsStatement.h
index 7a29656..66b570f 100644
--- a/src/sksl/ir/SkSLVarDeclarationsStatement.h
+++ b/src/sksl/ir/SkSLVarDeclarationsStatement.h
@@ -18,14 +18,14 @@
  */
 struct VarDeclarationsStatement : public Statement {
     VarDeclarationsStatement(std::unique_ptr<VarDeclarations> decl)
-    : INHERITED(decl->fPosition, kVarDeclarations_Kind) 
+    : INHERITED(decl->fPosition, kVarDeclarations_Kind)
     , fDeclaration(std::move(decl)) {}
 
     SkString description() const override {
         return fDeclaration->description();
     }
 
-    const std::shared_ptr<VarDeclarations> fDeclaration;
+    std::shared_ptr<VarDeclarations> fDeclaration;
 
     typedef Statement INHERITED;
 };
diff --git a/src/sksl/ir/SkSLVariable.h b/src/sksl/ir/SkSLVariable.h
index 39b8482..2c3391d 100644
--- a/src/sksl/ir/SkSLVariable.h
+++ b/src/sksl/ir/SkSLVariable.h
@@ -33,8 +33,8 @@
     , fModifiers(modifiers)
     , fType(type)
     , fStorage(storage)
-    , fIsReadFrom(false)
-    , fIsWrittenTo(false) {}
+    , fReadCount(0)
+    , fWriteCount(0) {}
 
     virtual SkString description() const override {
         return fModifiers.description() + fType.fName + " " + fName;
@@ -44,8 +44,12 @@
     const Type& fType;
     const Storage fStorage;
 
-    mutable bool fIsReadFrom;
-    mutable bool fIsWrittenTo;
+    // Tracks how many sites read from the variable. If this is zero for a non-out variable (or
+    // becomes zero during optimization), the variable is dead and may be eliminated.
+    mutable int fReadCount;
+    // Tracks how many sites write to the variable. If this is zero, the variable is dead and may be
+    // eliminated.
+    mutable int fWriteCount;
 
     typedef Symbol INHERITED;
 };
diff --git a/src/sksl/ir/SkSLVariableReference.h b/src/sksl/ir/SkSLVariableReference.h
index c6a2ea0..fecb04e 100644
--- a/src/sksl/ir/SkSLVariableReference.h
+++ b/src/sksl/ir/SkSLVariableReference.h
@@ -20,16 +20,83 @@
  * there is only one Variable 'x', but two VariableReferences to it.
  */
 struct VariableReference : public Expression {
-    VariableReference(Position position, const Variable& variable)
+    enum RefKind {
+        kRead_RefKind,
+        kWrite_RefKind,
+        kReadWrite_RefKind
+    };
+
+    VariableReference(Position position, const Variable& variable, RefKind refKind = kRead_RefKind)
     : INHERITED(position, kVariableReference_Kind, variable.fType)
-    , fVariable(variable) {}
+    , fVariable(variable)
+    , fRefKind(refKind) {
+        if (refKind != kRead_RefKind) {
+            fVariable.fWriteCount++;
+        }
+        if (refKind != kWrite_RefKind) {
+            fVariable.fReadCount++;
+        }
+    }
+
+    virtual ~VariableReference() override {
+        if (fRefKind != kWrite_RefKind) {
+            fVariable.fReadCount--;
+        }
+    }
+
+    RefKind refKind() {
+        return fRefKind;
+    }
+
+    void setRefKind(RefKind refKind) {
+        if (fRefKind != kRead_RefKind) {
+            fVariable.fWriteCount--;
+        }
+        if (fRefKind != kWrite_RefKind) {
+            fVariable.fReadCount--;
+        }
+        if (refKind != kRead_RefKind) {
+            fVariable.fWriteCount++;
+        }
+        if (refKind != kWrite_RefKind) {
+            fVariable.fReadCount++;
+        }
+        fRefKind = refKind;
+    }
 
     SkString description() const override {
         return fVariable.fName;
     }
 
+    virtual std::unique_ptr<Expression> constantPropagate(
+                                                        const IRGenerator& irGenerator,
+                                                        const DefinitionMap& definitions) override {
+        auto exprIter = definitions.find(&fVariable);
+        if (exprIter != definitions.end() && exprIter->second) {
+            const Expression* expr = exprIter->second->get();
+            switch (expr->fKind) {
+                case Expression::kIntLiteral_Kind:
+                    return std::unique_ptr<Expression>(new IntLiteral(
+                                                                     irGenerator.fContext,
+                                                                     Position(),
+                                                                     ((IntLiteral*) expr)->fValue));
+                case Expression::kFloatLiteral_Kind:
+                    return std::unique_ptr<Expression>(new FloatLiteral(
+                                                                   irGenerator.fContext,
+                                                                   Position(),
+                                                                   ((FloatLiteral*) expr)->fValue));
+                default:
+                    break;
+            }
+        }
+        return nullptr;
+    }
+
     const Variable& fVariable;
 
+private:
+    RefKind fRefKind;
+
     typedef Expression INHERITED;
 };
 
diff --git a/src/sksl/ir/SkSLWhileStatement.h b/src/sksl/ir/SkSLWhileStatement.h
index 7c6a290..a741a04 100644
--- a/src/sksl/ir/SkSLWhileStatement.h
+++ b/src/sksl/ir/SkSLWhileStatement.h
@@ -27,7 +27,7 @@
         return "while (" + fTest->description() + ") " + fStatement->description();
     }
 
-    const std::unique_ptr<Expression> fTest;
+    std::unique_ptr<Expression> fTest;
     const std::unique_ptr<Statement> fStatement;
 
     typedef Statement INHERITED;
diff --git a/src/utils/SkCanvasStateUtils.cpp b/src/utils/SkCanvasStateUtils.cpp
index 6dd0ca3..a78f343 100644
--- a/src/utils/SkCanvasStateUtils.cpp
+++ b/src/utils/SkCanvasStateUtils.cpp
@@ -202,8 +202,11 @@
     std::unique_ptr<SkCanvasState_v1> canvasState(new SkCanvasState_v1(canvas));
 
     // decompose the total matrix and clip
-    setup_MC_state(&canvasState->mcState, canvas->getTotalMatrix(),
-                   canvas->internal_private_getTotalClip());
+    {
+        SkRegion rgn;
+        canvas->temporary_internal_getRgnClip(&rgn);
+        setup_MC_state(&canvasState->mcState, canvas->getTotalMatrix(), rgn);
+    }
 
     /*
      * decompose the layers
diff --git a/src/utils/SkLua.cpp b/src/utils/SkLua.cpp
index 27127df..7ba98e5 100644
--- a/src/utils/SkLua.cpp
+++ b/src/utils/SkLua.cpp
@@ -8,7 +8,7 @@
 #include "SkLua.h"
 
 #if SK_SUPPORT_GPU
-#include "GrReducedClip.h"
+//#include "GrReducedClip.h"
 #endif
 
 #include "SkBlurImageFilter.h"
@@ -349,73 +349,6 @@
     CHECK_SETFIELD(key);
 }
 
-static const char* element_type(SkClipStack::Element::Type type) {
-    switch (type) {
-        case SkClipStack::Element::kEmpty_Type:
-            return "empty";
-        case SkClipStack::Element::kRect_Type:
-            return "rect";
-        case SkClipStack::Element::kRRect_Type:
-            return "rrect";
-        case SkClipStack::Element::kPath_Type:
-            return "path";
-    }
-    return "unknown";
-}
-
-static const char* region_op(SkRegion::Op op) {
-    switch (op) {
-        case SkRegion::kDifference_Op:
-            return "difference";
-        case SkRegion::kIntersect_Op:
-            return "intersect";
-        case SkRegion::kUnion_Op:
-            return "union";
-        case SkRegion::kXOR_Op:
-            return "xor";
-        case SkRegion::kReverseDifference_Op:
-            return "reverse-difference";
-        case SkRegion::kReplace_Op:
-            return "replace";
-    }
-    return "unknown";
-}
-
-void SkLua::pushClipStack(const SkClipStack& stack, const char* key) {
-    lua_newtable(fL);
-    SkClipStack::B2TIter iter(stack);
-    const SkClipStack::Element* element;
-    int i = 0;
-    while ((element = iter.next())) {
-        this->pushClipStackElement(*element);
-        lua_rawseti(fL, -2, ++i);
-    }
-    CHECK_SETFIELD(key);
-}
-
-void SkLua::pushClipStackElement(const SkClipStack::Element& element, const char* key) {
-    lua_newtable(fL);
-    SkClipStack::Element::Type type = element.getType();
-    this->pushString(element_type(type), "type");
-    switch (type) {
-        case SkClipStack::Element::kEmpty_Type:
-            break;
-        case SkClipStack::Element::kRect_Type:
-            this->pushRect(element.getRect(), "rect");
-            break;
-        case SkClipStack::Element::kRRect_Type:
-            this->pushRRect(element.getRRect(), "rrect");
-            break;
-        case SkClipStack::Element::kPath_Type:
-            this->pushPath(element.getPath(), "path");
-            break;
-    }
-    this->pushString(region_op((SkRegion::Op)element.getOp()), "op");
-    this->pushBool(element.isAA(), "aa");
-    CHECK_SETFIELD(key);
-}
-
-
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -640,33 +573,6 @@
     return 1;
 }
 
-static int lcanvas_getClipStack(lua_State* L) {
-    SkLua(L).pushClipStack(*get_ref<SkCanvas>(L, 1)->getClipStack());
-    return 1;
-}
-
-int SkLua::lcanvas_getReducedClipStack(lua_State* L) {
-#if SK_SUPPORT_GPU
-    const SkCanvas* canvas = get_ref<SkCanvas>(L, 1);
-    SkRect queryBounds = SkRect::Make(canvas->getTopLayerBounds());
-    const GrReducedClip reducedClip(*canvas->getClipStack(), queryBounds);
-
-    GrReducedClip::ElementList::Iter iter(reducedClip.elements());
-    int i = 0;
-    lua_newtable(L);
-    while(iter.get()) {
-        SkLua(L).pushClipStackElement(*iter.get());
-        iter.next();
-        lua_rawseti(L, -2, ++i);
-    }
-    // Currently this only returns the element list to lua, not the initial state or result bounds.
-    // It could return these as additional items on the lua stack.
-    return 1;
-#else
-    return 0;
-#endif
-}
-
 static int lcanvas_save(lua_State* L) {
     lua_pushinteger(L, get_ref<SkCanvas>(L, 1)->save());
     return 1;
@@ -742,10 +648,6 @@
     { "drawTextBlob", lcanvas_drawTextBlob },
     { "getSaveCount", lcanvas_getSaveCount },
     { "getTotalMatrix", lcanvas_getTotalMatrix },
-    { "getClipStack", lcanvas_getClipStack },
-#if SK_SUPPORT_GPU
-    { "getReducedClipStack", SkLua::lcanvas_getReducedClipStack },
-#endif
     { "save", lcanvas_save },
     { "saveLayer", lcanvas_saveLayer },
     { "restore", lcanvas_restore },
diff --git a/tests/CanvasStateTest.cpp b/tests/CanvasStateTest.cpp
index 9533474..38fb3fe 100644
--- a/tests/CanvasStateTest.cpp
+++ b/tests/CanvasStateTest.cpp
@@ -306,9 +306,11 @@
     REPORTER_ASSERT(reporter, !state);
 }
 
-#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
-#include "SkClipStack.h"
 DEF_TEST(CanvasState_test_saveLayer_clip, reporter) {
+    const uint32_t dontSaveFlag = 1 << 31;    // secret flag for don't save
+#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
+    static_assert(SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag == dontSaveFlag, "");
+#endif
     const int WIDTH = 100;
     const int HEIGHT = 100;
     const int LAYER_WIDTH = 50;
@@ -321,31 +323,21 @@
     SkRect bounds = SkRect::MakeWH(SkIntToScalar(LAYER_WIDTH), SkIntToScalar(LAYER_HEIGHT));
     canvas.clipRect(SkRect::MakeWH(SkIntToScalar(WIDTH), SkIntToScalar(HEIGHT)));
 
-    // Check that saveLayer without the kClipToLayer_SaveFlag leaves the
-    // clip stack unchanged.
-    canvas.saveLayer(SkCanvas::SaveLayerRec(&bounds,
-                                            nullptr,
-                                            SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag));
-    SkRect clipStackBounds;
-    SkClipStack::BoundsType boundsType;
-    canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
-    // The clip stack will return its bounds, or it may be "full" : i.e. empty + inside_out.
-    // Either result is consistent with this test, since the canvas' size is WIDTH/HEIGHT
-    if (SkClipStack::kInsideOut_BoundsType == boundsType) {
-        REPORTER_ASSERT(reporter, clipStackBounds.isEmpty());
-    } else {
-        REPORTER_ASSERT(reporter, clipStackBounds.width() == WIDTH);
-        REPORTER_ASSERT(reporter, clipStackBounds.height() == HEIGHT);
-    }
+    SkIRect devClip;
+    // Check that saveLayer without the kClipToLayer_SaveFlag leaves the clip unchanged.
+    canvas.saveLayer(SkCanvas::SaveLayerRec(&bounds, nullptr, dontSaveFlag));
+    canvas.getClipDeviceBounds(&devClip);
+    REPORTER_ASSERT(reporter, canvas.isClipRect());
+    REPORTER_ASSERT(reporter, devClip.width() == WIDTH);
+    REPORTER_ASSERT(reporter, devClip.height() == HEIGHT);
     canvas.restore();
 
     // Check that saveLayer with the kClipToLayer_SaveFlag sets the clip
     // stack to the layer bounds.
     canvas.saveLayer(&bounds, nullptr);
-    canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
-    REPORTER_ASSERT(reporter, clipStackBounds.width() == LAYER_WIDTH);
-    REPORTER_ASSERT(reporter, clipStackBounds.height() == LAYER_HEIGHT);
-
+    canvas.getClipDeviceBounds(&devClip);
+    REPORTER_ASSERT(reporter, canvas.isClipRect());
+    REPORTER_ASSERT(reporter, devClip.width() == LAYER_WIDTH);
+    REPORTER_ASSERT(reporter, devClip.height() == LAYER_HEIGHT);
     canvas.restore();
 }
-#endif
diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp
index a85f016..8448f4c 100644
--- a/tests/ClipStackTest.cpp
+++ b/tests/ClipStackTest.cpp
@@ -1456,4 +1456,33 @@
 #endif
 }
 
+#include "SkSurface.h"
+DEF_GPUTEST_FOR_ALL_CONTEXTS(canvas_private_clipRgn, reporter, ctxInfo) {
+    GrContext* context = ctxInfo.grContext();
+
+    const int w = 10;
+    const int h = 10;
+    SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
+    sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
+    SkCanvas* canvas = surf->getCanvas();
+    SkRegion rgn;
+
+    canvas->temporary_internal_getRgnClip(&rgn);
+    REPORTER_ASSERT(reporter, rgn.isRect());
+    REPORTER_ASSERT(reporter, rgn.getBounds() == SkIRect::MakeWH(w, h));
+
+    canvas->save();
+    canvas->clipRect(SkRect::MakeWH(5, 5), kDifference_SkClipOp);
+    canvas->temporary_internal_getRgnClip(&rgn);
+    REPORTER_ASSERT(reporter, rgn.isComplex());
+    REPORTER_ASSERT(reporter, rgn.getBounds() == SkIRect::MakeWH(w, h));
+    canvas->restore();
+
+    canvas->save();
+    canvas->clipRRect(SkRRect::MakeOval(SkRect::MakeLTRB(3, 3, 7, 7)));
+    canvas->temporary_internal_getRgnClip(&rgn);
+    REPORTER_ASSERT(reporter, rgn.isComplex());
+    REPORTER_ASSERT(reporter, rgn.getBounds() == SkIRect::MakeLTRB(3, 3, 7, 7));
+    canvas->restore();
+}
 #endif
diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp
index 12ac4d1..1501dc5 100644
--- a/tests/SkSLGLSLTest.cpp
+++ b/tests/SkSLGLSLTest.cpp
@@ -61,7 +61,7 @@
          "while (i < 10) sk_FragColor *= 0.5;"
          "do { sk_FragColor += 0.01; } while (sk_FragColor.x < 0.75);"
          "for (int i = 0; i < 10; i++) {"
-         "if (i % 0 == 1) break; else continue;"
+         "if (i % 2 == 1) break; else continue;"
          "}"
          "return;"
          "}",
@@ -75,12 +75,12 @@
          "        discard;\n"
          "    }\n"
          "    int i = 0;\n"
-         "    while (i < 10) sk_FragColor *= 0.5;\n"
+         "    while (true) sk_FragColor *= 0.5;\n"
          "    do {\n"
          "        sk_FragColor += 0.01;\n"
          "    } while (sk_FragColor.x < 0.75);\n"
          "    for (int i = 0;i < 10; i++) {\n"
-         "        if (i % 0 == 1) break; else continue;\n"
+         "        if (i % 2 == 1) break; else continue;\n"
          "    }\n"
          "    return;\n"
          "}\n");
@@ -106,8 +106,8 @@
          "}\n"
          "void main() {\n"
          "    float x = 10.0;\n"
-         "    bar(x);\n"
-         "    sk_FragColor = vec4(x);\n"
+         "    bar(10.0);\n"
+         "    sk_FragColor = vec4(10.0);\n"
          "}\n");
 }
 
@@ -116,7 +116,7 @@
          "void main() {"
          "float x = 1, y = 2;"
          "int z = 3;"
-         "x = x + y * z * x * (y - z);"
+         "x = x - x + y * z * x * (y - z);"
          "y = x / y / z;"
          "z = (z / 2 % 3 << 4) >> 2 << 1;"
          "bool b = (x > 4) == x < 2 || 2 >= sqrt(2) && y <= z;"
@@ -139,10 +139,10 @@
          "void main() {\n"
          "    float x = 1.0, y = 2.0;\n"
          "    int z = 3;\n"
-         "    x = x + ((y * float(z)) * x) * (y - float(z));\n"
-         "    y = (x / y) / float(z);\n"
-         "    z = (((z / 2) % 3 << 4) >> 2) << 1;\n"
-         "    bool b = x > 4.0 == x < 2.0 || 2.0 >= sqrt(2.0) && y <= float(z);\n"
+         "    x = -6.0;\n"
+         "    y = -1.0;\n"
+         "    z = 8;\n"
+         "    bool b = false == true || 2.0 >= sqrt(2.0) && true;\n"
          "    x += 12.0;\n"
          "    x -= 12.0;\n"
          "    x *= (y /= float(z = 10));\n"
@@ -287,7 +287,7 @@
          "out vec4 sk_FragColor;\n"
          "void main() {\n"
          "    float x = -5.0;\n"
-         "    x = min(abs(x), 6.0);\n"
+         "    x = min(abs(-5.0), 6.0);\n"
          "}\n");
 
     test(r,
@@ -302,7 +302,7 @@
          "    float minAbsHackVar0;\n"
          "    float minAbsHackVar1;\n"
          "    float x = -5.0;\n"
-         "    x = ((minAbsHackVar0 = abs(x)) < (minAbsHackVar1 = 6.0) ? minAbsHackVar0 : "
+         "    x = ((minAbsHackVar0 = abs(-5.0)) < (minAbsHackVar1 = 6.0) ? minAbsHackVar0 : "
                                                                                 "minAbsHackVar1);\n"
          "}\n");
 }
diff --git a/tools/lua/count_reduced_clipstacks.lua b/tools/lua/count_reduced_clipstacks.lua
deleted file mode 100644
index 1ea7a44..0000000
--- a/tools/lua/count_reduced_clipstacks.lua
+++ /dev/null
@@ -1,87 +0,0 @@
-stats = {}
-
--- switch this to run on the automated scraper system
-newline = "\n"
--- newline = "\\n"
-
-function sk_scrape_startcanvas(c, fileName)
-    canvas = c
-    oldstackstr = "<invalid>"
-end
-
-function sk_scrape_endcanvas(c, fileName)
-    canvas = nil
-end
-
-function string.starts(String,Start)
-   return string.sub(String,1,string.len(Start))==Start
-end
-
-function build_stack_string(stack)
-    local info = ""
-    for i = 1, #stack do
-        local element = stack[i];
-        info = info .. element["op"] .. ", " .. element["type"] .. ", aa:" .. tostring(element["aa"])
-        if (element["type"] == "path") then
-            if (element["path"]:getSegmentTypes() == "line" and element["path"]:isConvex()) then
-                info = info .. ", convex_poly " .. element["path"]:countPoints() .. " points"
-            else
-                info = info .. ", fill: " .. element["path"]:getFillType()
-                info = info .. ", segments: (" .. element["path"]:getSegmentTypes() .. ")"
-                info = info .. ", convex:" .. tostring(element["path"]:isConvex())
-            end
-        end
-        info = info .. newline
-    end
-    return info
-end
-
-function sk_scrape_accumulate(t)
-    if (string.starts(t.verb, "draw")) then
-        local stack = canvas:getReducedClipStack()
-        local stackstr = build_stack_string(stack)
-        if (stackstr ~= "") then
-            if (stats[stackstr] == nil) then
-                stats[stackstr] = {}
-                stats[stackstr].drawCnt = 0
-                stats[stackstr].instanceCnt = 0
-            end
-            stats[stackstr].drawCnt = stats[stackstr].drawCnt + 1
-            if (stackstr ~= oldstackstr) then
-                stats[stackstr].instanceCnt = stats[stackstr].instanceCnt + 1
-            end
-        end
-        oldstackstr = stackstr
-    end
-end
-
-function print_stats(stats)
-    function sort_by_draw_cnt(a, b)
-        return a.data.drawCnt > b.data.drawCnt
-    end
-    array = {}
-    for k,v in pairs(stats) do
-        array[#array + 1] = { name = k, data = v }
-    end
-    table.sort(array, sort_by_draw_cnt)
-    for i = 1, #array do
-        io.write("\n-------\n", array[i].name, tostring(array[i].data.drawCnt), " draws, ", tostring(array[i].data.instanceCnt), " instances.\n")
-    end
-end
-
-function sk_scrape_summarize()
-    print_stats(stats)
-    --[[ To use the web scraper comment out the print above, run the code below to generate an
-         aggregate table on the automated scraper system. Then use the print_stats function on
-         agg_stats in the aggregator step.
-    for k,v in pairs(stats) do
-        if (v.drawCnt ~= nil) then
-             -- io.write("\n-------\n", k, tostring(v.drawCnt), " draws, ", tostring(v.instanceCnt), " instances.\n")
-             local tableEntry = 'agg_stats["' .. k .. '"]'
-             io.write(tableEntry, " = ", tableEntry, " or {}\n")
-             io.write(tableEntry, ".drawCnt = (", tableEntry, ".drawCnt or 0 ) + ", v.drawCnt, "\n")
-             io.write(tableEntry, ".instanceCnt = (", tableEntry, ".instanceCnt or 0 ) + ", v.instanceCnt, "\n")
-        end
-    end
-    --]]
-end
diff --git a/tools/lua/dump_clipstack_at_restore.lua b/tools/lua/dump_clipstack_at_restore.lua
deleted file mode 100644
index eb5afb9..0000000
--- a/tools/lua/dump_clipstack_at_restore.lua
+++ /dev/null
@@ -1,33 +0,0 @@
-function sk_scrape_startcanvas(c, fileName)
-    canvas = c
-    clipstack = {}
-    restoreCount = 0
-end
-
-function sk_scrape_endcanvas(c, fileName)
-    canvas = nil
-end
-
-function sk_scrape_accumulate(t)
-    if (t.verb == "restore") then
-        restoreCount = restoreCount + 1;
-        -- io.write("Clip Stack at restore #", restoreCount, ":\n")
-        io.write("Reduced Clip Stack at restore #", restoreCount, ":\n")
-        for i = 1, #clipstack do
-            local element = clipstack[i];
-            io.write("\t", element["op"], ", ", element["type"], ", aa:", tostring(element["aa"]))
-            if (element["type"] == "path") then
-                io.write(", fill: ", element["path"]:getFillType())
-                io.write(", segments: \"", element["path"]:getSegmentTypes(), "\"")
-                io.write(", convex:", tostring(element["path"]:isConvex()))
-            end
-            io.write("\n")
-        end
-        io.write("\n")
-    else
-        -- clipstack = canvas:getClipStack()
-        clipstack = canvas:getReducedClipStack()
-    end
-end
-
-function sk_scrape_summarize() end