Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 18 Aug 2017 15:53:07 -0700
changeset 375684 4f4487cc2d30d988742109868dcf21c4113f12f5
parent 375577 8febdfacc7160c9ba90ba480e8bf5cd174e4fcab (current diff)
parent 375683 65558d987c7ea5b6f35cb09c1f444c7d4353935e (diff)
child 375685 3dc98e77386986e771f615d8418348adceb65c75
child 375744 3083bebb7d9d1c7c43f57065268bde7aeb25d676
child 375797 0e304a501b52ee7e61ddcffb6998546e5494da3d
push id32358
push userkwierso@gmail.com
push dateFri, 18 Aug 2017 22:53:28 +0000
treeherdermozilla-central@4f4487cc2d30 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone57.0a1
first release with
nightly linux32
4f4487cc2d30 / 57.0a1 / 20170819100442 / files
nightly linux64
4f4487cc2d30 / 57.0a1 / 20170819100442 / files
nightly mac
4f4487cc2d30 / 57.0a1 / 20170819100442 / files
nightly win32
4f4487cc2d30 / 57.0a1 / 20170819100442 / files
nightly win64
4f4487cc2d30 / 57.0a1 / 20170819100442 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to central, a=merge MozReview-Commit-ID: 4cWGBbMEU2x
Android.mk
browser/base/content/urlbarBindings.xml
browser/themes/shared/urlbar-searchbar.inc.css
dom/base/nsContentUtils.cpp
dom/media/fmp4/MP4Decoder.cpp
dom/xul/templates/nsXULContentUtils.cpp
gfx/doc/B2GInputFlow.svg
layout/painting/nsDisplayList.cpp
media/mtransport/gonk_addrs.cpp
media/webrtc/trunk/webrtc/modules/audio_device/gonk/audio_manager.cc
media/webrtc/trunk/webrtc/modules/audio_device/gonk/audio_manager.h
modules/libpref/init/all.js
rdf/base/nsInMemoryDataSource.cpp
rdf/base/nsRDFService.cpp
testing/web-platform/meta/css/css-multicol-1/multicol-block-clip-001.xht.ini
testing/web-platform/meta/css/css-multicol-1/multicol-block-clip-002.xht.ini
testing/web-platform/meta/css/css-multicol-1/multicol-count-computed-003.xht.ini
testing/web-platform/meta/css/css-multicol-1/multicol-count-computed-005.xht.ini
testing/web-platform/meta/service-workers/service-worker/interfaces.https.html.ini
testing/web-platform/meta/streams/readable-streams/pipe-through.dedicatedworker.html.ini
testing/web-platform/meta/streams/readable-streams/pipe-through.html.ini
testing/web-platform/meta/streams/readable-streams/pipe-through.serviceworker.https.html.ini
testing/web-platform/meta/streams/readable-streams/pipe-through.sharedworker.html.ini
testing/web-platform/meta/webdriver/get_title.py.ini
testing/web-platform/meta/webdriver/interface.html.ini
testing/web-platform/meta/webdriver/status.py.ini
testing/web-platform/meta/webdriver/tests/navigation.py.ini
testing/web-platform/tests/css/css-multicol-1/multicol-block-clip-001-ref.xht
testing/web-platform/tests/css/css-multicol-1/multicol-block-clip-001.xht
testing/web-platform/tests/css/css-multicol-1/multicol-block-clip-002-ref.xht
testing/web-platform/tests/css/css-multicol-1/multicol-block-clip-002.xht
testing/web-platform/tests/css/css-position-3/sticky-input-box-position.html
testing/web-platform/tests/lint
testing/web-platform/tests/manifest
testing/web-platform/tests/serve
testing/web-platform/tests/service-workers/service-worker/interfaces.https.html
testing/web-platform/tests/service-workers/service-worker/resources/interfaces.js
testing/web-platform/tests/streams/readable-streams/pipe-through.dedicatedworker.html
testing/web-platform/tests/streams/readable-streams/pipe-through.html
testing/web-platform/tests/streams/readable-streams/pipe-through.js
testing/web-platform/tests/streams/readable-streams/pipe-through.serviceworker.https.html
testing/web-platform/tests/streams/readable-streams/pipe-through.sharedworker.html
testing/web-platform/tests/webdriver/get_title.py
testing/web-platform/tests/webdriver/interface.html
testing/web-platform/tests/webdriver/state/__init__.py
testing/web-platform/tests/webdriver/state/text/__init__.py
testing/web-platform/tests/webdriver/state/text/get_text.py
testing/web-platform/tests/webdriver/status.py
testing/web-platform/tests/webdriver/tests/cookies.py
testing/web-platform/tests/webdriver/tests/maximize_window.py
testing/web-platform/tests/webdriver/tests/navigation.py
testing/web-platform/tests/wptrun
--- a/.taskcluster.yml
+++ b/.taskcluster.yml
@@ -24,17 +24,17 @@ tasks:
           then:
             name: "Gecko Decision Task"
             description: 'The task that creates all of the other tasks in the task graph'
           else:
             name: "Decision Task for cron job ${cron.job_name}"
             description: 'Created by a [cron task](https://tools.taskcluster.net/tasks/${cron.task_id})'
 
     provisionerId: "aws-provisioner-v1"
-    workerType: "gecko-decision"
+    workerType: "gecko-${repository.level}-decision"
 
     tags:
       $if: 'tasks_for == "hg-push"'
       then: {createdForUser: "${ownerEmail}"}
 
     routes:
       $if: 'tasks_for == "hg-push"'
       then:
@@ -121,14 +121,17 @@ tasks:
       artifacts:
         'public':
           type: 'directory'
           path: '/home/worker/artifacts'
           expires: {$fromNow: '1 year'}
 
     extra:
       treeherder:
-        $if: 'tasks_for == "hg-push"'
-        then:
-          symbol: D
-        else:
-          groupSymbol: cron
-          symbol: "${cron.job_symbol}"
+        $merge:
+          - machine:
+              platform: gecko-decision
+          - $if: 'tasks_for == "hg-push"'
+            then:
+              symbol: D
+            else:
+              groupSymbol: cron
+              symbol: "${cron.job_symbol}"
deleted file mode 100644
--- a/Android.mk
+++ /dev/null
@@ -1,5 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# empty file to block B2G/Gonk from trying to build anything inside mozilla-central
--- a/accessible/jsat/PointerAdapter.jsm
+++ b/accessible/jsat/PointerAdapter.jsm
@@ -39,27 +39,16 @@ var PointerRelay = { // jshint ignore:li
     switch (Utils.widgetToolkit) {
       case "android":
         this._eventsOfInterest = {
           "touchstart": true,
           "touchmove": true,
           "touchend": true };
         break;
 
-      case "gonk":
-        this._eventsOfInterest = {
-          "touchstart": true,
-          "touchmove": true,
-          "touchend": true,
-          "mousedown": false,
-          "mousemove": false,
-          "mouseup": false,
-          "click": false };
-        break;
-
       default:
         // Desktop.
         this._eventsOfInterest = {
           "mousemove": true,
           "mousedown": true,
           "mouseup": true,
           "click": false
         };
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -43,17 +43,17 @@ file, You can obtain one at http://mozil
                       xbl:inherits="tooltiptext=inputtooltiptext,value,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,focused,textoverflow"/>
           <xul:image anonid="go-button"
                      class="urlbar-go-button"
                      onclick="gURLBar.handleCommand(event);"
                      tooltiptext="&goEndCap.tooltip;"
                      xbl:inherits="pageproxystate,parentfocused=focused"/>
         </xul:hbox>
         <xul:dropmarker anonid="historydropmarker"
-                        class="autocomplete-history-dropmarker urlbar-history-dropmarker"
+                        class="autocomplete-history-dropmarker urlbar-history-dropmarker urlbar-icon"
                         tooltiptext="&urlbar.openHistoryPopup.tooltip;"
                         allowevents="true"
                         xbl:inherits="open,enablehistory,parentfocused=focused"/>
         <children includes="hbox"/>
       </xul:hbox>
       <xul:popupset anonid="popupset"
                     class="autocomplete-result-popupset"/>
       <children includes="toolbarbutton"/>
--- a/browser/components/customizableui/content/customizeMode.inc.xul
+++ b/browser/components/customizableui/content/customizeMode.inc.xul
@@ -1,17 +1,17 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <box id="customization-container" flex="1" hidden="true">
   <box id="customization-content-container">
     <box flex="1" id="customization-palette-container">
       <label id="customization-header">
-        &customizeMode.menuAndToolbars.header2;
+        &customizeMode.menuAndToolbars.header3;
       </label>
       <hbox id="customization-empty" hidden="true">
         <label>&customizeMode.menuAndToolbars.empty;</label>
         <label onclick="BrowserOpenAddonsMgr('addons://discover/');"
                onkeypress="BrowserOpenAddonsMgr('addons://discover/');"
                id="customization-more-tools"
                class="text-link">
           &customizeMode.menuAndToolbars.emptyLink;
--- a/browser/config/tooltool-manifests/win32/l10n.manifest
+++ b/browser/config/tooltool-manifests/win32/l10n.manifest
@@ -1,8 +1,16 @@
 [
   {
     "size": 266240,
     "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
     "algorithm": "sha512",
     "filename": "mozmake.exe"
+  },
+  {
+    "size": 1436488,
+    "visibility": "public",
+    "digest": "8c34a608c83524d3ec3c9ef7f71b94ada9775bf2d7fdc843006e84205760157ae71bfa1f5836782716bbfaf63f2d003b1bb5e45f132bfbdaed3dfe5f10e8ae99",
+    "algorithm": "sha512",
+    "filename": "xz-5.2.3.zip",
+    "unpack": true
   }
 ]
--- a/browser/config/tooltool-manifests/win64/l10n.manifest
+++ b/browser/config/tooltool-manifests/win64/l10n.manifest
@@ -1,8 +1,16 @@
 [
   {
     "size": 266240,
     "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
     "algorithm": "sha512",
     "filename": "mozmake.exe"
+  },
+  {
+    "size": 1436488,
+    "visibility": "public",
+    "digest": "8c34a608c83524d3ec3c9ef7f71b94ada9775bf2d7fdc843006e84205760157ae71bfa1f5836782716bbfaf63f2d003b1bb5e45f132bfbdaed3dfe5f10e8ae99",
+    "algorithm": "sha512",
+    "filename": "xz-5.2.3.zip",
+    "unpack": true
   }
 ]
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,5 +1,5 @@
 This is the PDF.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.8.618
+Current extension version is: 1.9.441
 
-Taken from upstream commit: 21cc2c02
+Taken from upstream commit: 8c8d8fa2
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -3821,18 +3821,18 @@ var _UnsupportedManager = function Unsup
       for (var i = 0, ii = listeners.length; i < ii; i++) {
         listeners[i](featureId);
       }
     }
   };
 }();
 var version, build;
 {
-  exports.version = version = '1.8.618';
-  exports.build = build = '21cc2c02';
+  exports.version = version = '1.9.441';
+  exports.build = build = '8c8d8fa2';
 }
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass;
@@ -4872,18 +4872,18 @@ var _text_layer = __w_pdfjs_require__(5)
 var _svg = __w_pdfjs_require__(4);
 
 var isWorker = typeof window === 'undefined';
 if (!_util.globalScope.PDFJS) {
   _util.globalScope.PDFJS = {};
 }
 var PDFJS = _util.globalScope.PDFJS;
 {
-  PDFJS.version = '1.8.618';
-  PDFJS.build = '21cc2c02';
+  PDFJS.version = '1.9.441';
+  PDFJS.build = '8c8d8fa2';
 }
 PDFJS.pdfBug = false;
 if (PDFJS.verbosity !== undefined) {
   (0, _util.setVerbosityLevel)(PDFJS.verbosity);
 }
 delete PDFJS.verbosity;
 Object.defineProperty(PDFJS, 'verbosity', {
   get() {
@@ -10439,18 +10439,18 @@ exports.PDFDataTransportStream = PDFData
 
 /***/ }),
 /* 14 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '1.8.618';
-var pdfjsBuild = '21cc2c02';
+var pdfjsVersion = '1.9.441';
+var pdfjsBuild = '8c8d8fa2';
 var pdfjsSharedUtil = __w_pdfjs_require__(0);
 var pdfjsDisplayGlobal = __w_pdfjs_require__(8);
 var pdfjsDisplayAPI = __w_pdfjs_require__(3);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(5);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(2);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(1);
 var pdfjsDisplaySVG = __w_pdfjs_require__(4);
 ;
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -2462,17 +2462,17 @@ var JpxStream = function JpxStreamClosur
     jpxImage.parse(this.bytes);
     var width = jpxImage.width;
     var height = jpxImage.height;
     var componentsCount = jpxImage.componentsCount;
     var tileCount = jpxImage.tiles.length;
     if (tileCount === 1) {
       this.buffer = jpxImage.tiles[0].items;
     } else {
-      var data = new Uint8Array(width * height * componentsCount);
+      var data = new Uint8ClampedArray(width * height * componentsCount);
       for (var k = 0; k < tileCount; k++) {
         var tileComponents = jpxImage.tiles[k];
         var tileWidth = tileComponents.width;
         var tileHeight = tileComponents.height;
         var tileLeft = tileComponents.left;
         var tileTop = tileComponents.top;
         var src = tileComponents.items;
         var srcPosition = 0;
@@ -20855,91 +20855,74 @@ var JpxImage = function JpxImageClosure(
     for (var i = 0, ii = context.tiles.length; i < ii; i++) {
       var tile = context.tiles[i];
       var transformedTiles = [];
       var c;
       for (c = 0; c < componentsCount; c++) {
         transformedTiles[c] = transformTile(context, tile, c);
       }
       var tile0 = transformedTiles[0];
-      var out = new Uint8Array(tile0.items.length * componentsCount);
+      var out = new Uint8ClampedArray(tile0.items.length * componentsCount);
       var result = {
         left: tile0.left,
         top: tile0.top,
         width: tile0.width,
         height: tile0.height,
         items: out
       };
-      var shift, offset, max, min, maxK;
+      var shift, offset;
       var pos = 0,
           j,
           jj,
           y0,
           y1,
-          y2,
-          r,
-          g,
-          b,
-          k,
-          val;
+          y2;
       if (tile.codingStyleDefaultParameters.multipleComponentTransform) {
         var fourComponents = componentsCount === 4;
         var y0items = transformedTiles[0].items;
         var y1items = transformedTiles[1].items;
         var y2items = transformedTiles[2].items;
         var y3items = fourComponents ? transformedTiles[3].items : null;
         shift = components[0].precision - 8;
         offset = (128 << shift) + 0.5;
-        max = 255 * (1 << shift);
-        maxK = max * 0.5;
-        min = -maxK;
         var component0 = tile.components[0];
         var alpha01 = componentsCount - 3;
         jj = y0items.length;
         if (!component0.codingStyleParameters.reversibleTransformation) {
           for (j = 0; j < jj; j++, pos += alpha01) {
             y0 = y0items[j] + offset;
             y1 = y1items[j];
             y2 = y2items[j];
-            r = y0 + 1.402 * y2;
-            g = y0 - 0.34413 * y1 - 0.71414 * y2;
-            b = y0 + 1.772 * y1;
-            out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;
-            out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;
-            out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;
+            out[pos++] = y0 + 1.402 * y2 >> shift;
+            out[pos++] = y0 - 0.34413 * y1 - 0.71414 * y2 >> shift;
+            out[pos++] = y0 + 1.772 * y1 >> shift;
           }
         } else {
           for (j = 0; j < jj; j++, pos += alpha01) {
             y0 = y0items[j] + offset;
             y1 = y1items[j];
             y2 = y2items[j];
-            g = y0 - (y2 + y1 >> 2);
-            r = g + y2;
-            b = g + y1;
-            out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;
-            out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;
-            out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;
+            let g = y0 - (y2 + y1 >> 2);
+            out[pos++] = g + y2 >> shift;
+            out[pos++] = g >> shift;
+            out[pos++] = g + y1 >> shift;
           }
         }
         if (fourComponents) {
           for (j = 0, pos = 3; j < jj; j++, pos += 4) {
-            k = y3items[j];
-            out[pos] = k <= min ? 0 : k >= maxK ? 255 : k + offset >> shift;
+            out[pos] = y3items[j] + offset >> shift;
           }
         }
       } else {
         for (c = 0; c < componentsCount; c++) {
           var items = transformedTiles[c].items;
           shift = components[c].precision - 8;
           offset = (128 << shift) + 0.5;
-          max = 127.5 * (1 << shift);
-          min = -max;
           for (pos = c, j = 0, jj = items.length; j < jj; j++) {
-            val = items[j];
-            out[pos] = val <= min ? 0 : val >= max ? 255 : val + offset >> shift;
+            out[pos] = items[j] + offset >> shift;
             pos += componentsCount;
           }
         }
       }
       resultImages.push(result);
     }
     return resultImages;
   }
@@ -32786,17 +32769,17 @@ var PDFImage = function PDFImageClosure(
       data = new Uint8Array(computedLength);
       data.set(imgArray);
       for (i = actualLength; i < computedLength; i++) {
         data[i] = 0xff;
       }
     }
     if (inverseDecode) {
       for (i = 0; i < actualLength; i++) {
-        data[i] = ~data[i];
+        data[i] ^= 0xFF;
       }
     }
     return {
       data,
       width,
       height
     };
   };
@@ -34035,17 +34018,17 @@ var Jbig2Image = function Jbig2ImageClos
     }
     return visitor.buffer;
   }
   function SimpleSegmentVisitor() {}
   SimpleSegmentVisitor.prototype = {
     onPageInformation: function SimpleSegmentVisitor_onPageInformation(info) {
       this.currentPageInfo = info;
       var rowSize = info.width + 7 >> 3;
-      var buffer = new Uint8Array(rowSize * info.height);
+      var buffer = new Uint8ClampedArray(rowSize * info.height);
       if (info.defaultPixelValue) {
         for (var i = 0, ii = buffer.length; i < ii; i++) {
           buffer[i] = 0xFF;
         }
       }
       this.buffer = buffer;
     },
     drawBitmap: function SimpleSegmentVisitor_drawBitmap(regionInfo, bitmap) {
@@ -34647,19 +34630,16 @@ var JpegImage = function JpegImageClosur
     for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
       for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
         var offset = getBlockBufferOffset(component, blockRow, blockCol);
         quantizeAndInverse(component, offset, computationBuffer);
       }
     }
     return component.blockData;
   }
-  function clamp0to255(a) {
-    return a <= 0 ? 0 : a >= 255 ? 255 : a;
-  }
   function findNextFileMarker(data, currentPos, startPos) {
     function peekUint16(pos) {
       return data[pos] << 8 | data[pos + 1];
     }
     var maxPos = data.length - 1;
     var newPos = startPos < currentPos ? startPos : currentPos;
     if (currentPos >= maxPos) {
       return null;
@@ -34927,17 +34907,17 @@ var JpegImage = function JpegImageClosur
           scaleY = this.height / height;
       var component, componentScaleX, componentScaleY, blocksPerScanline;
       var x, y, i, j, k;
       var index;
       var offset = 0;
       var output;
       var numComponents = this.components.length;
       var dataLength = width * height * numComponents;
-      var data = new Uint8Array(dataLength);
+      var data = new Uint8ClampedArray(dataLength);
       var xScaleBlockOffset = new Uint32Array(width);
       var mask3LSB = 0xfffffff8;
       for (i = 0; i < numComponents; i++) {
         component = this.components[i];
         componentScaleX = component.scaleX * scaleX;
         componentScaleY = component.scaleY * scaleY;
         offset = i;
         output = component.output;
@@ -34981,78 +34961,71 @@ var JpegImage = function JpegImageClosur
       return false;
     },
     _convertYccToRgb: function convertYccToRgb(data) {
       var Y, Cb, Cr;
       for (var i = 0, length = data.length; i < length; i += 3) {
         Y = data[i];
         Cb = data[i + 1];
         Cr = data[i + 2];
-        data[i] = clamp0to255(Y - 179.456 + 1.402 * Cr);
-        data[i + 1] = clamp0to255(Y + 135.459 - 0.344 * Cb - 0.714 * Cr);
-        data[i + 2] = clamp0to255(Y - 226.816 + 1.772 * Cb);
+        data[i] = Y - 179.456 + 1.402 * Cr;
+        data[i + 1] = Y + 135.459 - 0.344 * Cb - 0.714 * Cr;
+        data[i + 2] = Y - 226.816 + 1.772 * Cb;
       }
       return data;
     },
     _convertYcckToRgb: function convertYcckToRgb(data) {
       var Y, Cb, Cr, k;
       var offset = 0;
       for (var i = 0, length = data.length; i < length; i += 4) {
         Y = data[i];
         Cb = data[i + 1];
         Cr = data[i + 2];
         k = data[i + 3];
-        var r = -122.67195406894 + Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr - 5.4080610064599e-5 * Y + 0.00048449797120281 * k - 0.154362151871126) + Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y - 0.00477271405408747 * k + 1.53380253221734) + Y * (0.000961250184130688 * Y - 0.00266257332283933 * k + 0.48357088451265) + k * (-0.000336197177618394 * k + 0.484791561490776);
-        var g = 107.268039397724 + Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr + 0.000659397001245577 * Y + 0.000426105652938837 * k - 0.176491792462875) + Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y + 0.000770482631801132 * k - 0.151051492775562) + Y * (0.00126935368114843 * Y - 0.00265090189010898 * k + 0.25802910206845) + k * (-0.000318913117588328 * k - 0.213742400323665);
-        var b = -20.810012546947 + Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr + 0.0020741088115012 * Y - 0.00288260236853442 * k + 0.814272968359295) + Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y + 0.000560833691242812 * k - 0.195152027534049) + Y * (0.00174418132927582 * Y - 0.00255243321439347 * k + 0.116935020465145) + k * (-0.000343531996510555 * k + 0.24165260232407);
-        data[offset++] = clamp0to255(r);
-        data[offset++] = clamp0to255(g);
-        data[offset++] = clamp0to255(b);
+        data[offset++] = -122.67195406894 + Cb * (-6.60635669420364e-5 * Cb + 0.000437130475926232 * Cr - 5.4080610064599e-5 * Y + 0.00048449797120281 * k - 0.154362151871126) + Cr * (-0.000957964378445773 * Cr + 0.000817076911346625 * Y - 0.00477271405408747 * k + 1.53380253221734) + Y * (0.000961250184130688 * Y - 0.00266257332283933 * k + 0.48357088451265) + k * (-0.000336197177618394 * k + 0.484791561490776);
+        data[offset++] = 107.268039397724 + Cb * (2.19927104525741e-5 * Cb - 0.000640992018297945 * Cr + 0.000659397001245577 * Y + 0.000426105652938837 * k - 0.176491792462875) + Cr * (-0.000778269941513683 * Cr + 0.00130872261408275 * Y + 0.000770482631801132 * k - 0.151051492775562) + Y * (0.00126935368114843 * Y - 0.00265090189010898 * k + 0.25802910206845) + k * (-0.000318913117588328 * k - 0.213742400323665);
+        data[offset++] = -20.810012546947 + Cb * (-0.000570115196973677 * Cb - 2.63409051004589e-5 * Cr + 0.0020741088115012 * Y - 0.00288260236853442 * k + 0.814272968359295) + Cr * (-1.53496057440975e-5 * Cr - 0.000132689043961446 * Y + 0.000560833691242812 * k - 0.195152027534049) + Y * (0.00174418132927582 * Y - 0.00255243321439347 * k + 0.116935020465145) + k * (-0.000343531996510555 * k + 0.24165260232407);
       }
       return data;
     },
     _convertYcckToCmyk: function convertYcckToCmyk(data) {
       var Y, Cb, Cr;
       for (var i = 0, length = data.length; i < length; i += 4) {
         Y = data[i];
         Cb = data[i + 1];
         Cr = data[i + 2];
-        data[i] = clamp0to255(434.456 - Y - 1.402 * Cr);
-        data[i + 1] = clamp0to255(119.541 - Y + 0.344 * Cb + 0.714 * Cr);
-        data[i + 2] = clamp0to255(481.816 - Y - 1.772 * Cb);
+        data[i] = 434.456 - Y - 1.402 * Cr;
+        data[i + 1] = 119.541 - Y + 0.344 * Cb + 0.714 * Cr;
+        data[i + 2] = 481.816 - Y - 1.772 * Cb;
       }
       return data;
     },
     _convertCmykToRgb: function convertCmykToRgb(data) {
       var c, m, y, k;
       var offset = 0;
-      var min = -255 * 255 * 255;
-      var scale = 1 / 255 / 255;
+      var scale = 1 / 255;
       for (var i = 0, length = data.length; i < length; i += 4) {
-        c = data[i];
-        m = data[i + 1];
-        y = data[i + 2];
-        k = data[i + 3];
-        var r = c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k - 72734.4411664936) + m * (1.7149763477362134 * m - 5.6096736904047315 * y - 17.873870861415444 * k - 1401.7366389350734) + y * (-2.5217340131683033 * y - 21.248923337353073 * k + 4465.541406466231) - k * (21.86122147463605 * k + 48317.86113160301);
-        var g = c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k - 20220.756542821975) + m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 48691.05921601825) + y * (4.444339102852739 * y + 9.8632861493405 * k - 6341.191035517494) - k * (20.737325471181034 * k + 47890.15695978492);
-        var b = c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k - 3616.812083916688) + m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 28620.90484698408) + y * (0.03296041114873217 * y + 115.60384449646641 * k - 49363.43385999684) - k * (22.33816807309886 * k + 45932.16563550634);
-        data[offset++] = r >= 0 ? 255 : r <= min ? 0 : 255 + r * scale | 0;
-        data[offset++] = g >= 0 ? 255 : g <= min ? 0 : 255 + g * scale | 0;
-        data[offset++] = b >= 0 ? 255 : b <= min ? 0 : 255 + b * scale | 0;
+        c = data[i] * scale;
+        m = data[i + 1] * scale;
+        y = data[i + 2] * scale;
+        k = data[i + 3] * scale;
+        data[offset++] = 255 + c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k - 285.2331026137004) + m * (1.7149763477362134 * m - 5.6096736904047315 * y - 17.873870861415444 * k - 5.497006427196366) + y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) - k * (21.86122147463605 * k + 189.48180835922747);
+        data[offset++] = 255 + c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k - 79.2970844816548) + m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) + y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) - k * (20.737325471181034 * k + 187.80453709719578);
+        data[offset++] = 255 + c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k - 14.183576799673286) + m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) + y * (0.03296041114873217 * y + 115.60384449646641 * k - 193.58209356861505) - k * (22.33816807309886 * k + 180.12613974708367);
       }
       return data;
     },
     getData: function getData(width, height, forceRGBoutput) {
       if (this.numComponents > 4) {
         throw new JpegError('Unsupported color mode');
       }
       var data = this._getLinearizedBlockData(width, height);
       if (this.numComponents === 1 && forceRGBoutput) {
         var dataLength = data.length;
-        var rgbData = new Uint8Array(dataLength * 3);
+        var rgbData = new Uint8ClampedArray(dataLength * 3);
         var offset = 0;
         for (var i = 0; i < dataLength; i++) {
           var grayColor = data[i];
           rgbData[offset++] = grayColor;
           rgbData[offset++] = grayColor;
           rgbData[offset++] = grayColor;
         }
         return rgbData;
@@ -39878,18 +39851,18 @@ exports.Type1Parser = Type1Parser;
 
 /***/ }),
 /* 35 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '1.8.618';
-var pdfjsBuild = '21cc2c02';
+var pdfjsVersion = '1.9.441';
+var pdfjsBuild = '8c8d8fa2';
 var pdfjsCoreWorker = __w_pdfjs_require__(17);
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 36 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
--- a/browser/extensions/pdfjs/content/web/viewer.html
+++ b/browser/extensions/pdfjs/content/web/viewer.html
@@ -30,17 +30,16 @@ See https://github.com/adobe-type-tools/
 <base href="resource://pdf.js/web/">
 <script src="../build/pdf.js"></script>
 
 
     <link rel="stylesheet" href="viewer.css">
 
 
 
-
     <script src="viewer.js"></script>
 
   </head>
 
   <body tabindex="1" class="loadingInProgress">
     <div id="outerContainer">
 
       <div id="sidebarContainer">
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -3975,36 +3975,35 @@ Object.defineProperty(exports, "__esModu
   value: true
 });
 exports.PDFAttachmentViewer = undefined;
 
 var _pdfjsLib = __webpack_require__(1);
 
 class PDFAttachmentViewer {
   constructor({ container, eventBus, downloadManager }) {
-    this.attachments = null;
     this.container = container;
     this.eventBus = eventBus;
     this.downloadManager = downloadManager;
-    this._renderedCapability = (0, _pdfjsLib.createPromiseCapability)();
+    this.reset();
     this.eventBus.on('fileattachmentannotation', this._appendAttachment.bind(this));
   }
   reset(keepRenderedCapability = false) {
     this.attachments = null;
     this.container.textContent = '';
     if (!keepRenderedCapability) {
       this._renderedCapability = (0, _pdfjsLib.createPromiseCapability)();
     }
   }
   _dispatchEvent(attachmentsCount) {
+    this._renderedCapability.resolve();
     this.eventBus.dispatch('attachmentsloaded', {
       source: this,
       attachmentsCount
     });
-    this._renderedCapability.resolve();
   }
   _bindPdfLink(button, content, filename) {
     if (_pdfjsLib.PDFJS.disableCreateObjectURL) {
       throw new Error('bindPdfLink: ' + 'Unsupported "PDFJS.disableCreateObjectURL" value.');
     }
     let blobUrl;
     button.onclick = function () {
       if (!blobUrl) {
@@ -4730,21 +4729,20 @@ Object.defineProperty(exports, "__esModu
 });
 exports.PDFOutlineViewer = undefined;
 
 var _pdfjsLib = __webpack_require__(1);
 
 const DEFAULT_TITLE = '\u2013';
 class PDFOutlineViewer {
   constructor({ container, linkService, eventBus }) {
-    this.outline = null;
-    this.lastToggleIsShow = true;
     this.container = container;
     this.linkService = linkService;
     this.eventBus = eventBus;
+    this.reset();
   }
   reset() {
     this.outline = null;
     this.lastToggleIsShow = true;
     this.container.textContent = '';
     this.container.classList.remove('outlineWithDeepNesting');
   }
   _dispatchEvent(outlineCount) {
@@ -5892,23 +5890,30 @@ class PDFSidebar {
       this.outlineButton.disabled = !outlineCount;
       if (outlineCount) {
         this._showUINotification(SidebarView.OUTLINE);
       } else if (this.active === SidebarView.OUTLINE) {
         this.switchView(SidebarView.THUMBS);
       }
     });
     this.eventBus.on('attachmentsloaded', evt => {
-      let attachmentsCount = evt.attachmentsCount;
-      this.attachmentsButton.disabled = !attachmentsCount;
-      if (attachmentsCount) {
+      if (evt.attachmentsCount) {
+        this.attachmentsButton.disabled = false;
         this._showUINotification(SidebarView.ATTACHMENTS);
-      } else if (this.active === SidebarView.ATTACHMENTS) {
-        this.switchView(SidebarView.THUMBS);
-      }
+        return;
+      }
+      Promise.resolve().then(() => {
+        if (this.attachmentsView.hasChildNodes()) {
+          return;
+        }
+        this.attachmentsButton.disabled = true;
+        if (this.active === SidebarView.ATTACHMENTS) {
+          this.switchView(SidebarView.THUMBS);
+        }
+      });
     });
     this.eventBus.on('presentationmodechanged', evt => {
       if (!evt.active && !evt.switchInProgress && this.isThumbnailViewVisible) {
         this._updateThumbnailViewer();
       }
     });
   }
 }
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -73,16 +73,28 @@
 #ifdef XP_MACOSX
   @DIR_MACOS@active-update.xml
   @DIR_MACOS@update-settings.ini
   @DIR_MACOS@updates.xml
   @DIR_MACOS@defaults/*
   @DIR_MACOS@updates/*
 #endif
 
+# bug 1391079 - remove this block before 57 uplift to beta
+#ifdef XP_MACOSX
+  @DIR_MACOS@._firefox-bin.sig
+  @DIR_MACOS@._firefox.sig
+  @DIR_MACOS@._XUL.sig
+  @DIR_MACOS@firefox-bin.sig
+  @DIR_MACOS@firefox.sig
+  @DIR_MACOS@plugin-container.app/Contents/MacOS/._plugin-container.sig
+  @DIR_MACOS@plugin-container.app/Contents/MacOS/plugin-container.sig
+  @DIR_MACOS@XUL.sig
+#endif
+
 # Common Directory removals
 @DIR_MACOS@chrome/
 #ifdef XP_UNIX
   #ifndef XP_MACOSX
     chrome/icons/
     chrome/icons/default/
   #endif
 #endif
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -821,17 +821,17 @@ you can use these alternative items. Oth
 <!ENTITY syncSignIn.label             "Sign In To &syncBrand.shortName.label;…">
 <!ENTITY syncSignIn.accesskey         "Y">
 <!ENTITY syncSyncNowItem.label        "Sync Now">
 <!ENTITY syncSyncNowItem.accesskey    "S">
 <!ENTITY syncReAuthItem.label         "Reconnect to &syncBrand.shortName.label;…">
 <!ENTITY syncReAuthItem.accesskey     "R">
 <!ENTITY syncToolbarButton.label      "Sync">
 
-<!ENTITY customizeMode.menuAndToolbars.header2 "Additional Tools and Features">
+<!ENTITY customizeMode.menuAndToolbars.header3 "Drag your favorite items into the toolbar or overflow menu.">
 <!ENTITY customizeMode.menuAndToolbars.empty "Want more tools?">
 <!ENTITY customizeMode.menuAndToolbars.emptyLink "Choose from thousands of add-ons">
 <!ENTITY customizeMode.restoreDefaults "Restore Defaults">
 <!ENTITY customizeMode.done "Done">
 <!ENTITY customizeMode.titlebar "Title Bar">
 <!ENTITY customizeMode.toolbars2 "Toolbars">
 <!ENTITY customizeMode.lwthemes "Themes">
 <!ENTITY customizeMode.lwthemes.myThemes "My Themes">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -581,18 +581,25 @@ browser.menu.showCharacterEncoding=false
 
 # Mozilla data reporting notification (Telemetry, Firefox Health Report, etc)
 dataReportingNotification.message       = %1$S automatically sends some data to %2$S so that we can improve your experience.
 dataReportingNotification.button.label  = Choose What I Share
 dataReportingNotification.button.accessKey  = C
 
 # Process hang reporter
 processHang.label = A web page is slowing down your browser. What would you like to do?
+# LOCALIZATION NOTE (processHang.add-on.label): The first %S is the name of
+# an extension. The second %S is the name of the product (e.g., Firefox)
+processHang.add-on.label = A script in the extension “%S” is causing %S to slow down.
+processHang.add-on.learn-more.text = Learn more
+processHang.add-on.learn-more.url = https://support.mozilla.org/en-US/kb/warning-unresponsive-script?cache=no#w_other-causes
 processHang.button_stop.label = Stop It
 processHang.button_stop.accessKey = S
+processHang.button_stop_sandbox.label = Temporarily Disable Extension on Page
+processHang.button_stop_sandbox.accessKey = A
 processHang.button_wait.label = Wait
 processHang.button_wait.accessKey = W
 processHang.button_debug.label = Debug Script
 processHang.button_debug.accessKey = D
 
 # LOCALIZATION NOTE (fullscreenButton.tooltip): %S is the keyboard shortcut for full screen
 fullscreenButton.tooltip=Display the window in full screen (%S)
 
--- a/browser/modules/ContentCrashHandlers.jsm
+++ b/browser/modules/ContentCrashHandlers.jsm
@@ -145,16 +145,18 @@ this.TabCrashHandler = {
         }
 
         // check for environment affecting crash reporting
         let env = Cc["@mozilla.org/process/environment;1"]
                     .getService(Ci.nsIEnvironment);
         let shutdown = env.exists("MOZ_CRASHREPORTER_SHUTDOWN");
 
         if (shutdown) {
+          dump("A content process crashed and MOZ_CRASHREPORTER_SHUTDOWN is " +
+               "set, shutting down\n");
           Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
         }
 
         break;
       }
       case "oop-frameloader-crashed": {
         aSubject.QueryInterface(Ci.nsIFrameLoader);
 
--- a/browser/modules/ProcessHangMonitor.jsm
+++ b/browser/modules/ProcessHangMonitor.jsm
@@ -60,16 +60,24 @@ var ProcessHangMonitor = {
    * Terminate JavaScript associated with the hang being reported for
    * the selected browser in |win|.
    */
   terminateScript(win) {
     this.handleUserInput(win, report => report.terminateScript());
   },
 
   /**
+   * Terminate Sandbox globals associated with the hang being reported
+   * for the selected browser in |win|.
+   */
+  terminateGlobal(win) {
+    this.handleUserInput(win, report => report.terminateGlobal());
+  },
+
+  /**
    * Start devtools debugger for JavaScript associated with the hang
    * being reported for the selected browser in |win|.
    */
   debugScript(win) {
     this.handleUserInput(win, report => {
       function callback() {
         report.endStartingDebugger();
       }
@@ -107,16 +115,33 @@ var ProcessHangMonitor = {
         break;
       case report.PLUGIN_HANG:
         this.terminatePlugin(win);
         break;
     }
   },
 
   /**
+   * Stop all scripts from running in the Sandbox global attached to
+   * this window.
+   */
+  stopGlobal(win) {
+    let report = this.findActiveReport(win.gBrowser.selectedBrowser);
+    if (!report) {
+      return;
+    }
+
+    switch (report.hangType) {
+      case report.SLOW_SCRIPT:
+        this.terminateGlobal(win);
+        break;
+    }
+  },
+
+  /**
    * Dismiss the notification, clear the report from the active list and set up
    * a new timer to track a wait period during which we won't notify.
    */
   waitLonger(win) {
     let report = this.findActiveReport(win.gBrowser.selectedBrowser);
     if (!report) {
       return;
     }
@@ -299,28 +324,61 @@ var ProcessHangMonitor = {
       {
         label: bundle.getString("processHang.button_wait.label"),
         accessKey: bundle.getString("processHang.button_wait.accessKey"),
         callback() {
           ProcessHangMonitor.waitLonger(win);
         }
       }];
 
+    let message = bundle.getString("processHang.label");
+    if (report.addonId) {
+      let aps = Cc["@mozilla.org/addons/policy-service;1"].getService(Ci.nsIAddonPolicyService);
+
+      let doc = win.document;
+      let brandBundle = doc.getElementById("bundle_brand");
+
+      let addonName = aps.getExtensionName(report.addonId);
+
+      let label = bundle.getFormattedString("processHang.add-on.label",
+                                            [addonName, brandBundle.getString("brandShortName")]);
+
+      let linkText = bundle.getString("processHang.add-on.learn-more.text");
+      let linkURL = bundle.getString("processHang.add-on.learn-more.url");
+
+      let link = doc.createElement("label");
+      link.setAttribute("class", "text-link");
+      link.setAttribute("role", "link");
+      link.setAttribute("onclick", `openUILinkIn(${JSON.stringify(linkURL)}, "tab")`);
+      link.setAttribute("value", linkText);
+
+      message = doc.createDocumentFragment();
+      message.appendChild(doc.createTextNode(label + " "));
+      message.appendChild(link);
+
+      buttons.unshift({
+        label: bundle.getString("processHang.button_stop_sandbox.label"),
+        accessKey: bundle.getString("processHang.button_stop_sandbox.accessKey"),
+        callback() {
+          ProcessHangMonitor.stopGlobal(win);
+        }
+      });
+    }
+
     if (AppConstants.MOZ_DEV_EDITION && report.hangType == report.SLOW_SCRIPT) {
       buttons.push({
         label: bundle.getString("processHang.button_debug.label"),
         accessKey: bundle.getString("processHang.button_debug.accessKey"),
         callback() {
           ProcessHangMonitor.debugScript(win);
         }
       });
     }
 
-    nb.appendNotification(bundle.getString("processHang.label"),
-                          "process-hang",
+    nb.appendNotification(message, "process-hang",
                           "chrome://browser/content/aboutRobots-icon.png",
                           nb.PRIORITY_WARNING_HIGH, buttons);
   },
 
   /**
    * Ensure that no hang notifications are visible in |win|.
    */
   hideNotification(win) {
--- a/browser/themes/shared/icons/arrow-dropdown-16.svg
+++ b/browser/themes/shared/icons/arrow-dropdown-16.svg
@@ -1,6 +1,6 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="context-fill" d="M8,12L3,7,4,6l4,4,4-4,1,1Z"/>
+  <path fill="context-fill" fill-opacity="context-fill-opacity" d="M8,12L3,7,4,6l4,4,4-4,1,1Z"/>
 </svg>
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -109,18 +109,16 @@
   list-style-image: url("chrome://browser/skin/sync.svg");
 }
 
 /* URL bar and page action buttons */
 
 .urlbar-history-dropmarker {
   -moz-appearance: none;
   list-style-image: url(chrome://browser/skin/arrow-dropdown-16.svg);
-  -moz-context-properties: fill;
-  fill: currentColor;
   transition: opacity 0.15s ease;
 }
 
 #urlbar[switchingtabs] > .urlbar-textbox-container > .urlbar-history-dropmarker {
   transition: none;
 }
 
 #navigator-toolbox:not(:hover) > #nav-bar:not([customizing="true"]) > #nav-bar-customization-target > #urlbar-container > #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
--- a/build/gyp.mozbuild
+++ b/build/gyp.mozbuild
@@ -55,17 +55,16 @@ gyp_vars.update({
     'use_glib': 1 if CONFIG['GLIB_LIBS'] else 0,
     # bug 1373485 - avoid pkg-config for gtk2 in webrtc
     'use_gtk': 0,
 
      # turn off mandatory use of NEON and instead use NEON detection
     'arm_neon': 0,
     'arm_neon_optional': 1,
 
-    'moz_widget_toolkit_gonk': 0,
     'moz_webrtc_omx': 0,
     'moz_webrtc_mediacodec': 0,
 
     # Turn off multi monitor screen share
     'multi_monitor_screenshare%' : 0,
 
     # (for vp8) chromium sets to 0 also
     'use_temporal_layers': 0,
--- a/build/moz.configure/compilers-util.configure
+++ b/build/moz.configure/compilers-util.configure
@@ -2,17 +2,19 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 @template
 @imports('textwrap')
 @imports(_from='mozbuild.configure', _import='SandboxDependsFunction')
-def compiler_class(compiler):
+def compiler_class(compiler, host_or_target):
+    is_target = host_or_target is target
+
     class Compiler(SandboxDependsFunction):
         # Generates a test program and attempts to compile it. In case of
         # failure, the resulting check will return None. If the test program
         # succeeds, it will return the output of the test program.
         # - `includes` are the includes (as file names) that will appear at the
         #   top of the generated test program.
         # - `body` is the code that will appear in the main function of the
         #   generated test program. `return 0;` is appended to the function
@@ -42,17 +44,18 @@ def compiler_class(compiler):
             else:
                 def checking_fn(fn):
                     return fn
 
             @depends(self, dependable(flags), extra_toolchain_flags, when=when)
             @checking_fn
             def func(compiler, flags, extra_flags):
                 flags = flags or []
-                flags += extra_flags or []
+                if is_target:
+                    flags += extra_flags or []
                 flags.append('-c')
 
                 if try_invoke_compiler(
                     compiler.wrapper + [compiler.compiler] + compiler.flags,
                     compiler.language, source, flags,
                     onerror=onerror) is not None:
                     return True
 
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -804,17 +804,17 @@ def compiler(language, host_or_target, c
     if language == 'C':
         set_config(
             '%s_TYPE' % var, valid_compiler.type)
         add_old_configure_assignment(
             '%s_TYPE' % var, valid_compiler.type)
         add_old_configure_assignment(
             '%s_VERSION' % var, valid_compiler.version)
 
-    valid_compiler = compiler_class(valid_compiler)
+    valid_compiler = compiler_class(valid_compiler, host_or_target)
 
     def compiler_error():
         raise FatalCheckError('Failed compiling a simple %s source with %s'
                               % (language, what))
 
     valid_compiler.try_compile(check_msg='%s works' % what,
                                onerror=compiler_error)
 
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -35,16 +35,29 @@ public:
     eNullPrincipal,
     eCodebasePrincipal,
     eExpandedPrincipal,
     eSystemPrincipal
   };
 
   explicit BasePrincipal(PrincipalKind aKind);
 
+  template<typename T>
+  bool Is() const
+  {
+    return mKind == T::Kind();
+  }
+
+  template<typename T>
+  T* As()
+  {
+    MOZ_ASSERT(Is<T>());
+    return static_cast<T*>(this);
+  }
+
   enum DocumentDomainConsideration { DontConsiderDocumentDomain, ConsiderDocumentDomain};
   bool Subsumes(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration);
 
   NS_IMETHOD GetOrigin(nsACString& aOrigin) final;
   NS_IMETHOD GetOriginNoSuffix(nsACString& aOrigin) final;
   NS_IMETHOD Equals(nsIPrincipal* other, bool* _retval) final;
   NS_IMETHOD EqualsConsideringDomain(nsIPrincipal* other, bool* _retval) final;
   NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval) final;
--- a/caps/ContentPrincipal.h
+++ b/caps/ContentPrincipal.h
@@ -25,16 +25,18 @@ public:
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
   bool IsCodebasePrincipal() const override { return true; }
 
   ContentPrincipal();
 
+  static PrincipalKind Kind() { return eCodebasePrincipal; }
+
   // Init() must be called before the principal is in a usable state.
   nsresult Init(nsIURI* aCodebase,
                 const mozilla::OriginAttributes& aOriginAttributes,
                 const nsACString& aOriginNoSuffix);
 
   virtual nsresult GetScriptLocation(nsACString& aStr) override;
 
   /**
--- a/caps/ExpandedPrincipal.h
+++ b/caps/ExpandedPrincipal.h
@@ -15,16 +15,18 @@
 class ExpandedPrincipal : public nsIExpandedPrincipal
                         , public mozilla::BasePrincipal
 {
 public:
   static already_AddRefed<ExpandedPrincipal>
   Create(nsTArray<nsCOMPtr<nsIPrincipal>>& aWhiteList,
          const mozilla::OriginAttributes& aAttrs);
 
+  static PrincipalKind Kind() { return eExpandedPrincipal; }
+
   NS_DECL_NSIEXPANDEDPRINCIPAL
   NS_DECL_NSISERIALIZABLE
 
   NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return nsJSPrincipals::AddRef(); };
   NS_IMETHOD_(MozExternalRefCountType) Release() override { return nsJSPrincipals::Release(); };
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
--- a/caps/NullPrincipal.h
+++ b/caps/NullPrincipal.h
@@ -36,16 +36,18 @@ public:
   // This should only be used by deserialization, and the factory constructor.
   // Other consumers should use the Create and CreateWithInheritedAttributes
   // methods.
   NullPrincipal()
     : BasePrincipal(eNullPrincipal)
   {
   }
 
+  static PrincipalKind Kind() { return eNullPrincipal; }
+
   NS_DECL_NSISERIALIZABLE
 
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
--- a/caps/NullPrincipalURI.cpp
+++ b/caps/NullPrincipalURI.cpp
@@ -14,40 +14,38 @@
 #include "nsEscape.h"
 #include "nsCRT.h"
 #include "nsIUUIDGenerator.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 //// NullPrincipalURI
 
 NullPrincipalURI::NullPrincipalURI()
-  : mPath(mPathBytes, ArrayLength(mPathBytes), ArrayLength(mPathBytes) - 1)
 {
 }
 
 NullPrincipalURI::NullPrincipalURI(const NullPrincipalURI& aOther)
-  : mPath(mPathBytes, ArrayLength(mPathBytes), ArrayLength(mPathBytes) - 1)
 {
   mPath.Assign(aOther.mPath);
 }
 
 nsresult
 NullPrincipalURI::Init()
 {
   // FIXME: bug 327161 -- make sure the uuid generator is reseeding-resistant.
   nsCOMPtr<nsIUUIDGenerator> uuidgen = services::GetUUIDGenerator();
   NS_ENSURE_TRUE(uuidgen, NS_ERROR_NOT_AVAILABLE);
 
   nsID id;
   nsresult rv = uuidgen->GenerateUUIDInPlace(&id);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  MOZ_ASSERT(mPathBytes == mPath.BeginWriting());
-
-  id.ToProvidedString(mPathBytes);
+  mPath.SetLength(NSID_LENGTH - 1); // -1 because NSID_LENGTH counts the '\0'
+  id.ToProvidedString(
+    *reinterpret_cast<char(*)[NSID_LENGTH]>(mPath.BeginWriting()));
 
   MOZ_ASSERT(mPath.Length() == NSID_LENGTH - 1);
   MOZ_ASSERT(strlen(mPath.get()) == NSID_LENGTH - 1);
 
   return NS_OK;
 }
 
 /* static */
--- a/caps/NullPrincipalURI.h
+++ b/caps/NullPrincipalURI.h
@@ -47,13 +47,12 @@ public:
 
 private:
   NullPrincipalURI(const NullPrincipalURI& aOther);
 
   ~NullPrincipalURI() {}
 
   nsresult Init();
 
-  char mPathBytes[NSID_LENGTH];
-  nsFixedCString mPath;
+  nsAutoCStringN<NSID_LENGTH> mPath;
 };
 
 #endif // __NullPrincipalURI_h__
--- a/caps/SystemPrincipal.h
+++ b/caps/SystemPrincipal.h
@@ -25,16 +25,18 @@ class SystemPrincipal final : public moz
   SystemPrincipal()
     : BasePrincipal(eSystemPrincipal)
   {
   }
 
 public:
   static already_AddRefed<SystemPrincipal> Create();
 
+  static PrincipalKind Kind() { return eSystemPrincipal; }
+
   NS_DECL_NSISERIALIZABLE
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
   NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
--- a/caps/nsIAddonPolicyService.idl
+++ b/caps/nsIAddonPolicyService.idl
@@ -48,16 +48,22 @@ interface nsIAddonPolicyService : nsISup
   /**
    * Returns true if unprivileged code associated with the given addon may load
    * data from |aURI|.  If |aExplicit| is true, the <all_urls> permission and
    * permissive host globs are ignored when checking for a match.
    */
   boolean addonMayLoadURI(in AString aAddonId, in nsIURI aURI, [optional] in boolean aExplicit);
 
   /**
+   * Returns the name of the WebExtension with the given ID, or the ID string
+   * if no matching add-on can be found.
+   */
+  AString getExtensionName(in AString aAddonId);
+
+  /**
    * Returns true if a given extension:// URI is web-accessible.
    */
   boolean extensionURILoadableByAnyone(in nsIURI aURI);
 
   /**
    * Maps an extension URI to the ID of the addon it belongs to.
    */
   AString extensionURIToAddonId(in nsIURI aURI);
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -561,16 +561,20 @@ distclean::
 	$(wildcard *.$(OBJ_SUFFIX)) $(wildcard *.ho) $(wildcard host_*.o*) \
 	$(wildcard *.$(LIB_SUFFIX)) $(wildcard *$(DLL_SUFFIX)) \
 	$(wildcard *.$(IMPORT_LIB_SUFFIX))
 
 alltags:
 	$(RM) TAGS
 	find $(topsrcdir) -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' -o -name '*.idl' \) -print | $(TAG_PROGRAM)
 
+define EXPAND_CC_OR_CXX
+$(if $(PROG_IS_C_ONLY_$(1)),$(EXPAND_CC),$(EXPAND_CCC))
+endef
+
 #
 # PROGRAM = Foo
 # creates OBJS, links with LIBS to create Foo
 #
 $(PROGRAM): $(PROGOBJS) $(STATIC_LIBS_DEPS) $(EXTRA_DEPS) $(EXE_DEF_FILE) $(RESFILE) $(GLOBAL_DEPS)
 	$(REPORT_BUILD)
 	@$(RM) $@.manifest
 ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
@@ -590,17 +594,17 @@ ifdef MSMANIFEST_TOOL
 	fi
 endif	# MSVC with manifest tool
 ifdef MOZ_PROFILE_GENERATE
 # touch it a few seconds into the future to work around FAT's
 # 2-second granularity
 	touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink
 endif
 else # !WINNT || GNU_CC
-	$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE)
+	$(call EXPAND_CC_OR_CXX,$@) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE)
 	$(call CHECK_BINARY,$@)
 endif # WINNT && !GNU_CC
 
 ifdef ENABLE_STRIP
 	$(STRIP) $(STRIP_FLAGS) $@
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
@@ -649,17 +653,17 @@ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
 	$(EXPAND_LINK) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
 ifdef MSMANIFEST_TOOL
 	@if test -f $@.manifest; then \
 		$(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
 		rm -f $@.manifest; \
 	fi
 endif	# MSVC with manifest tool
 else
-	$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS)
+	$(call EXPAND_CC_OR_CXX,$@) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS)
 	$(call CHECK_BINARY,$@)
 endif # WINNT && !GNU_CC
 
 ifdef ENABLE_STRIP
 	$(STRIP) $(STRIP_FLAGS) $@
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
--- a/config/system-headers
+++ b/config/system-headers
@@ -387,19 +387,16 @@ descrip.h
 Devices.h
 Dialogs.h
 direct.h
 dirent.h
 DiskInit.h
 dlfcn.h
 dlgs.h
 dl.h
-#ifdef MOZ_WIDGET_GONK
-dns_sd.h
-#endif
 docobj.h
 dos/dosextens.h
 dos.h
 Drag.h
 DriverServices.h
 DriverSynchronization.h
 DropInPanel.h
 dvidef.h
--- a/devtools/client/inspector/fonts/components/App.js
+++ b/devtools/client/inspector/fonts/components/App.js
@@ -55,14 +55,22 @@ const App = createClass({
             id: "font-showall",
             className: "theme-link",
             title: getStr("fontinspector.seeAll.tooltip"),
             onClick: onShowAllFont,
           },
           getStr("fontinspector.seeAll")
         )
       ),
-      FontList({ fonts })
+      fonts.length ?
+        FontList({ fonts })
+        :
+        dom.div(
+          {
+            className: "devtools-sidepanel-no-result"
+          },
+          getStr("fontinspector.noFontsOnSelectedElement")
+        )
     );
   }
 });
 
 module.exports = connect(state => state)(App);
--- a/devtools/client/inspector/fonts/fonts.js
+++ b/devtools/client/inspector/fonts/fonts.js
@@ -131,34 +131,37 @@ FontInspector.prototype = {
    */
   onShowAllFont() {
     this.store.dispatch(updateShowAllFonts(true));
     this.update();
   },
 
   update: Task.async(function* () {
     let node = this.inspector.selection.nodeFront;
+    let fonts = [];
+    let { fontOptions } = this.store.getState();
+    let { showAllFonts, previewText } = fontOptions;
 
-    if (!node ||
-        !this.isPanelVisible() ||
-        !this.inspector.selection.isConnected() ||
-        !this.inspector.selection.isElementNode()) {
+    // Clear the list of fonts if the currently selected node is not connected or an
+    // element node unless all fonts are supposed to be shown.
+    if (!showAllFonts &&
+        (!node ||
+         !this.isPanelVisible() ||
+         !this.inspector.selection.isConnected() ||
+         !this.inspector.selection.isElementNode())) {
+      this.store.dispatch(updateFonts(fonts));
       return;
     }
 
-    let { fontOptions } = this.store.getState();
-    let { showAllFonts, previewText } = fontOptions;
-
     let options = {
       includePreviews: true,
       previewText,
       previewFillStyle: getColor("body-color")
     };
 
-    let fonts = [];
     if (showAllFonts) {
       fonts = yield this.pageStyle.getAllUsedFontFaces(options)
                       .catch(console.error);
     } else {
       fonts = yield this.pageStyle.getUsedFontFaces(node, options)
                       .catch(console.error);
     }
 
--- a/devtools/client/locales/en-US/font-inspector.properties
+++ b/devtools/client/locales/en-US/font-inspector.properties
@@ -19,11 +19,15 @@ fontinspector.usedAs=Used as:
 # LOCALIZATION NOTE (fontinspector.system) This label indicates that the font is a local
 # system font.
 fontinspector.system=system
 
 # LOCALIZATION NOTE (fontinspector.remote) This label indicates that the font is a remote
 # font.
 fontinspector.remote=remote
 
-# LOCALIZATION NOTE (previewHint):
+# LOCALIZATION NOTE (fontinspector.previewHint):
 # This is the label shown as the placeholder in font inspector preview text box.
 fontinspector.previewText=Preview Text
+
+# LOCALIZATION NOTE (fontinspector.noFontsOnSelectedElement): This label is shown when
+# no fonts found on the selected element.
+fontinspector.noFontsOnSelectedElement=No fonts were found for the current element.
--- a/devtools/client/netmonitor/src/utils/filter-autocomplete-provider.js
+++ b/devtools/client/netmonitor/src/utils/filter-autocomplete-provider.js
@@ -34,17 +34,17 @@ function getAutocompleteValuesForFlag(fl
       break;
     case "remote-ip":
       values.push(request.remoteAddress);
       break;
     case "cause":
       values.push(request.cause.type);
       break;
     case "mime-type":
-      values.push(request.mimeType);
+      values.push(request.mimeType.replace(/;.+/, ""));
       break;
     case "set-cookie-name":
       values = responseCookies.map(c => c.name);
       break;
     case "set-cookie-value":
       values = responseCookies.map(c => c.value);
       break;
     case "set-cookie-domain":
--- a/devtools/client/netmonitor/test/browser_net_filter-autocomplete.js
+++ b/devtools/client/netmonitor/test/browser_net_filter-autocomplete.js
@@ -103,18 +103,22 @@ add_task(async function () {
   testAutocompleteContents(["status-code:200", "status-code:304"], document);
 
   // Typing the exact value closes autocomplete
   EventUtils.synthesizeKey("304", {});
   ok(!document.querySelector(".devtools-autocomplete-popup"),
     "Typing the exact value closes autocomplete");
 
   // Check if mime-type has been correctly parsed out and values also get autocomplete
-  EventUtils.synthesizeKey(" mime-type:au", {});
-  testAutocompleteContents(["mime-type:audio/ogg"], document);
+  EventUtils.synthesizeKey(" mime-type:text", {});
+  testAutocompleteContents([
+    "mime-type:text/css",
+    "mime-type:text/html",
+    "mime-type:text/plain"
+  ], document);
 
   // The negative filter flags
   EventUtils.synthesizeKey(" -", {});
   testAutocompleteContents([
     "-cause:",
     "-domain:",
     "-has-response-header:",
     "-is:",
--- a/devtools/shared/discovery/discovery.js
+++ b/devtools/shared/discovery/discovery.js
@@ -155,28 +155,17 @@ LocalDevice.prototype = {
     this._generate();
   },
 
   /**
    * Generate a new device name from various platform-specific properties.
    * Triggers the |name| setter to persist if needed.
    */
   _generate: function () {
-    if (Services.appinfo.widgetToolkit == "gonk") {
-      // For Firefox OS devices, create one from the device name plus a little
-      // randomness.  The goal is just to distinguish devices in an office
-      // environment where many people may have the same device model for
-      // testing purposes (which would otherwise all report the same name).
-      let name = libcutils.property_get("ro.product.device");
-      // Pick a random number from [0, 2^32)
-      let randomID = Math.floor(Math.random() * Math.pow(2, 32));
-      // To hex and zero pad
-      randomID = ("00000000" + randomID.toString(16)).slice(-8);
-      this.name = name + "-" + randomID;
-    } else if (Services.appinfo.widgetToolkit == "android") {
+    if (Services.appinfo.widgetToolkit == "android") {
       // For Firefox for Android, use the device's model name.
       // TODO: Bug 1180997: Find the right way to expose an editable name
       this.name = sysInfo.get("device");
     } else {
       this.name = Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService)
                                                           .myHostName;
     }
   },
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -120,16 +120,17 @@
 #include "nsIScrollableFrame.h"
 #include "nsView.h"
 #include "nsViewManager.h"
 #include "nsISelectionController.h"
 #include "nsISelection.h"
 #include "nsIPrompt.h"
 #include "nsIPromptService.h"
 #include "nsIPromptFactory.h"
+#include "nsIAddonPolicyService.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIWebBrowserFind.h"  // For window.find()
 #include "nsIWindowMediator.h"  // For window.find()
 #include "nsComputedDOMStyle.h"
 #include "nsDOMCID.h"
 #include "nsDOMWindowUtils.h"
@@ -11677,17 +11678,17 @@ nsGlobalWindow::HandleIdleActiveEvent()
       NotifyIdleObserver(&idleObserver, false);
     }
   }
 
   return NS_OK;
 }
 
 nsGlobalWindow::SlowScriptResponse
-nsGlobalWindow::ShowSlowScriptDialog()
+nsGlobalWindow::ShowSlowScriptDialog(const nsString& aAddonId)
 {
   MOZ_ASSERT(IsInnerWindow());
 
   nsresult rv;
   AutoJSContext cx;
 
   if (Preferences::GetBool("dom.always_stop_slow_scripts")) {
     return KillSlowScript;
@@ -11727,20 +11728,24 @@ nsGlobalWindow::ShowSlowScriptDialog()
 
   if (XRE_IsContentProcess() &&
       ProcessHangMonitor::Get()) {
     ProcessHangMonitor::SlowScriptAction action;
     RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
     nsIDocShell* docShell = GetDocShell();
     nsCOMPtr<nsITabChild> child = docShell ? docShell->GetTabChild() : nullptr;
     action = monitor->NotifySlowScript(child,
-                                       filename.get());
+                                       filename.get(),
+                                       aAddonId);
     if (action == ProcessHangMonitor::Terminate) {
       return KillSlowScript;
     }
+    if (action == ProcessHangMonitor::TerminateGlobal) {
+      return KillScriptGlobal;
+    }
 
     if (action == ProcessHangMonitor::StartDebugger) {
       // Spin a nested event loop so that the debugger in the parent can fetch
       // any information it needs. Once the debugger has started, return to the
       // script.
       RefPtr<nsGlobalWindow> outer = GetOuterWindowInternal();
       outer->EnterModalState();
       SpinEventLoopUntil([&]() { return monitor->IsDebuggerStartupComplete(); });
@@ -11767,71 +11772,68 @@ nsGlobalWindow::ShowSlowScriptDialog()
   if (hasFrame) {
     const char *debugCID = "@mozilla.org/dom/slow-script-debug;1";
     nsCOMPtr<nsISlowScriptDebug> debugService = do_GetService(debugCID, &rv);
     if (NS_SUCCEEDED(rv)) {
       debugService->GetActivationHandler(getter_AddRefs(debugCallback));
     }
   }
 
-  bool showDebugButton = !!debugCallback;
+  bool failed = false;
+  auto getString = [&] (const char* name,
+                        nsContentUtils::PropertiesFile propFile = nsContentUtils::eDOM_PROPERTIES) {
+    nsAutoString result;
+    nsresult rv = nsContentUtils::GetLocalizedString(
+      propFile, name, result);
+
+    // GetStringFromName can return NS_OK and still give nullptr string
+    failed = failed || NS_FAILED(rv) || result.IsEmpty();
+    return Move(result);
+  };
+
+  bool isAddonScript = !aAddonId.IsEmpty();
+  bool showDebugButton = debugCallback && !isAddonScript;
 
   // Get localizable strings
-  nsAutoString title, msg, stopButton, waitButton, debugButton, neverShowDlg;
-
-  rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                          "KillScriptTitle",
-                                          title);
-
-  nsresult tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                           "StopScriptButton",
-                                           stopButton);
-  if (NS_FAILED(tmp)) {
-    rv = tmp;
-  }
-
-  tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                           "WaitForScriptButton",
-                                           waitButton);
-  if (NS_FAILED(tmp)) {
-    rv = tmp;
-  }
-
-  tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                           "DontAskAgain",
-                                           neverShowDlg);
-  if (NS_FAILED(tmp)) {
-    rv = tmp;
-  }
-
-  if (showDebugButton) {
-    tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                             "DebugScriptButton",
-                                             debugButton);
-    if (NS_FAILED(tmp)) {
-      rv = tmp;
-    }
-
-    tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                             "KillScriptWithDebugMessage",
-                                             msg);
-    if (NS_FAILED(tmp)) {
-      rv = tmp;
-    }
-  }
-  else {
-    tmp = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                             "KillScriptMessage",
-                                             msg);
-    if (NS_FAILED(tmp)) {
-      rv = tmp;
-    }
-  }
-
-  if (NS_FAILED(rv)) {
+
+  nsAutoString title, checkboxMsg, debugButton, msg;
+  if (isAddonScript) {
+    title = getString("KillAddonScriptTitle");
+    checkboxMsg = getString("KillAddonScriptGlobalMessage");
+
+    auto appName = getString("brandShortName", nsContentUtils::eBRAND_PROPERTIES);
+
+    nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1");
+    nsString addonName;
+    if (!aps || NS_FAILED(aps->GetExtensionName(aAddonId, addonName))) {
+      addonName = aAddonId;
+    }
+
+    const char16_t* params[] = {addonName.get(), appName.get()};
+    rv = nsContentUtils::FormatLocalizedString(
+        nsContentUtils::eDOM_PROPERTIES, "KillAddonScriptMessage",
+        params, msg);
+
+    failed = failed || NS_FAILED(rv);
+  } else {
+    title = getString("KillScriptTitle");
+    checkboxMsg = getString("DontAskAgain");
+
+    if (showDebugButton) {
+      debugButton = getString("DebugScriptButton");
+      msg = getString("KillScriptWithDebugMessage");
+    } else {
+      msg = getString("KillScriptMessage");
+    }
+  }
+
+  auto stopButton = getString("StopScriptButton");
+  auto waitButton = getString("WaitForScriptButton");
+
+  if (failed) {
     NS_ERROR("Failed to get localized strings.");
     return ContinueSlowScript;
   }
 
   // Append file and line number information, if available
   if (filename.get()) {
     nsAutoString scriptLocation;
     // We want to drop the middle part of too-long locations.  We'll
@@ -11869,46 +11871,54 @@ nsGlobalWindow::ShowSlowScriptDialog()
     if (NS_SUCCEEDED(rv)) {
       msg.AppendLiteral("\n\n");
       msg.Append(scriptLocation);
       msg.Append(':');
       msg.AppendInt(lineno);
     }
   }
 
-  int32_t buttonPressed = 0; // In case the user exits dialog by clicking X.
-  bool neverShowDlgChk = false;
   uint32_t buttonFlags = nsIPrompt::BUTTON_POS_1_DEFAULT +
                          (nsIPrompt::BUTTON_TITLE_IS_STRING *
                           (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1));
 
   // Add a third button if necessary.
   if (showDebugButton)
     buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
 
+  bool checkboxValue = false;
+  int32_t buttonPressed = 0; // In case the user exits dialog by clicking X.
   {
     // Null out the operation callback while we're re-entering JS here.
     AutoDisableJSInterruptCallback disabler(cx);
+
     // Open the dialog.
     rv = prompt->ConfirmEx(title.get(), msg.get(), buttonFlags,
                            waitButton.get(), stopButton.get(),
-                           debugButton.get(), neverShowDlg.get(),
-                           &neverShowDlgChk, &buttonPressed);
-  }
-
-  if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) {
-    return neverShowDlgChk ? AlwaysContinueSlowScript : ContinueSlowScript;
-  }
+                           debugButton.get(), checkboxMsg.get(),
+                           &checkboxValue, &buttonPressed);
+  }
+
+  if (buttonPressed == 0) {
+    if (checkboxValue && !isAddonScript && NS_SUCCEEDED(rv))
+      return AlwaysContinueSlowScript;
+    return ContinueSlowScript;
+  }
+
   if (buttonPressed == 2) {
-    if (debugCallback) {
-      rv = debugCallback->HandleSlowScriptDebug(this);
-      return NS_SUCCEEDED(rv) ? ContinueSlowScript : KillSlowScript;
-    }
-  }
+    MOZ_RELEASE_ASSERT(debugCallback);
+
+    rv = debugCallback->HandleSlowScriptDebug(this);
+    return NS_SUCCEEDED(rv) ? ContinueSlowScript : KillSlowScript;
+  }
+
   JS_ClearPendingException(cx);
+
+  if (checkboxValue && isAddonScript)
+    return KillScriptGlobal;
   return KillSlowScript;
 }
 
 uint32_t
 nsGlobalWindow::FindInsertionIndex(IdleObserverHolder* aIdleObserver)
 {
   MOZ_ASSERT(IsInnerWindow());
   MOZ_ASSERT(aIdleObserver, "Idle observer not instantiated.");
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -732,19 +732,20 @@ public:
   {
     mAllowScriptsToClose = true;
   }
 
   enum SlowScriptResponse {
     ContinueSlowScript = 0,
     ContinueSlowScriptAndKeepNotifying,
     AlwaysContinueSlowScript,
-    KillSlowScript
+    KillSlowScript,
+    KillScriptGlobal
   };
-  SlowScriptResponse ShowSlowScriptDialog();
+  SlowScriptResponse ShowSlowScriptDialog(const nsString& aAddonId);
 
   // Inner windows only.
   void AddGamepad(uint32_t aIndex, mozilla::dom::Gamepad* aGamepad);
   void RemoveGamepad(uint32_t aIndex);
   void GetGamepads(nsTArray<RefPtr<mozilla::dom::Gamepad> >& aGamepads);
   already_AddRefed<mozilla::dom::Gamepad> GetGamepad(uint32_t aIndex);
   void SetHasSeenGamepadInput(bool aHasSeen);
   bool HasSeenGamepadInput();
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2677,16 +2677,22 @@ nsJSContext::EnsureStatics()
 
   Preferences::RegisterCallbackAndCall(SetMemoryPrefChangedCallbackInt,
                                        "javascript.options.mem.gc_high_frequency_high_limit_mb",
                                        (void *)JSGC_HIGH_FREQUENCY_HIGH_LIMIT);
 
   Preferences::RegisterCallbackAndCall(SetMemoryPrefChangedCallbackInt,
                                        "javascript.options.mem.gc_allocation_threshold_mb",
                                        (void *)JSGC_ALLOCATION_THRESHOLD);
+  Preferences::RegisterCallbackAndCall(SetMemoryPrefChangedCallbackInt,
+                                       "javascript.options.mem.gc_allocation_threshold_factor",
+                                       (void *)JSGC_ALLOCATION_THRESHOLD_FACTOR);
+  Preferences::RegisterCallbackAndCall(SetMemoryPrefChangedCallbackInt,
+                                       "javascript.options.mem.gc_allocation_threshold_factor_avoid_interrupt",
+                                       (void *)JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT);
 
   Preferences::RegisterCallbackAndCall(SetIncrementalCCPrefChangedCallback,
                                        "dom.cycle_collector.incremental");
 
   Preferences::RegisterCallbackAndCall(SetMemoryPrefChangedCallbackInt,
                                        "javascript.options.mem.gc_min_empty_chunk_count",
                                        (void *)JSGC_MIN_EMPTY_CHUNK_COUNT);
 
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -6284,17 +6284,17 @@ CanvasRenderingContext2D::GetCanvasLayer
   uint32_t flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
   canvasLayer->SetContentFlags(flags);
 
   mResetLayer = false;
 
   return canvasLayer.forget();
 }
 
-void
+bool
 CanvasRenderingContext2D::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                                    CanvasRenderer* aRenderer,
                                                    bool aMirror)
 {
   CanvasInitializeData data;
   data.mSize = GetSize();
   data.mHasAlpha = !mOpaque;
   data.mPreTransCallback = CanvasRenderingContext2DUserData::PreTransactionCallback;
@@ -6311,16 +6311,17 @@ CanvasRenderingContext2D::InitializeCanv
         data.mFrontbufferGLTex = skiaGLTex;
       }
   }
 
   data.mBufferProvider = mBufferProvider;
 
   aRenderer->Initialize(data);
   aRenderer->SetDirty();
+  return true;
 }
 
 void
 CanvasRenderingContext2D::MarkContextClean()
 {
   if (mInvalidateCount > 0) {
     mPredictManyRedrawCalls = mInvalidateCount > kCanvasMaxInvalidateCount;
   }
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -463,17 +463,17 @@ public:
 
   virtual void SetIsOpaque(bool aIsOpaque) override;
   bool GetIsOpaque() override { return mOpaque; }
   NS_IMETHOD Reset() override;
   already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                          Layer* aOldLayer,
                                          LayerManager* aManager,
                                          bool aMirror = false) override;
-  void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+  bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                 CanvasRenderer* aRenderer,
                                 bool aMirror = false) override;
   virtual bool ShouldForceInactiveLayer(LayerManager* aManager) override;
   void MarkContextClean() override;
   void MarkContextCleanForFrameCapture() override;
   bool IsContextCleanForFrameCapture() override;
   NS_IMETHOD SetIsIPC(bool aIsIPC) override;
   // this rect is in canvas device space
--- a/dom/canvas/ImageUtils.cpp
+++ b/dom/canvas/ImageUtils.cpp
@@ -231,17 +231,16 @@ private:
     if (mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
       return mImage->AsPlanarYCbCrImage()->GetData();
     }
     return mImage->AsNVImage()->GetData();
   }
 };
 
 // TODO: optimize for other platforms.
-// For GONK: implement GrallocImageImpl, GrallocPlanarYCbCrImpl and GonkCameraImpl.
 // For Windows: implement D3D9RGB32TextureImpl and D3D11ShareHandleTextureImpl.
 // Others: SharedBGRImpl, MACIOSrufaceImpl, GLImageImpl, SurfaceTextureImpl
 //         EGLImageImpl and OverlayImegImpl.
 
 ImageUtils::ImageUtils(layers::Image* aImage)
 : mImpl(nullptr)
 {
   MOZ_ASSERT(aImage, "Create ImageUtils with nullptr.");
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1317,19 +1317,16 @@ private:
 };
 
 already_AddRefed<layers::Layer>
 WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
                              Layer* oldLayer,
                              LayerManager* manager,
                              bool aMirror /*= false*/)
 {
-    if (IsContextLost())
-        return nullptr;
-
     if (!mResetLayer && oldLayer &&
         oldLayer->HasUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData)) {
         RefPtr<layers::Layer> ret = oldLayer;
         return ret.forget();
     }
 
     RefPtr<CanvasLayer> canvasLayer = manager->CreateCanvasLayer();
     if (!canvasLayer) {
@@ -1340,34 +1337,39 @@ WebGLContext::GetCanvasLayer(nsDisplayLi
     WebGLContextUserData* userData = nullptr;
     if (builder->IsPaintingToWindow() && mCanvasElement && !aMirror) {
         userData = new WebGLContextUserData(mCanvasElement);
     }
 
     canvasLayer->SetUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData, userData);
 
     CanvasRenderer* canvasRenderer = canvasLayer->CreateOrGetCanvasRenderer();
-    InitializeCanvasRenderer(builder, canvasRenderer, aMirror);
+    if (!InitializeCanvasRenderer(builder, canvasRenderer, aMirror))
+      return nullptr;
+
     uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE;
     canvasLayer->SetContentFlags(flags);
 
     mResetLayer = false;
     // We only wish to update mLayerIsMirror when a new layer is returned.
     // If a cached layer is returned above, aMirror is not changing since
     // the last cached layer was created and mLayerIsMirror is still valid.
     mLayerIsMirror = aMirror;
 
     return canvasLayer.forget();
 }
 
-void
+bool
 WebGLContext::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                        CanvasRenderer* aRenderer,
                                        bool aMirror)
 {
+    if (IsContextLost())
+        return false;
+
     CanvasInitializeData data;
     if (aBuilder->IsPaintingToWindow() && mCanvasElement && !aMirror) {
         // Make the layer tell us whenever a transaction finishes (including
         // the current transaction), so we can clear our invalidation state and
         // start invalidating again. We need to do this for the layer that is
         // being painted to a window (there shouldn't be more than one at a time,
         // and if there is, flushing the invalidation state more often than
         // necessary is harmless).
@@ -1386,16 +1388,17 @@ WebGLContext::InitializeCanvasRenderer(n
     data.mGLContext = gl;
     data.mSize = nsIntSize(mWidth, mHeight);
     data.mHasAlpha = gl->Caps().alpha;
     data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha;
     data.mIsMirror = aMirror;
 
     aRenderer->Initialize(data);
     aRenderer->SetDirty();
+    return true;
 }
 
 layers::LayersBackend
 WebGLContext::GetCompositorBackendType() const
 {
     if (mCanvasElement) {
         return mCanvasElement->GetCompositorBackendType();
     } else if (mOffscreenCanvas) {
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -457,17 +457,17 @@ public:
     }
 
     void InvalidateResolveCacheForTextureWithTexUnit(const GLuint);
 
     already_AddRefed<Layer>
     GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer,
                    LayerManager* manager,
                    bool aMirror = false) override;
-    void
+    bool
     InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                              CanvasRenderer* aRenderer,
                              bool aMirror = false) override;
 
     // Note that 'clean' here refers to its invalidation state, not the
     // contents of the buffer.
     void MarkContextClean() override { mInvalidated = false; }
 
--- a/dom/canvas/nsICanvasRenderingContextInternal.h
+++ b/dom/canvas/nsICanvasRenderingContextInternal.h
@@ -136,19 +136,19 @@ public:
   NS_IMETHOD Reset() = 0;
 
   // Return the CanvasLayer for this context, creating
   // one for the given layer manager if not available.
   virtual already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* builder,
                                                  Layer *oldLayer,
                                                  LayerManager *manager,
                                                  bool aMirror = false) = 0;
-  virtual void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+  virtual bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                         CanvasRenderer* aRenderer,
-                                        bool aMirror = false) { };
+                                        bool aMirror = false) { return true; }
 
   // Return true if the canvas should be forced to be "inactive" to ensure
   // it can be drawn to the screen even if it's too large to be blitted by
   // an accelerated CanvasLayer.
   virtual bool ShouldForceInactiveLayer(LayerManager *manager) { return false; }
 
   virtual void MarkContextClean() = 0;
 
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -1183,39 +1183,45 @@ HTMLCanvasElement::GetCanvasLayer(nsDisp
       NS_WARNING("CreateCanvasLayer failed!");
       return nullptr;
     }
 
     LayerUserData* userData = nullptr;
     layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData);
 
     CanvasRenderer* canvasRenderer = layer->CreateOrGetCanvasRenderer();
-    InitializeCanvasRenderer(aBuilder, canvasRenderer);
+
+    if (!InitializeCanvasRenderer(aBuilder, canvasRenderer)) {
+      return nullptr;
+    }
 
     layer->Updated();
     return layer.forget();
   }
 
   return nullptr;
 }
 
-void
+bool
 HTMLCanvasElement::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                             CanvasRenderer* aRenderer)
 {
   if (mCurrentContext) {
-    mCurrentContext->InitializeCanvasRenderer(aBuilder, aRenderer);
+    return mCurrentContext->InitializeCanvasRenderer(aBuilder, aRenderer);
   }
 
   if (mOffscreenCanvas) {
     CanvasInitializeData data;
     data.mRenderer = GetAsyncCanvasRenderer();
     data.mSize = GetWidthHeight();
     aRenderer->Initialize(data);
+    return true;
   }
+
+  return true;
 }
 
 bool
 HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager* aManager)
 {
   if (mCurrentContext) {
     return mCurrentContext->ShouldForceInactiveLayer(aManager);
   }
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -305,17 +305,17 @@ public:
 
   /*
    * Helpers called by various users of Canvas
    */
 
   already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                          Layer *aOldLayer,
                                          LayerManager *aManager);
-  void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+  bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                 CanvasRenderer* aRenderer);
   // Should return true if the canvas layer should always be marked inactive.
   // We should return true here if we can't do accelerated compositing with
   // a non-BasicCanvasLayer.
   bool ShouldForceInactiveLayer(LayerManager *aManager);
 
   // Call this whenever we need future changes to the canvas
   // to trigger fresh invalidation requests. This needs to be called
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -1144,16 +1144,17 @@ HTMLInputElement::HTMLInputElement(alrea
   , mCanShowInvalidUI(true)
   , mHasRange(false)
   , mIsDraggingRange(false)
   , mNumberControlSpinnerIsSpinning(false)
   , mNumberControlSpinnerSpinsUp(false)
   , mPickerRunning(false)
   , mSelectionCached(true)
   , mIsPreviewEnabled(false)
+  , mHasPatternAttribute(false)
 {
   // If size is above 512, mozjemalloc allocates 1kB, see
   // memory/mozjemalloc/jemalloc.c
   static_assert(sizeof(HTMLInputElement) <= 512,
                 "Keep the size of HTMLInputElement under 512 to avoid "
                 "performance regression!");
 
   // We are in a type=text so we now we currenty need a nsTextEditorState.
@@ -1452,18 +1453,25 @@ HTMLInputElement::AfterSetAttr(int32_t a
       // This *has* to be called *after* validity has changed.
       if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
         UpdateBarredFromConstraintValidation();
       }
     } else if (aName == nsGkAtoms::maxlength) {
       UpdateTooLongValidityState();
     } else if (aName == nsGkAtoms::minlength) {
       UpdateTooShortValidityState();
-    } else if (aName == nsGkAtoms::pattern && mDoneCreating) {
-      UpdatePatternMismatchValidityState();
+    } else if (aName == nsGkAtoms::pattern) {
+      // Although pattern attribute only applies to single line text controls,
+      // we set this flag for all input types to save having to check the type
+      // here.
+      mHasPatternAttribute = !!aValue;
+
+      if (mDoneCreating) {
+        UpdatePatternMismatchValidityState();
+      }
     } else if (aName == nsGkAtoms::multiple) {
       UpdateTypeMismatchValidityState();
     } else if (aName == nsGkAtoms::max) {
       UpdateHasRange();
       nsresult rv = mInputType->MinMaxStepAttrChanged();
       NS_ENSURE_SUCCESS(rv, rv);
       // Validity state must be updated *after* the UpdateValueDueToAttrChange
       // call above or else the following assert will not be valid.
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -334,16 +334,21 @@ public:
     mSelectionCached = false;
   }
   nsTextEditorState::SelectionProperties& GetSelectionProperties()
   {
     MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER);
     return mSelectionProperties;
   }
 
+  bool HasPatternAttribute() const
+  {
+    return mHasPatternAttribute;
+  }
+
   // nsIConstraintValidation
   bool     IsTooLong();
   bool     IsTooShort();
   bool     IsValueMissing() const;
   bool     HasTypeMismatch() const;
   bool     HasPatternMismatch() const;
   bool     IsRangeOverflow() const;
   bool     IsRangeUnderflow() const;
@@ -1662,16 +1667,17 @@ protected:
   bool                     mCanShowInvalidUI    : 1;
   bool                     mHasRange            : 1;
   bool                     mIsDraggingRange     : 1;
   bool                     mNumberControlSpinnerIsSpinning : 1;
   bool                     mNumberControlSpinnerSpinsUp : 1;
   bool                     mPickerRunning : 1;
   bool                     mSelectionCached : 1;
   bool                     mIsPreviewEnabled : 1;
+  bool                     mHasPatternAttribute : 1;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
                                     GenericSpecifiedValues* aGenericData);
 
   /**
    * Returns true if this input's type will fire a DOM "change" event when it
    * loses focus if its value has changed since it gained focus.
--- a/dom/html/input/SingleLineTextInputTypes.cpp
+++ b/dom/html/input/SingleLineTextInputTypes.cpp
@@ -67,18 +67,22 @@ SingleLineTextInputTypeBase::IsValueMiss
   }
 
   return IsValueEmpty();
 }
 
 bool
 SingleLineTextInputTypeBase::HasPatternMismatch() const
 {
+  if (!mInputElement->HasPatternAttribute()) {
+    return false;
+  }
+
   nsAutoString pattern;
- if (!mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::pattern, pattern)) {
+  if (!mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::pattern, pattern)) {
     return false;
   }
 
   nsAutoString value;
   GetNonFileValueInternal(value);
 
   if (value.IsEmpty()) {
     return false;
--- a/dom/indexedDB/ProfilerHelpers.h
+++ b/dom/indexedDB/ProfilerHelpers.h
@@ -32,17 +32,17 @@
 // Include this last to avoid path problems on Windows.
 #include "ActorsChild.h"
 
 namespace mozilla {
 namespace dom {
 namespace indexedDB {
 
 class MOZ_STACK_CLASS LoggingIdString final
-  : public nsAutoCString
+  : public nsAutoCStringN<NSID_LENGTH>
 {
 public:
   LoggingIdString()
   {
     using mozilla::ipc::BackgroundChildImpl;
 
     if (IndexedDatabaseManager::GetLoggingMode() !=
           IndexedDatabaseManager::Logging_Disabled) {
@@ -56,19 +56,20 @@ public:
       }
     }
   }
 
   explicit
   LoggingIdString(const nsID& aID)
   {
     static_assert(NSID_LENGTH > 1, "NSID_LENGTH is set incorrectly!");
-    static_assert(NSID_LENGTH <= kDefaultStorageSize,
-                  "nID string won't fit in our storage!");
-    MOZ_ASSERT(Capacity() > NSID_LENGTH);
+    static_assert(NSID_LENGTH <= kStorageSize,
+                  "nsID string won't fit in our storage!");
+    // Capacity() excludes the null terminator; NSID_LENGTH includes it.
+    MOZ_ASSERT(Capacity() + 1 == NSID_LENGTH);
 
     if (IndexedDatabaseManager::GetLoggingMode() !=
           IndexedDatabaseManager::Logging_Disabled) {
       // NSID_LENGTH counts the null terminator, SetLength() does not.
       SetLength(NSID_LENGTH - 1);
 
       aID.ToProvidedString(
         *reinterpret_cast<char(*)[NSID_LENGTH]>(BeginWriting()));
--- a/dom/indexedDB/test/file.js
+++ b/dom/indexedDB/test/file.js
@@ -204,18 +204,18 @@ function verifyView(view1, view2)
   continueToNextStep();
 }
 
 function verifyWasmModule(module1, module2)
 {
   let getGlobalForObject = SpecialPowers.Cu.getGlobalForObject;
   let testingFunctions = SpecialPowers.Cu.getJSTestingFunctions();
   let wasmExtractCode = SpecialPowers.unwrap(testingFunctions.wasmExtractCode);
-  let exp1 = wasmExtractCode(module1);
-  let exp2 = wasmExtractCode(module2);
+  let exp1 = wasmExtractCode(module1, "ion");
+  let exp2 = wasmExtractCode(module2, "ion");
   let code1 = exp1.code;
   let code2 = exp2.code;
   ok(code1 instanceof getGlobalForObject(code1).Uint8Array, "Instance of Uint8Array");
   ok(code2 instanceof getGlobalForObject(code1).Uint8Array, "Instance of Uint8Array");
   ok(code1.length == code2.length, "Correct length");
   verifyBuffers(code1, code2);
   continueToNextStep();
 }
--- a/dom/indexedDB/test/unit/xpcshell-child-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-child-process.ini
@@ -1,17 +1,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 [DEFAULT]
 dupe-manifest =
 head = xpcshell-head-child-process.js
 tail =
-skip-if = toolkit == 'android' || toolkit == 'gonk'
+skip-if = toolkit == 'android'
 support-files =
   GlobalObjectsChild.js
   GlobalObjectsComponent.js
   GlobalObjectsComponent.manifest
   GlobalObjectsModule.jsm
   GlobalObjectsSandbox.js
   xpcshell-head-parent-process.js
   xpcshell-shared.ini
--- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
+++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
@@ -502,18 +502,18 @@ function verifyView(view1, view2)
   is(view1.byteLength, view2.byteLength, "Correct byteLength");
   verifyBuffers(view1, view2);
   continueToNextStep();
 }
 
 function verifyWasmModule(module1, module2)
 {
   let testingFunctions = Cu.getJSTestingFunctions();
-  let exp1 = testingFunctions.wasmExtractCode(module1);
-  let exp2 = testingFunctions.wasmExtractCode(module2);
+  let exp1 = testingFunctions.wasmExtractCode(module1, "ion");
+  let exp2 = testingFunctions.wasmExtractCode(module2, "ion");
   let code1 = exp1.code;
   let code2 = exp2.code;
   ok(code1 instanceof Uint8Array, "Instance of Uint8Array");
   ok(code1.length == code2.length, "Correct length");
   verifyBuffers(code1, code2);
   continueToNextStep();
 }
 
--- a/dom/indexedDB/test/unit/xpcshell-parent-process.ini
+++ b/dom/indexedDB/test/unit/xpcshell-parent-process.ini
@@ -1,17 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 [DEFAULT]
 dupe-manifest =
 head = xpcshell-head-parent-process.js
 tail =
-skip-if = toolkit == 'gonk'
 support-files =
   bug1056939_profile.zip
   defaultStorageUpgrade_profile.zip
   idbSubdirUpgrade1_profile.zip
   idbSubdirUpgrade2_profile.zip
   mutableFileUpgrade_profile.zip
   obsoleteOriginAttributes_profile.zip
   oldDirectories_profile.zip
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -716,18 +716,17 @@ interface nsIDOMWindowUtils : nsISupport
    * Create a new or update an existing touch point on the digitizer.
    * To trigger os level gestures, individual touch points should
    * transition through a complete set of touch states which should be
    * sent as individual calls. For example:
    * tap - msg1:TOUCH_CONTACT, msg2:TOUCH_REMOVE
    * drag - msg1-n:TOUCH_CONTACT (moving), msgn+1:TOUCH_REMOVE
    * hover drag - msg1-n:TOUCH_HOVER (moving), msgn+1:TOUCH_REMOVE
    *
-   * Widget support: Windows 8.0+, Winrt/Win32. Gonk supports CONTACT, REMOVE,
-   * and CANCEL but no HOVER. Other widgets will throw.
+   * Widget support: Windows 8.0+, Winrt/Win32. Other widgets will throw.
    *
    * NOTE: The synthesized native event will be fired asynchronously, and upon
    * completion the observer, if provided, will be notified with a "touchpoint"
    * topic.
    *
    * @param aPointerId The touch point id to create or update.
    * @param aTouchState one or more of the touch states listed above
    * @param aScreenX, aScreenY screen coords of this event
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1988,22 +1988,19 @@ ContentParent::LaunchSubprocess(ProcessP
 
   std::vector<std::string> extraArgs;
   extraArgs.push_back("-childID");
   char idStr[21];
   SprintfLiteral(idStr, "%" PRId64, static_cast<uint64_t>(mChildID));
   extraArgs.push_back(idStr);
   extraArgs.push_back(IsForBrowser() ? "-isForBrowser" : "-notForBrowser");
 
-  char boolBuf[1024];
-  char intBuf[1024];
-  char strBuf[1024];
-  nsFixedCString boolPrefs(boolBuf, 1024, 0);
-  nsFixedCString intPrefs(intBuf, 1024, 0);
-  nsFixedCString stringPrefs(strBuf, 1024, 0);
+  nsAutoCStringN<1024> boolPrefs;
+  nsAutoCStringN<1024> intPrefs;
+  nsAutoCStringN<1024> stringPrefs;
 
   size_t prefsLen;
   ContentPrefs::GetContentPrefs(&prefsLen);
 
   for (unsigned int i = 0; i < prefsLen; i++) {
     MOZ_ASSERT(i == 0 || strcmp(ContentPrefs::GetContentPref(i), ContentPrefs::GetContentPref(i - 1)) > 0);
     switch (Preferences::GetType(ContentPrefs::GetContentPref(i))) {
     case nsIPrefBranch::PREF_INT:
@@ -5133,17 +5130,27 @@ ContentParent::UpdateCookieStatus(nsICha
 }
 
 nsresult
 ContentParent::AboutToLoadHttpFtpWyciwygDocumentForChild(nsIChannel* aChannel)
 {
   MOZ_ASSERT(aChannel);
 
   nsresult rv;
-  if (!aChannel->IsDocument()) {
+  bool isDocument = aChannel->IsDocument();
+  if (!isDocument) {
+    // We may be looking at a nsIHttpChannel which has isMainDocumentChannel set
+    // (e.g. the internal http channel for a view-source: load.).
+    nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
+    if (httpChannel) {
+      rv = httpChannel->GetIsMainDocumentChannel(&isDocument);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
+  if (!isDocument) {
     return NS_OK;
   }
 
   // Get the principal for the channel result, so that we can get the permission
   // key for the document which will be created from this response.
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   if (NS_WARN_IF(!ssm)) {
     return NS_ERROR_FAILURE;
@@ -5153,19 +5160,17 @@ ContentParent::AboutToLoadHttpFtpWyciwyg
   rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(principal));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = TransmitPermissionsForPrincipal(principal);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsLoadFlags newLoadFlags;
   aChannel->GetLoadFlags(&newLoadFlags);
-  bool isDocument = false;
-  aChannel->GetIsDocument(&isDocument);
-  if (newLoadFlags & nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE && isDocument) {
+  if (newLoadFlags & nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE) {
     UpdateCookieStatus(aChannel);
   }
 
   return NS_OK;
 }
 
 nsresult
 ContentParent::TransmitPermissionsForPrincipal(nsIPrincipal* aPrincipal)
--- a/dom/ipc/ContentPrefs.cpp
+++ b/dom/ipc/ContentPrefs.cpp
@@ -49,16 +49,17 @@ const char* mozilla::dom::ContentPrefs::
   "dom.enable_resource_timing",
   "dom.event.handling-user-input-time-limit",
   "dom.event.touch.coalescing.enabled",
   "dom.forms.autocomplete.formautofill",
   "dom.ipc.processPriorityManager.backgroundGracePeriodMS",
   "dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS",
   "dom.ipc.useNativeEventProcessing.content",
   "dom.max_chrome_script_run_time",
+  "dom.max_ext_content_script_run_time",
   "dom.max_script_run_time",
   "dom.mozBrowserFramesEnabled",
   "dom.performance.enable_notify_performance_timing",
   "dom.performance.enable_user_timing_logging",
   "dom.storage.testing",
   "dom.url.encode_decode_hash",
   "dom.url.getters_decode_hash",
   "dom.use_watchdog",
@@ -108,16 +109,17 @@ const char* mozilla::dom::ContentPrefs::
   "javascript.options.shared_memory",
   "javascript.options.streams",
   "javascript.options.strict",
   "javascript.options.strict.debug",
   "javascript.options.throw_on_asmjs_validation_failure",
   "javascript.options.throw_on_debuggee_would_run",
   "javascript.options.wasm",
   "javascript.options.wasm_baselinejit",
+  "javascript.options.wasm_ionjit",
   "javascript.options.werror",
   "javascript.use_us_english_locale",
   "layout.idle_period.required_quiescent_frames",
   "layout.idle_period.time_limit",
   "layout.interruptible-reflow.enabled",
   "mathml.disabled",
   "media.apple.forcevda",
   "media.clearkey.persistent-license.enabled",
--- a/dom/ipc/PProcessHangMonitor.ipdl
+++ b/dom/ipc/PProcessHangMonitor.ipdl
@@ -9,16 +9,17 @@ using base::ProcessId from "base/process
 using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 
 namespace mozilla {
 
 struct SlowScriptData
 {
   TabId tabId;
   nsCString filename;
+  nsString addonId;
 };
 
 struct PluginHangData
 {
   uint32_t pluginId;
   ProcessId contentProcessId;
 };
 
@@ -30,17 +31,17 @@ union HangData
 
 protocol PProcessHangMonitor
 {
 parent:
   async HangEvidence(HangData data);
   async ClearHang();
 
 child:
-  async TerminateScript();
+  async TerminateScript(bool aTerminateGlobal);
 
   async BeginStartingDebugger();
   async EndStartingDebugger();
 
   async ForcePaint(TabId tabId, uint64_t aLayerObserverEpoch);
 };
 
 } // namespace mozilla
--- a/dom/ipc/ProcessHangMonitor.cpp
+++ b/dom/ipc/ProcessHangMonitor.cpp
@@ -80,30 +80,32 @@ class HangMonitorChild
  public:
   explicit HangMonitorChild(ProcessHangMonitor* aMonitor);
   ~HangMonitorChild() override;
 
   void Bind(Endpoint<PProcessHangMonitorChild>&& aEndpoint);
 
   typedef ProcessHangMonitor::SlowScriptAction SlowScriptAction;
   SlowScriptAction NotifySlowScript(nsITabChild* aTabChild,
-                                    const char* aFileName);
+                                    const char* aFileName,
+                                    const nsString& aAddonId);
   void NotifySlowScriptAsync(TabId aTabId,
-                             const nsCString& aFileName);
+                             const nsCString& aFileName,
+                             const nsString& aAddonId);
 
   bool IsDebuggerStartupComplete();
 
   void NotifyPluginHang(uint32_t aPluginId);
   void NotifyPluginHangAsync(uint32_t aPluginId);
 
   void ClearHang();
   void ClearHangAsync();
   void ClearForcePaint();
 
-  mozilla::ipc::IPCResult RecvTerminateScript() override;
+  mozilla::ipc::IPCResult RecvTerminateScript(const bool& aTerminateGlobal) override;
   mozilla::ipc::IPCResult RecvBeginStartingDebugger() override;
   mozilla::ipc::IPCResult RecvEndStartingDebugger() override;
 
   mozilla::ipc::IPCResult RecvForcePaint(const TabId& aTabId, const uint64_t& aLayerObserverEpoch) override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   void InterruptCallback();
@@ -126,16 +128,17 @@ class HangMonitorChild
   const RefPtr<ProcessHangMonitor> mHangMonitor;
   Monitor mMonitor;
 
   // Main thread-only.
   bool mSentReport;
 
   // These fields must be accessed with mMonitor held.
   bool mTerminateScript;
+  bool mTerminateGlobal;
   bool mStartDebugger;
   bool mFinishedStartingDebugger;
   bool mForcePaint;
   TabId mForcePaintTab;
   MOZ_INIT_OUTSIDE_CTOR uint64_t mForcePaintEpoch;
   JSContext* mContext;
   bool mShutdownDone;
 
@@ -157,20 +160,22 @@ public:
 
   HangMonitoredProcess(HangMonitorParent* aActor,
                        ContentParent* aContentParent)
     : mActor(aActor), mContentParent(aContentParent) {}
 
   NS_IMETHOD GetHangType(uint32_t* aHangType) override;
   NS_IMETHOD GetScriptBrowser(nsIDOMElement** aBrowser) override;
   NS_IMETHOD GetScriptFileName(nsACString& aFileName) override;
+  NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
 
   NS_IMETHOD GetPluginName(nsACString& aPluginName) override;
 
   NS_IMETHOD TerminateScript() override;
+  NS_IMETHOD TerminateGlobal() override;
   NS_IMETHOD BeginStartingDebugger() override;
   NS_IMETHOD EndStartingDebugger() override;
   NS_IMETHOD TerminatePlugin() override;
   NS_IMETHOD UserCanceled() override;
 
   NS_IMETHOD IsReportForBrowser(nsIFrameLoader* aFrameLoader, bool* aResult) override;
 
   // Called when a content process shuts down.
@@ -225,17 +230,17 @@ public:
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   void SetProcess(HangMonitoredProcess* aProcess) { mProcess = aProcess; }
 
   void Shutdown();
 
   void ForcePaint(dom::TabParent* aTabParent, uint64_t aLayerObserverEpoch);
 
-  void TerminateScript();
+  void TerminateScript(bool aTerminateGlobal);
   void BeginStartingDebugger();
   void EndStartingDebugger();
   void CleanupPluginHang(uint32_t aPluginId, bool aRemoveFiles);
 
   /**
    * Update the dump for the specified plugin. This method is thread-safe and
    * is used to replace a browser minidump with a full minidump. If aDumpId is
    * empty this is a no-op.
@@ -290,16 +295,17 @@ bool HangMonitorParent::sShouldForcePain
 
 /* HangMonitorChild implementation */
 
 HangMonitorChild::HangMonitorChild(ProcessHangMonitor* aMonitor)
  : mHangMonitor(aMonitor),
    mMonitor("HangMonitorChild lock"),
    mSentReport(false),
    mTerminateScript(false),
+   mTerminateGlobal(false),
    mStartDebugger(false),
    mFinishedStartingDebugger(false),
    mForcePaint(false),
    mShutdownDone(false),
    mIPCOpen(true)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   mContext = danger::GetJSContext();
@@ -376,22 +382,26 @@ HangMonitorChild::ActorDestroy(ActorDest
   // We use a task here to ensure that IPDL is finished with this
   // HangMonitorChild before it gets deleted on the main thread.
   Dispatch(NewNonOwningRunnableMethod("HangMonitorChild::ShutdownOnThread",
                                       this,
                                       &HangMonitorChild::ShutdownOnThread));
 }
 
 mozilla::ipc::IPCResult
-HangMonitorChild::RecvTerminateScript()
+HangMonitorChild::RecvTerminateScript(const bool& aTerminateGlobal)
 {
   MOZ_RELEASE_ASSERT(IsOnThread());
 
   MonitorAutoLock lock(mMonitor);
-  mTerminateScript = true;
+  if (aTerminateGlobal) {
+    mTerminateGlobal = true;
+  } else {
+    mTerminateScript = true;
+  }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 HangMonitorChild::RecvBeginStartingDebugger()
 {
   MOZ_RELEASE_ASSERT(IsOnThread());
 
@@ -447,58 +457,65 @@ HangMonitorChild::Bind(Endpoint<PProcess
   sInstance = this;
 
   DebugOnly<bool> ok = aEndpoint.Bind(this);
   MOZ_ASSERT(ok);
 }
 
 void
 HangMonitorChild::NotifySlowScriptAsync(TabId aTabId,
-                                        const nsCString& aFileName)
+                                        const nsCString& aFileName,
+                                        const nsString& aAddonId)
 {
   if (mIPCOpen) {
-    Unused << SendHangEvidence(SlowScriptData(aTabId, aFileName));
+    Unused << SendHangEvidence(SlowScriptData(aTabId, aFileName, aAddonId));
   }
 }
 
 HangMonitorChild::SlowScriptAction
 HangMonitorChild::NotifySlowScript(nsITabChild* aTabChild,
-                                   const char* aFileName)
+                                   const char* aFileName,
+                                   const nsString& aAddonId)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   mSentReport = true;
 
   {
     MonitorAutoLock lock(mMonitor);
 
     if (mTerminateScript) {
       mTerminateScript = false;
       return SlowScriptAction::Terminate;
     }
 
+    if (mTerminateGlobal) {
+      mTerminateGlobal = false;
+      return SlowScriptAction::TerminateGlobal;
+    }
+
     if (mStartDebugger) {
       mStartDebugger = false;
       return SlowScriptAction::StartDebugger;
     }
   }
 
   TabId id;
   if (aTabChild) {
     RefPtr<TabChild> tabChild = static_cast<TabChild*>(aTabChild);
     id = tabChild->GetTabId();
   }
   nsAutoCString filename(aFileName);
 
-  Dispatch(NewNonOwningRunnableMethod<TabId, nsCString>(
+  Dispatch(NewNonOwningRunnableMethod<TabId, nsCString, nsString>(
     "HangMonitorChild::NotifySlowScriptAsync",
     this,
     &HangMonitorChild::NotifySlowScriptAsync,
     id,
-    filename));
+    filename, aAddonId));
   return SlowScriptAction::Continue;
 }
 
 bool
 HangMonitorChild::IsDebuggerStartupComplete()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
@@ -549,16 +566,17 @@ HangMonitorChild::ClearHang()
     // bounce to background thread
     Dispatch(NewNonOwningRunnableMethod("HangMonitorChild::ClearHangAsync",
                                         this,
                                         &HangMonitorChild::ClearHangAsync));
 
     MonitorAutoLock lock(mMonitor);
     mSentReport = false;
     mTerminateScript = false;
+    mTerminateGlobal = false;
     mStartDebugger = false;
     mFinishedStartingDebugger = false;
   }
 }
 
 void
 HangMonitorChild::ClearHangAsync()
 {
@@ -831,22 +849,22 @@ HangMonitorParent::RecvClearHang()
   NS_DispatchToMainThread(
     mMainThreadTaskFactory.NewRunnableMethod(
       &HangMonitorParent::ClearHangNotification));
 
   return IPC_OK();
 }
 
 void
-HangMonitorParent::TerminateScript()
+HangMonitorParent::TerminateScript(bool aTerminateGlobal)
 {
   MOZ_RELEASE_ASSERT(IsOnThread());
 
   if (mIPCOpen) {
-    Unused << SendTerminateScript();
+    Unused << SendTerminateScript(aTerminateGlobal);
   }
 }
 
 void
 HangMonitorParent::BeginStartingDebugger()
 {
   MOZ_RELEASE_ASSERT(IsOnThread());
 
@@ -951,16 +969,28 @@ HangMonitoredProcess::GetScriptFileName(
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   aFileName = mHangData.get_SlowScriptData().filename();
   return NS_OK;
 }
 
 NS_IMETHODIMP
+HangMonitoredProcess::GetAddonId(nsAString& aAddonId)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (mHangData.type() != HangData::TSlowScriptData) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  aAddonId = mHangData.get_SlowScriptData().addonId();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 HangMonitoredProcess::GetPluginName(nsACString& aPluginName)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   if (mHangData.type() != HangData::TPluginHangData) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   uint32_t id = mHangData.get_PluginHangData().pluginId();
@@ -983,19 +1013,38 @@ HangMonitoredProcess::TerminateScript()
     return NS_ERROR_UNEXPECTED;
   }
 
   if (!mActor) {
     return NS_ERROR_UNEXPECTED;
   }
 
   ProcessHangMonitor::Get()->Dispatch(
-    NewNonOwningRunnableMethod("HangMonitorParent::TerminateScript",
-                               mActor,
-                               &HangMonitorParent::TerminateScript));
+    NewNonOwningRunnableMethod<bool>("HangMonitorParent::TerminateScript",
+                                     mActor,
+                                     &HangMonitorParent::TerminateScript, false));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HangMonitoredProcess::TerminateGlobal()
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (mHangData.type() != HangData::TSlowScriptData) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  if (!mActor) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  ProcessHangMonitor::Get()->Dispatch(
+    NewNonOwningRunnableMethod<bool>("HangMonitorParent::TerminateScript",
+                                     mActor,
+                                     &HangMonitorParent::TerminateScript, true));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HangMonitoredProcess::BeginStartingDebugger()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   if (mHangData.type() != HangData::TSlowScriptData) {
@@ -1160,20 +1209,21 @@ ProcessHangMonitor::Observe(nsISupports*
       obs->RemoveObserver(this, "xpcom-shutdown");
     }
   }
   return NS_OK;
 }
 
 ProcessHangMonitor::SlowScriptAction
 ProcessHangMonitor::NotifySlowScript(nsITabChild* aTabChild,
-                                     const char* aFileName)
+                                     const char* aFileName,
+                                     const nsString& aAddonId)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
-  return HangMonitorChild::Get()->NotifySlowScript(aTabChild, aFileName);
+  return HangMonitorChild::Get()->NotifySlowScript(aTabChild, aFileName, aAddonId);
 }
 
 bool
 ProcessHangMonitor::IsDebuggerStartupComplete()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   return HangMonitorChild::Get()->IsDebuggerStartupComplete();
 }
--- a/dom/ipc/ProcessHangMonitor.h
+++ b/dom/ipc/ProcessHangMonitor.h
@@ -10,16 +10,17 @@
 #include "mozilla/AlreadyAddRefed.h"
 #include "mozilla/Atomics.h"
 #include "nsCOMPtr.h"
 #include "nsIObserver.h"
 
 class nsIRunnable;
 class nsITabChild;
 class nsIThread;
+class nsString;
 
 namespace mozilla {
 
 namespace dom {
 class ContentParent;
 class TabParent;
 } // namespace dom
 
@@ -47,20 +48,22 @@ class ProcessHangMonitor final
   static void ForcePaint(PProcessHangMonitorParent* aParent,
                          dom::TabParent* aTab,
                          uint64_t aLayerObserverEpoch);
   static void ClearForcePaint();
 
   enum SlowScriptAction {
     Continue,
     Terminate,
-    StartDebugger
+    StartDebugger,
+    TerminateGlobal,
   };
   SlowScriptAction NotifySlowScript(nsITabChild* aTabChild,
-                                    const char* aFileName);
+                                    const char* aFileName,
+                                    const nsString& aAddonId);
 
   void NotifyPluginHang(uint32_t aPluginId);
 
   bool IsDebuggerStartupComplete();
 
   void InitiateCPOWTimeout();
   bool ShouldTimeOutCPOWs();
 
--- a/dom/ipc/nsIHangReport.idl
+++ b/dom/ipc/nsIHangReport.idl
@@ -27,29 +27,35 @@ interface nsIHangReport : nsISupports
   // The type of hang being reported: SLOW_SCRIPT or PLUGIN_HANG.
   readonly attribute unsigned long hangType;
 
   // For SLOW_SCRIPT reports, these fields contain information about the
   // slow script.
   // Only valid for SLOW_SCRIPT reports.
   readonly attribute nsIDOMElement scriptBrowser;
   readonly attribute ACString scriptFileName;
+  readonly attribute AString addonId;
 
   // For PLUGIN_HANGs, this field contains information about the plugin.
   // Only valid for PLUGIN_HANG reports.
   readonly attribute ACString pluginName;
 
   // Called by front end code when user ignores or cancels
   // the notification.
   void userCanceled();
 
   // Terminate the slow script if it is still running.
   // Only valid for SLOW_SCRIPT reports.
   void terminateScript();
 
+  // Terminate all scripts on the global that triggered the slow script
+  // warning.
+  // Only valid for SLOW_SCRIPT reports.
+  void terminateGlobal();
+
   // Terminate the plugin if it is still hung.
   // Only valid for PLUGIN_HANG reports.
   void terminatePlugin();
 
   // Ask the content process to start up the slow script debugger.
   // Only valid for SLOW_SCRIPT reports.
   void beginStartingDebugger();
 
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -1,16 +1,22 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 KillScriptTitle=Warning: Unresponsive script
 KillScriptMessage=A script on this page may be busy, or it may have stopped responding. You can stop the script now, or you can continue to see if the script will complete.
 KillScriptWithDebugMessage=A script on this page may be busy, or it may have stopped responding. You can stop the script now, open the script in the debugger, or let the script continue.
 KillScriptLocation=Script: %S
+
+KillAddonScriptTitle=Warning: Unresponsive add-on script
+# LOCALIZATION NOTE (KillAddonScriptMessage): The first %S is the name of an add-on. The second %S is the name of the application (e.g., Firefox).
+KillAddonScriptMessage=A script from the add-on “%S” is running on this page, and making %S unresponsive.\n\nIt may be busy, or it may have stopped responsing permanently. You can stop the script now, or you can continue to see if it will complete.
+KillAddonScriptGlobalMessage=Prevent the add-on script from running on this page until it next reloads.
+
 StopScriptButton=Stop script
 DebugScriptButton=Debug script
 WaitForScriptButton=Continue
 DontAskAgain=&Don’t ask me again
 JSURLLoadBlockedWarning=Attempt to load a javascript: URL from one host\nin a window displaying content from another host\nwas blocked by the security manager.
 WindowCloseBlockedWarning=Scripts may not close windows that were not opened by script.
 OnBeforeUnloadTitle=Are you sure?
 OnBeforeUnloadMessage=This page is asking you to confirm that you want to leave - data you have entered may not be saved.
--- a/dom/media/MediaDevices.cpp
+++ b/dom/media/MediaDevices.cpp
@@ -77,18 +77,16 @@ public:
   NS_DECL_ISUPPORTS
 
   EnumDevResolver(Promise* aPromise, uint64_t aWindowId)
   : mPromise(aPromise), mWindowId(aWindowId) {}
 
   NS_IMETHOD
   OnSuccess(nsIVariant* aDevices) override
   {
-    // Cribbed from MediaPermissionGonk.cpp
-
     // Create array for nsIMediaDevice
     nsTArray<nsCOMPtr<nsIMediaDevice>> devices;
     // Contain the fumes
     {
       uint16_t vtype;
       nsresult rv = aDevices->GetDataType(&vtype);
       NS_ENSURE_SUCCESS(rv, rv);
       if (vtype != nsIDataType::VTYPE_EMPTY_ARRAY) {
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -111,19 +111,16 @@ private:
   DECL_MEDIA_PREF("media.clearkey.persistent-license.enabled", ClearKeyPersistentLicenseEnabled, bool, false);
 
   // PlatformDecoderModule
   DECL_MEDIA_PREF("media.apple.forcevda",                     AppleForceVDA, bool, false);
   DECL_MEDIA_PREF("media.gmp.insecure.allow",                 GMPAllowInsecure, bool, false);
   DECL_MEDIA_PREF("media.eme.enabled",                        EMEEnabled, bool, false);
   DECL_MEDIA_PREF("media.use-blank-decoder",                  PDMUseBlankDecoder, bool, false);
   DECL_MEDIA_PREF("media.gpu-process-decoder",                PDMUseGPUDecoder, bool, false);
-#ifdef MOZ_GONK_MEDIACODEC
-  DECL_MEDIA_PREF("media.gonk.enabled",                       PDMGonkDecoderEnabled, bool, true);
-#endif
 #ifdef MOZ_WIDGET_ANDROID
   DECL_MEDIA_PREF("media.android-media-codec.enabled",        PDMAndroidMediaCodecEnabled, bool, false);
   DECL_MEDIA_PREF("media.android-media-codec.preferred",      PDMAndroidMediaCodecPreferred, bool, false);
   DECL_MEDIA_PREF("media.navigator.hardware.vp8_encode.acceleration_remote_enabled", RemoteMediaCodecVP8EncoderEnabled, bool, false);
 #endif
   // WebRTC
   DECL_MEDIA_PREF("media.navigator.mediadatadecoder_enabled", MediaDataDecoderEnabled, bool, false);
 #ifdef MOZ_FFMPEG
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -60,20 +60,16 @@ MP4Decoder::IsSupportedType(const MediaC
 
   // Whitelist MP4 types, so they explicitly match what we encounter on
   // the web, as opposed to what we use internally (i.e. what our demuxers
   // etc output).
   const bool isAudio = aType.Type() == MEDIAMIMETYPE("audio/mp4")
                        || aType.Type() == MEDIAMIMETYPE("audio/x-m4a");
   const bool isVideo = aType.Type() == MEDIAMIMETYPE("video/mp4")
                        || aType.Type() == MEDIAMIMETYPE("video/quicktime")
-  // On B2G, treat 3GPP as MP4 when Gonk PDM is available.
-#ifdef MOZ_GONK_MEDIACODEC
-                       || aType.Type() == MEDIAMIMETYPE(VIDEO_3GPP)
-#endif
                        || aType.Type() == MEDIAMIMETYPE("video/x-m4v");
 
   if (!isAudio && !isVideo) {
     return false;
   }
 
   nsTArray<UniquePtr<TrackInfo>> trackInfos;
   if (aType.ExtendedType().Codecs().IsEmpty()) {
--- a/dom/media/fmp4/moz.build
+++ b/dom/media/fmp4/moz.build
@@ -13,11 +13,8 @@ UNIFIED_SOURCES += [
     'MP4Decoder.cpp',
 ]
 
 SOURCES += [
     'MP4Demuxer.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
-
-if CONFIG['MOZ_GONK_MEDIACODEC']:
-    DEFINES['MOZ_GONK_MEDIACODEC'] = True
--- a/dom/media/mediasource/moz.build
+++ b/dom/media/mediasource/moz.build
@@ -33,17 +33,14 @@ UNIFIED_SOURCES += [
     'SourceBufferResource.cpp',
     'TrackBuffersManager.cpp',
 ]
 
 TEST_DIRS += [
     'gtest',
 ]
 
-if CONFIG['MOZ_GONK_MEDIACODEC']:
-    DEFINES['MOZ_GONK_MEDIACODEC'] = True
-
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -315,19 +315,16 @@ DEFINES['MOZILLA_INTERNAL_API'] = True
 if CONFIG['OS_TARGET'] == 'WINNT':
     DEFINES['WEBRTC_WIN'] = True
 else:
     DEFINES['WEBRTC_POSIX'] = True
 
 if CONFIG['ANDROID_VERSION'] > '15':
     DEFINES['MOZ_OMX_WEBM_DECODER'] = True
 
-if CONFIG['MOZ_GONK_MEDIACODEC']:
-    DEFINES['MOZ_GONK_MEDIACODEC'] = True
-
 if CONFIG['MOZ_ANDROID_HLS_SUPPORT']:
     DEFINES['MOZ_ANDROID_HLS_SUPPORT'] = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 # Suppress some GCC warnings being treated as errors:
 #  - about attributes on forward declarations for types that are already
 #    defined, which complains about an important MOZ_EXPORT for android::AString
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -13,19 +13,16 @@
 #include "FFVPXRuntimeLinker.h"
 #endif
 #ifdef MOZ_FFMPEG
 #include "FFmpegRuntimeLinker.h"
 #endif
 #ifdef MOZ_APPLEMEDIA
 #include "AppleDecoderModule.h"
 #endif
-#ifdef MOZ_GONK_MEDIACODEC
-#include "GonkDecoderModule.h"
-#endif
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidDecoderModule.h"
 #endif
 #include "GMPDecoderModule.h"
 
 #include "mozilla/CDMProxy.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/SharedThreadPool.h"
@@ -366,22 +363,16 @@ PDMFactory::CreatePDMs()
   } else {
     mFFmpegFailedToLoad = false;
   }
 #endif
 #ifdef MOZ_APPLEMEDIA
   m = new AppleDecoderModule();
   StartupPDM(m);
 #endif
-#ifdef MOZ_GONK_MEDIACODEC
-  if (MediaPrefs::PDMGonkDecoderEnabled()) {
-    m = new GonkDecoderModule();
-    StartupPDM(m);
-  }
-#endif
 #ifdef MOZ_WIDGET_ANDROID
   if(MediaPrefs::PDMAndroidMediaCodecEnabled()){
     m = new AndroidDecoderModule();
     StartupPDM(m, MediaPrefs::PDMAndroidMediaCodecPreferred());
   }
 #endif
 
   m = new AgnosticDecoderModule();
--- a/dom/media/platforms/omx/OmxDataDecoder.cpp
+++ b/dom/media/platforms/omx/OmxDataDecoder.cpp
@@ -295,18 +295,18 @@ OmxDataDecoder::DoAsyncShutdown()
 }
 
 void
 OmxDataDecoder::FillBufferDone(BufferData* aData)
 {
   MOZ_ASSERT(!aData || aData->mStatus == BufferData::BufferStatus::OMX_CLIENT);
 
   // Don't output sample when flush or shutting down, especially for video
-  // decoded frame. Because video decoded frame has a promise in BufferData
-  // waiting for layer to resolve it via recycle callback on Gonk, if other
+  // decoded frame. Because video decoded frame can have a promise in
+  // BufferData waiting for layer to resolve it via recycle callback, if other
   // module doesn't send it to layer, it will cause a unresolved promise and
   // waiting for resolve infinitely.
   if (mFlushing || mShuttingDown) {
     LOG("mFlush or mShuttingDown, drop data");
     aData->mStatus = BufferData::BufferStatus::FREE;
     return;
   }
 
@@ -331,18 +331,17 @@ OmxDataDecoder::Output(BufferData* aData
   RefPtr<MediaData> data = mMediaDataHelper->GetMediaData(aData, isPlatformData);
   if (!data) {
     aData->mStatus = BufferData::BufferStatus::FREE;
     return;
   }
 
   if (isPlatformData) {
     // If the MediaData is platform dependnet data, it's mostly a kind of
-    // limited resource, for example, GraphicBuffer on Gonk. So we use promise
-    // to notify when the resource is free.
+    // limited resource, so we use promise to notify when the resource is free.
     aData->mStatus = BufferData::BufferStatus::OMX_CLIENT_OUTPUT;
 
     MOZ_RELEASE_ASSERT(aData->mPromise.IsEmpty());
     RefPtr<OmxBufferPromise> p = aData->mPromise.Ensure(__func__);
 
     RefPtr<OmxDataDecoder> self = this;
     RefPtr<BufferData> buffer = aData;
     p->Then(mOmxTaskQueue, __func__,
--- a/dom/media/platforms/omx/OmxPlatformLayer.cpp
+++ b/dom/media/platforms/omx/OmxPlatformLayer.cpp
@@ -277,46 +277,25 @@ OmxPlatformLayer::CompressionFormat()
   } else if (VPXDecoder::IsVP8(mInfo->mMimeType)) {
     return static_cast<OMX_VIDEO_CODINGTYPE>(OMX_VIDEO_CodingVP8);
   } else {
     MOZ_ASSERT_UNREACHABLE("Unsupported compression format");
     return OMX_VIDEO_CodingUnused;
   }
 }
 
-// Implementations for different platforms will be defined in their own files.
-#ifdef OMX_PLATFORM_GONK
-
-bool
-OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType)
-{
-  return GonkOmxPlatformLayer::FindComponents(aMimeType);
-}
-
-OmxPlatformLayer*
-OmxPlatformLayer::Create(OmxDataDecoder* aDataDecoder,
-                         OmxPromiseLayer* aPromiseLayer,
-                         TaskQueue* aTaskQueue,
-                         layers::ImageContainer* aImageContainer)
-{
-  return new GonkOmxPlatformLayer(aDataDecoder, aPromiseLayer, aTaskQueue, aImageContainer);
-}
-
-#else // For platforms without OMX IL support.
-
+// For platforms without OMX IL support.
 bool
 OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType)
 {
   return false;
 }
 
 OmxPlatformLayer*
 OmxPlatformLayer::Create(OmxDataDecoder* aDataDecoder,
                         OmxPromiseLayer* aPromiseLayer,
                         TaskQueue* aTaskQueue,
                         layers::ImageContainer* aImageContainer)
 {
   return nullptr;
 }
 
-#endif
-
 }
--- a/dom/media/platforms/omx/OmxPlatformLayer.h
+++ b/dom/media/platforms/omx/OmxPlatformLayer.h
@@ -39,19 +39,19 @@ public:
   virtual OMX_ERRORTYPE EmptyThisBuffer(BufferData* aData) = 0;
 
   virtual OMX_ERRORTYPE FillThisBuffer(BufferData* aData) = 0;
 
   virtual OMX_ERRORTYPE SendCommand(OMX_COMMANDTYPE aCmd,
                                     OMX_U32 aParam1,
                                     OMX_PTR aCmdData) = 0;
 
-  // Buffer could be platform dependent; for example, video decoding needs gralloc
-  // on Gonk. Therefore, derived class needs to implement its owned buffer
-  // allocate/release API according to its platform type.
+  // Buffer could be platform dependent. Therefore, derived class needs to
+  // implement its owned buffer allocate/release API according to its platform
+  // type.
   virtual nsresult AllocateOmxBuffer(OMX_DIRTYPE aType, BUFFERLIST* aBufferList) = 0;
 
   virtual nsresult ReleaseOmxBuffer(OMX_DIRTYPE aType, BUFFERLIST* aBufferList) = 0;
 
   virtual OMX_ERRORTYPE GetState(OMX_STATETYPE* aType) = 0;
 
   virtual OMX_ERRORTYPE GetParameter(OMX_INDEXTYPE aParamIndex,
                                      OMX_PTR aComponentParameterStructure,
--- a/dom/media/platforms/omx/OmxPromiseLayer.h
+++ b/dom/media/platforms/omx/OmxPromiseLayer.h
@@ -131,17 +131,17 @@ public:
       , mBuffer(aBuffer)
     {}
 
     typedef void* BufferID;
 
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BufferData)
 
     // In most cases, the ID of this buffer is the pointer address of mBuffer.
-    // However, in platform like gonk, it is another value.
+    // However, on some platforms it may be another value.
     virtual BufferID ID()
     {
       return mBuffer;
     }
 
     // Return the platform dependent MediaData().
     // For example, it returns the MediaData with Gralloc texture.
     // If it returns nullptr, then caller uses the normal way to
--- a/dom/media/webrtc/MediaEngine.h
+++ b/dom/media/webrtc/MediaEngine.h
@@ -25,18 +25,17 @@ enum {
   kAudioTrack = 2,
   kTrackCount
 };
 
 /**
  * Abstract interface for managing audio and video devices. Each platform
  * must implement a concrete class that will map these classes and methods
  * to the appropriate backend. For example, on Desktop platforms, these will
- * correspond to equivalent webrtc (GIPS) calls, and on B2G they will map to
- * a Gonk interface.
+ * correspond to equivalent webrtc (GIPS) calls.
  */
 class MediaEngineVideoSource;
 class MediaEngineAudioSource;
 
 enum MediaEngineState {
   kAllocated,
   kStarted,
   kStopped,
@@ -301,17 +300,16 @@ public:
    */
   virtual bool IsFake() = 0;
 
   /* Returns the type of media source (camera, microphone, screen, window, etc) */
   virtual dom::MediaSourceEnum GetMediaSource() const = 0;
 
   /* If implementation of MediaEngineSource supports TakePhoto(), the picture
    * should be return via aCallback object. Otherwise, it returns NS_ERROR_NOT_IMPLEMENTED.
-   * Currently, only Gonk MediaEngineSource implementation supports it.
    */
   virtual nsresult TakePhoto(MediaEnginePhotoCallback* aCallback) = 0;
 
   /* Return false if device is currently allocated or started */
   bool IsAvailable() {
     if (mState == kAllocated || mState == kStarted) {
       return false;
     } else {
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.h
+++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h
@@ -59,25 +59,20 @@ public:
 
   uint32_t GetBestFitnessDistance(
       const nsTArray<const NormalizedConstraintSet*>& aConstraintSets,
       const nsString& aDeviceId) const override;
 
   void Shutdown() override
   {
     MonitorAutoLock lock(mMonitor);
-    // Release mImage and it's resources just in case -- also we can be
-    // held by something in a CC chain, and not be deleted until final-cc,
-    // which is too late for releasing images.  (This should be null'd on
-    // Stop(), but apparently Stop() may not get called in this case
-    // somehow.) (Bug 1374164)
-
+    // really Stop() *should* be called before it gets here
     Unused << NS_WARN_IF(mImage);
-
     mImage = nullptr;
+    mImageContainer = nullptr;
   }
 
 protected:
   struct CapabilityCandidate {
     explicit CapabilityCandidate(uint8_t index, uint32_t distance = 0)
     : mIndex(index), mDistance(distance) {}
 
     size_t mIndex;
@@ -119,20 +114,19 @@ protected:
   // mSources[] and mPrincipalHandles[] are accessed from webrtc threads.
 
   // All the mMonitor accesses are from the child classes.
   Monitor mMonitor; // Monitor for processing Camera frames.
   nsTArray<RefPtr<SourceMediaStream>> mSources; // When this goes empty, we shut down HW
   nsTArray<PrincipalHandle> mPrincipalHandles; // Directly mapped to mSources.
   RefPtr<layers::Image> mImage;
   RefPtr<layers::ImageContainer> mImageContainer;
-  int mWidth, mHeight; // protected with mMonitor on Gonk due to different threading
   // end of data protected by mMonitor
 
-
+  int mWidth, mHeight;
   bool mInitDone;
   bool mHasDirectListeners;
   int mCaptureIndex;
   TrackID mTrackID;
 
   webrtc::CaptureCapability mCapability;
 
   mutable nsTArray<webrtc::CaptureCapability> mHardcodedCapabilities;
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -39,17 +39,19 @@ NS_IMPL_ISUPPORTS(MediaEngineDefaultVide
 
 MediaEngineDefaultVideoSource::MediaEngineDefaultVideoSource()
 #ifdef MOZ_WEBRTC
   : MediaEngineCameraVideoSource("FakeVideo.Monitor")
 #else
   : MediaEngineVideoSource()
 #endif
   , mTimer(nullptr)
+#ifndef MOZ_WEBRTC
   , mMonitor("Fake video")
+#endif
   , mCb(16), mCr(16)
 {
   mImageContainer =
     layers::LayerManager::CreateImageContainer(layers::ImageContainer::ASYNCHRONOUS);
 }
 
 MediaEngineDefaultVideoSource::~MediaEngineDefaultVideoSource()
 {}
--- a/dom/media/webrtc/MediaEngineDefault.h
+++ b/dom/media/webrtc/MediaEngineDefault.h
@@ -82,34 +82,43 @@ public:
     return dom::MediaSourceEnum::Camera;
   }
 
   nsresult TakePhoto(MediaEnginePhotoCallback* aCallback) override
   {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
+  void Shutdown() override {
+    Stop(mSource, mTrackID);
+    MonitorAutoLock lock(mMonitor);
+    mImageContainer = nullptr;
+  }
+
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
   NS_DECL_NSINAMED
 
 protected:
   ~MediaEngineDefaultVideoSource();
 
   friend class MediaEngineDefault;
 
+  RefPtr<SourceMediaStream> mSource;
   TrackID mTrackID;
   nsCOMPtr<nsITimer> mTimer;
-  // mMonitor protects mImage access/changes, and transitions of mState
-  // from kStarted to kStopped (which are combined with EndTrack() and
-  // image changes).
+
+#ifndef MOZ_WEBRTC
+  // mMonitor protects mImage/mImageContainer access/changes, and
+  // transitions of mState from kStarted to kStopped (which are combined
+  // with EndTrack() and image changes).
   Monitor mMonitor;
   RefPtr<layers::Image> mImage;
-
   RefPtr<layers::ImageContainer> mImageContainer;
+#endif
 
   MediaEnginePrefs mOpts;
   int mCb;
   int mCr;
 };
 
 class SineWaveGenerator;
 
@@ -194,25 +203,30 @@ public:
 
   void EnumerateVideoDevices(dom::MediaSourceEnum,
                              nsTArray<RefPtr<MediaEngineVideoSource> >*) override;
   void EnumerateAudioDevices(dom::MediaSourceEnum,
                              nsTArray<RefPtr<MediaEngineAudioSource> >*) override;
   void Shutdown() override {
     MutexAutoLock lock(mMutex);
 
+    for (auto& source : mVSources) {
+      source->Shutdown();
+    }
+    for (auto& source : mASources) {
+      source->Shutdown();
+    }
     mVSources.Clear();
     mASources.Clear();
   };
 
 private:
   ~MediaEngineDefault() {}
 
   Mutex mMutex;
   // protected with mMutex:
-
   nsTArray<RefPtr<MediaEngineVideoSource> > mVSources;
   nsTArray<RefPtr<MediaEngineAudioSource> > mASources;
 };
 
 } // namespace mozilla
 
 #endif /* NSMEDIAENGINEDEFAULT_H_ */
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -65,17 +65,16 @@ MediaEngineRemoteVideoSource::Init()
 
 void
 MediaEngineRemoteVideoSource::Shutdown()
 {
   LOG((__PRETTY_FUNCTION__));
   if (!mInitDone) {
     return;
   }
-  Super::Shutdown();
   if (mState == kStarted) {
     SourceMediaStream *source;
     bool empty;
 
     while (1) {
       {
         MonitorAutoLock lock(mMonitor);
         empty = mSources.IsEmpty();
@@ -91,16 +90,17 @@ MediaEngineRemoteVideoSource::Shutdown()
   }
 
   for (auto& registered : mRegisteredHandles) {
     MOZ_ASSERT(mState == kAllocated || mState == kStopped);
     Deallocate(registered.get());
   }
 
   MOZ_ASSERT(mState == kReleased);
+  Super::Shutdown();
   mInitDone = false;
 }
 
 nsresult
 MediaEngineRemoteVideoSource::Allocate(
     const dom::MediaTrackConstraints& aConstraints,
     const MediaEnginePrefs& aPrefs,
     const nsString& aDeviceId,
@@ -201,18 +201,20 @@ MediaEngineRemoteVideoSource::Stop(mozil
                                    mozilla::TrackID aID)
 {
   LOG((__PRETTY_FUNCTION__));
   AssertIsOnOwningThread();
   {
     MonitorAutoLock lock(mMonitor);
 
     // Drop any cached image so we don't start with a stale image on next
-    // usage
+    // usage.  Also, gfx gets very upset if these are held until this object
+    // is gc'd in final-cc during shutdown (bug 1374164)
     mImage = nullptr;
+    // we drop mImageContainer only in MediaEngineCaptureVideoSource::Shutdown()
 
     size_t i = mSources.IndexOf(aSource);
     if (i == mSources.NoIndex) {
       // Already stopped - this is allowed
       return NS_OK;
     }
 
     MOZ_ASSERT(mSources.Length() == mPrincipalHandles.Length());
@@ -382,53 +384,59 @@ MediaEngineRemoteVideoSource::DeliverFra
   if (mState != kStarted) {
     LOG(("DeliverFrame: video not started"));
     return 0;
   }
 
   // Update the dimensions
   FrameSizeChange(aProps.width(), aProps.height());
 
-  // Create a video frame and append it to the track.
-  RefPtr<layers::PlanarYCbCrImage> image = mImageContainer->CreatePlanarYCbCrImage();
-
-  uint8_t* frame = static_cast<uint8_t*> (aBuffer);
-  const uint8_t lumaBpp = 8;
-  const uint8_t chromaBpp = 4;
+  layers::PlanarYCbCrData data;
+  RefPtr<layers::PlanarYCbCrImage> image;
+  {
+    // We grab the lock twice, but don't hold it across the (long) CopyData
+    MonitorAutoLock lock(mMonitor);
+    if (!mImageContainer) {
+      LOG(("DeliverFrame() called after Stop()!"));
+      return 0;
+    }
+    // Create a video frame and append it to the track.
+    image = mImageContainer->CreatePlanarYCbCrImage();
 
-  // Take lots of care to round up!
-  layers::PlanarYCbCrData data;
-  data.mYChannel = frame;
-  data.mYSize = IntSize(mWidth, mHeight);
-  data.mYStride = (mWidth * lumaBpp + 7)/ 8;
-  data.mCbCrStride = (mWidth * chromaBpp + 7) / 8;
-  data.mCbChannel = frame + mHeight * data.mYStride;
-  data.mCrChannel = data.mCbChannel + ((mHeight+1)/2) * data.mCbCrStride;
-  data.mCbCrSize = IntSize((mWidth+1)/ 2, (mHeight+1)/ 2);
-  data.mPicX = 0;
-  data.mPicY = 0;
-  data.mPicSize = IntSize(mWidth, mHeight);
-  data.mStereoMode = StereoMode::MONO;
+    uint8_t* frame = static_cast<uint8_t*> (aBuffer);
+    const uint8_t lumaBpp = 8;
+    const uint8_t chromaBpp = 4;
+
+    // Take lots of care to round up!
+    data.mYChannel = frame;
+    data.mYSize = IntSize(mWidth, mHeight);
+    data.mYStride = (mWidth * lumaBpp + 7)/ 8;
+    data.mCbCrStride = (mWidth * chromaBpp + 7) / 8;
+    data.mCbChannel = frame + mHeight * data.mYStride;
+    data.mCrChannel = data.mCbChannel + ((mHeight+1)/2) * data.mCbCrStride;
+    data.mCbCrSize = IntSize((mWidth+1)/ 2, (mHeight+1)/ 2);
+    data.mPicX = 0;
+    data.mPicY = 0;
+    data.mPicSize = IntSize(mWidth, mHeight);
+    data.mStereoMode = StereoMode::MONO;
+  }
 
   if (!image->CopyData(data)) {
     MOZ_ASSERT(false);
     return 0;
   }
 
+  MonitorAutoLock lock(mMonitor);
 #ifdef DEBUG
   static uint32_t frame_num = 0;
   LOGFRAME(("frame %d (%dx%d); timeStamp %u, ntpTimeMs %" PRIu64 ", renderTimeMs %" PRIu64,
             frame_num++, mWidth, mHeight,
             aProps.timeStamp(), aProps.ntpTimeMs(), aProps.renderTimeMs()));
 #endif
 
-  // we don't touch anything in 'this' until here (except for snapshot,
-  // which has it's own lock)
-  MonitorAutoLock lock(mMonitor);
-
   // implicitly releases last image
   mImage = image.forget();
 
   // We'll push the frame into the MSG on the next NotifyPull. This will avoid
   // swamping the MSG with frames should it be taking longer than normal to run
   // an iteration.
 
   return 0;
--- a/dom/media/webspeech/synth/pico/nsPicoService.cpp
+++ b/dom/media/webspeech/synth/pico/nsPicoService.cpp
@@ -47,18 +47,18 @@
 #define PICO_RESET_SOFT 0x10
 
 // Currently, Pico only provides mono output.
 #define PICO_CHANNELS_NUM 1
 
 // Pico's sample rate is always 16000
 #define PICO_SAMPLE_RATE 16000
 
-// The path to the language files in Gonk
-#define GONK_PICO_LANG_PATH "/system/tts/lang_pico"
+// The path to the language files in Android
+#define PICO_LANG_PATH "/system/tts/lang_pico"
 
 namespace mozilla {
 namespace dom {
 
 StaticRefPtr<nsPicoService> nsPicoService::sSingleton;
 
 class PicoApi
 {
@@ -509,21 +509,21 @@ nsPicoService::Init()
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_ASSERT(!mInitialized);
 
   if (!sPicoApi.Init()) {
     NS_WARNING("Failed to initialize pico library");
     return;
   }
 
-  // Use environment variable, or default android/b2g path
+  // Use environment variable, or default android path
   nsAutoCString langPath(PR_GetEnv("PICO_LANG_PATH"));
 
   if (langPath.IsEmpty()) {
-    langPath.AssignLiteral(GONK_PICO_LANG_PATH);
+    langPath.AssignLiteral(PICO_LANG_PATH);
   }
 
   nsCOMPtr<nsIFile> voicesDir;
   NS_NewNativeLocalFile(langPath, true, getter_AddRefs(voicesDir));
 
   nsCOMPtr<nsISimpleEnumerator> dirIterator;
   nsresult rv = voicesDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
 
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -154,88 +154,117 @@ NPClass nsJSObjWrapper::sJSObjWrapperNPC
     nsJSObjWrapper::NP_HasProperty,
     nsJSObjWrapper::NP_GetProperty,
     nsJSObjWrapper::NP_SetProperty,
     nsJSObjWrapper::NP_RemoveProperty,
     nsJSObjWrapper::NP_Enumerate,
     nsJSObjWrapper::NP_Construct
   };
 
-static bool
-NPObjWrapper_AddProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> v);
-
-static bool
-NPObjWrapper_DelProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                         JS::ObjectOpResult &result);
-
-static bool
-NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                         JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result);
-
-static bool
-NPObjWrapper_GetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp);
-
-static bool
-NPObjWrapper_NewEnumerate(JSContext *cx, JS::Handle<JSObject*> obj, JS::AutoIdVector &properties,
-                          bool enumerableOnly);
+class NPObjWrapperProxyHandler : public js::BaseProxyHandler
+{
+  static const char family;
+
+public:
+  static const NPObjWrapperProxyHandler singleton;
+
+  constexpr NPObjWrapperProxyHandler()
+    : BaseProxyHandler(&family)
+  {}
+
+  bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
+                      JS::Handle<JS::PropertyDescriptor> desc,
+                      JS::ObjectOpResult& result) const override {
+    ::JS_ReportErrorASCII(cx, "Trying to add unsupported property on NPObject!");
+    return false;
+  }
+
+  bool getPrototypeIfOrdinary(JSContext* cx, JS::Handle<JSObject*> proxy,
+                              bool* isOrdinary,
+                              JS::MutableHandle<JSObject*> proto) const override {
+    *isOrdinary = true;
+    proto.set(js::GetStaticPrototype(proxy));
+    return true;
+  }
+
+  bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy,
+                    bool *extensible) const override {
+    // Needs to be extensible so nsObjectLoadingContent can mutate our
+    // __proto__.
+    *extensible = true;
+    return true;
+  }
+
+  bool preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy,
+                         JS::ObjectOpResult& result) const override {
+    result.succeed();
+    return true;
+  }
+
+  bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
+                                JS::Handle<jsid> id,
+                                JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
+
+  bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
+                       JS::AutoIdVector& properties) const override;
+
+  bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
+               JS::ObjectOpResult& result) const override;
+
+  bool get(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<JS::Value> receiver,
+           JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
+
+  bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
+           JS::Handle<JS::Value> vp, JS::Handle<JS::Value> receiver, JS::ObjectOpResult& result)
+           const override;
+
+  bool isCallable(JSObject* obj) const override {
+    return true;
+  }
+  bool call(JSContext* cx, JS::Handle<JSObject*> proxy,
+            const JS::CallArgs& args) const override;
+
+  bool isConstructor(JSObject* obj) const override {
+    return true;
+  }
+  bool construct(JSContext* cx, JS::Handle<JSObject*> proxy,
+                 const JS::CallArgs& args) const override;
+
+  bool finalizeInBackground(const JS::Value& priv) const override {
+    return false;
+  }
+  void finalize(JSFreeOp* fop, JSObject* proxy) const override;
+};
+
+const char NPObjWrapperProxyHandler::family = 0;
+const NPObjWrapperProxyHandler NPObjWrapperProxyHandler::singleton;
 
 static bool
 NPObjWrapper_Resolve(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                     bool *resolvedp);
-
-static void
-NPObjWrapper_Finalize(js::FreeOp *fop, JSObject *obj);
+                     bool* resolved, JS::MutableHandle<JSObject*> method);
 
 static void
 NPObjWrapper_ObjectMoved(JSObject *obj, const JSObject *old);
 
 static bool
-NPObjWrapper_Call(JSContext *cx, unsigned argc, JS::Value *vp);
-
-static bool
-NPObjWrapper_Construct(JSContext *cx, unsigned argc, JS::Value *vp);
-
-static bool
 NPObjWrapper_toPrimitive(JSContext *cx, unsigned argc, JS::Value *vp);
 
 static bool
 CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj,
                      JS::Handle<jsid> id,  NPVariant* getPropertyResult,
                      JS::MutableHandle<JS::Value> vp);
 
-const static js::ClassOps sNPObjectJSWrapperClassOps = {
-    NPObjWrapper_AddProperty,
-    NPObjWrapper_DelProperty,
-    NPObjWrapper_GetProperty,
-    NPObjWrapper_SetProperty,
-    nullptr,                    /* enumerate */
-    NPObjWrapper_NewEnumerate,
-    NPObjWrapper_Resolve,
-    nullptr,                    /* mayResolve */
-    NPObjWrapper_Finalize,
-    NPObjWrapper_Call,
-    nullptr,                    /* hasInstance */
-    NPObjWrapper_Construct,
-    nullptr,                    /* trace */
-};
-
-const static js::ClassExtension sNPObjectJSWrapperClassExtension = {
-    nullptr,                    /* weakmapKeyDelegateOp */
+static const js::ClassExtension sNPObjWrapperProxyClassExtension = PROXY_MAKE_EXT(
     NPObjWrapper_ObjectMoved
-};
-
-const static js::Class sNPObjectJSWrapperClass = {
+);
+
+const js::Class sNPObjWrapperProxyClass = PROXY_CLASS_WITH_EXT(
     NPRUNTIME_JSCLASS_NAME,
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_FOREGROUND_FINALIZE,
-    &sNPObjectJSWrapperClassOps,
-    JS_NULL_CLASS_SPEC,
-    &sNPObjectJSWrapperClassExtension,
-    JS_NULL_OBJECT_OPS
-};
+    JSCLASS_HAS_RESERVED_SLOTS(1),
+    &sNPObjWrapperProxyClassExtension);
 
 typedef struct NPObjectMemberPrivate {
     JS::Heap<JSObject *> npobjWrapper;
     JS::Heap<JS::Value> fieldValue;
     JS::Heap<jsid> methodName;
     NPP   npp;
 } NPObjectMemberPrivate;
 
@@ -1079,17 +1108,17 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS
   // No need to enter the right compartment here as we only get the
   // class and private from the JSObject, neither of which cares about
   // compartments.
 
   if (nsNPObjWrapper::IsWrapper(obj)) {
     // obj is one of our own, its private data is the NPObject we're
     // looking for.
 
-    NPObject *npobj = (NPObject *)::JS_GetPrivate(obj);
+    NPObject *npobj = (NPObject *)js::GetProxyPrivate(obj).toPrivate();
 
     // If the private is null, that means that the object has already been torn
     // down, possible because the owning plugin was destroyed (there can be
     // multiple plugins, so the fact that it was destroyed does not prevent one
     // of its dead JS objects from being passed to another plugin). There's not
     // much use in wrapping such a dead object, so we just return null, causing
     // us to throw.
     if (!npobj)
@@ -1166,76 +1195,55 @@ GetNPObjectWrapper(JSContext *cx, JSObje
 static NPObject *
 GetNPObject(JSContext *cx, JSObject *obj)
 {
   obj = GetNPObjectWrapper(cx, obj, /* wrapResult = */ false);
   if (!obj) {
     return nullptr;
   }
 
-  return (NPObject *)::JS_GetPrivate(obj);
+  return (NPObject *)js::GetProxyPrivate(obj).toPrivate();
 }
 
-
-// Does not actually add a property because this is always followed by a
-// SetProperty call.
-static bool
-NPObjWrapper_AddProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::Handle<JS::Value> v)
+static JSObject*
+NPObjWrapper_GetResolvedProps(JSContext* cx, JS::Handle<JSObject*> obj)
 {
-  NPObject *npobj = GetNPObject(cx, obj);
-
-  if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
-      !npobj->_class->hasMethod) {
-    ThrowJSExceptionASCII(cx, "Bad NPObject as private data!");
-
-    return false;
-  }
-
-  if (NPObjectIsOutOfProcessProxy(npobj)) {
-    return true;
-  }
-
-  PluginDestructionGuard pdg(LookupNPP(npobj));
-
-  NPIdentifier identifier = JSIdToNPIdentifier(id);
-  bool hasProperty = npobj->_class->hasProperty(npobj, identifier);
-  if (!ReportExceptionIfPending(cx))
-    return false;
-
-  if (hasProperty)
-    return true;
-
-  // We must permit methods here since JS_DefineUCFunction() will add
-  // the function as a property
-  bool hasMethod = npobj->_class->hasMethod(npobj, identifier);
-  if (!ReportExceptionIfPending(cx))
-    return false;
-
-  if (!hasMethod) {
-    ThrowJSExceptionASCII(cx, "Trying to add unsupported property on NPObject!");
-
-    return false;
-  }
-
-  return true;
+  JS::Value slot = js::GetProxyReservedSlot(obj, 0);
+  if (slot.isObject())
+    return &slot.toObject();
+
+  MOZ_ASSERT(slot.isUndefined());
+
+  JSObject* res = JS_NewObject(cx, nullptr);
+  if (!res)
+    return nullptr;
+
+  SetProxyReservedSlot(obj, 0, JS::ObjectValue(*res));
+  return res;
 }
 
-static bool
-NPObjWrapper_DelProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                         JS::ObjectOpResult &result)
+bool
+NPObjWrapperProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
+                                  JS::ObjectOpResult& result) const
 {
-  NPObject *npobj = GetNPObject(cx, obj);
+  NPObject *npobj = GetNPObject(cx, proxy);
 
   if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
       !npobj->_class->removeProperty) {
     ThrowJSExceptionASCII(cx, "Bad NPObject as private data!");
 
     return false;
   }
 
+  JS::Rooted<JSObject*> resolvedProps(cx, NPObjWrapper_GetResolvedProps(cx, proxy));
+  if (!resolvedProps)
+    return false;
+  if (!JS_DeletePropertyById(cx, resolvedProps, id, result))
+    return false;
+
   PluginDestructionGuard pdg(LookupNPP(npobj));
 
   NPIdentifier identifier = JSIdToNPIdentifier(id);
 
   if (!NPObjectIsOutOfProcessProxy(npobj)) {
     bool hasProperty = npobj->_class->hasProperty(npobj, identifier);
     if (!ReportExceptionIfPending(cx))
       return false;
@@ -1249,21 +1257,22 @@ NPObjWrapper_DelProperty(JSContext *cx, 
   // obj.prop` returning false: in strict mode it becomes a TypeError. Legacy
   // code---nothing else that uses the JSAPI works this way anymore.
   bool succeeded = npobj->_class->removeProperty(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return false;
   return succeeded ? result.succeed() : result.failCantDelete();
 }
 
-static bool
-NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                         JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result)
+bool
+NPObjWrapperProxyHandler::set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
+                              JS::Handle<JS::Value> vp, JS::Handle<JS::Value> receiver,
+                              JS::ObjectOpResult& result) const
 {
-  NPObject *npobj = GetNPObject(cx, obj);
+  NPObject *npobj = GetNPObject(cx, proxy);
 
   if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
       !npobj->_class->setProperty) {
     ThrowJSExceptionASCII(cx, "Bad NPObject as private data!");
 
     return false;
   }
 
@@ -1272,16 +1281,28 @@ NPObjWrapper_SetProperty(JSContext *cx, 
   NPP npp = LookupNPP(npobj);
 
   if (!npp) {
     ThrowJSExceptionASCII(cx, "No NPP found for NPObject!");
 
     return false;
   }
 
+  {
+    bool resolved = false;
+    JS::Rooted<JSObject*> method(cx);
+    if (!NPObjWrapper_Resolve(cx, proxy, id, &resolved, &method))
+      return false;
+    if (!resolved) {
+      // We don't have a property/method with this id. Forward to the prototype
+      // chain.
+      return js::BaseProxyHandler::set(cx, proxy, id, vp, receiver, result);
+    }
+  }
+
   PluginDestructionGuard pdg(npp);
 
   NPIdentifier identifier = JSIdToNPIdentifier(id);
 
   if (!NPObjectIsOutOfProcessProxy(npobj)) {
     bool hasProperty = npobj->_class->hasProperty(npobj, identifier);
     if (!ReportExceptionIfPending(cx))
       return false;
@@ -1310,19 +1331,23 @@ NPObjWrapper_SetProperty(JSContext *cx, 
 
     return false;
   }
 
   return result.succeed();
 }
 
 static bool
-NPObjWrapper_GetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp)
+CallNPMethod(JSContext *cx, unsigned argc, JS::Value *vp);
+
+bool
+NPObjWrapperProxyHandler::get(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<JS::Value> receiver,
+                              JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const
 {
-  NPObject *npobj = GetNPObject(cx, obj);
+  NPObject *npobj = GetNPObject(cx, proxy);
 
   if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
       !npobj->_class->hasMethod || !npobj->_class->getProperty) {
     ThrowJSExceptionASCII(cx, "Bad NPObject as private data!");
 
     return false;
   }
 
@@ -1344,29 +1369,44 @@ NPObjWrapper_GetProperty(JSContext *cx, 
       if (!tag) {
         return false;
       }
 
       vp.setString(tag);
       return true;
     }
 
-    vp.setUndefined();
-    return true;
+    return js::BaseProxyHandler::get(cx, proxy, receiver, id, vp);
   }
 
   // Find out what plugin (NPP) is the owner of the object we're
   // manipulating, and make it own any JSObject wrappers created here.
   NPP npp = LookupNPP(npobj);
   if (!npp) {
     ThrowJSExceptionASCII(cx, "No NPP found for NPObject!");
 
     return false;
   }
 
+  {
+    bool resolved = false;
+    JS::Rooted<JSObject*> method(cx);
+    if (!NPObjWrapper_Resolve(cx, proxy, id, &resolved, &method))
+      return false;
+    if (method) {
+      vp.setObject(*method);
+      return true;
+    }
+    if (!resolved) {
+      // We don't have a property/method with this id. Forward to the prototype
+      // chain.
+      return js::BaseProxyHandler::get(cx, proxy, receiver, id, vp);
+    }
+  }
+
   PluginDestructionGuard pdg(npp);
 
   bool hasProperty, hasMethod;
 
   NPVariant npv;
   VOID_TO_NPVARIANT(npv);
 
   NPIdentifier identifier = JSIdToNPIdentifier(id);
@@ -1386,52 +1426,54 @@ NPObjWrapper_GetProperty(JSContext *cx, 
       if (success)
         _releasevariantvalue(&npv);
       return false;
     }
 
     if (success) {
       // We return NPObject Member class here to support ambiguous members.
       if (hasProperty && hasMethod)
-        return CreateNPObjectMember(npp, cx, obj, npobj, id, &npv, vp);
+        return CreateNPObjectMember(npp, cx, proxy, npobj, id, &npv, vp);
 
       if (hasProperty) {
         vp.set(NPVariantToJSVal(npp, cx, &npv));
         _releasevariantvalue(&npv);
 
         if (!ReportExceptionIfPending(cx))
           return false;
+        return true;
       }
     }
-    return true;
+    return js::BaseProxyHandler::get(cx, proxy, receiver, id, vp);
   }
 
   hasProperty = npobj->_class->hasProperty(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return false;
 
   hasMethod = npobj->_class->hasMethod(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return false;
 
   // We return NPObject Member class here to support ambiguous members.
   if (hasProperty && hasMethod)
-    return CreateNPObjectMember(npp, cx, obj, npobj, id, nullptr, vp);
+    return CreateNPObjectMember(npp, cx, proxy, npobj, id, nullptr, vp);
 
   if (hasProperty) {
     if (npobj->_class->getProperty(npobj, identifier, &npv))
       vp.set(NPVariantToJSVal(npp, cx, &npv));
 
     _releasevariantvalue(&npv);
 
     if (!ReportExceptionIfPending(cx))
       return false;
+    return true;
   }
 
-  return true;
+  return js::BaseProxyHandler::get(cx, proxy, receiver, id, vp);
 }
 
 static bool
 CallNPMethodInternal(JSContext *cx, JS::Handle<JSObject*> obj, unsigned argc,
                      JS::Value *argv, JS::Value *rval, bool ctorCall)
 {
   NPObject *npobj = GetNPObject(cx, obj);
 
@@ -1563,21 +1605,46 @@ CallNPMethod(JSContext *cx, unsigned arg
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   JS::Rooted<JSObject*> obj(cx, JS_THIS_OBJECT(cx, vp));
   if (!obj)
       return false;
 
   return CallNPMethodInternal(cx, obj, args.length(), args.array(), vp, false);
 }
 
-static bool
-NPObjWrapper_NewEnumerate(JSContext *cx, JS::Handle<JSObject*> obj,
-                          JS::AutoIdVector &properties, bool enumerableOnly)
+bool
+NPObjWrapperProxyHandler::getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
+                                                   JS::Handle<jsid> id,
+                                                   JS::MutableHandle<JS::PropertyDescriptor> desc) const
 {
-  NPObject *npobj = GetNPObject(cx, obj);
+  bool resolved = false;
+  JS::Rooted<JSObject*> method(cx);
+  if (!NPObjWrapper_Resolve(cx, proxy, id, &resolved, &method))
+    return false;
+  if (!resolved) {
+    // No such property.
+    desc.object().set(nullptr);
+    return true;
+  }
+
+  // This returns a descriptor with |null| JS value if this is a plugin
+  // property (as opposed to a method). That should be fine, hopefully, as the
+  // previous code had very inconsistent behavior in this case as well. The main
+  // reason for returning a descriptor here is to make property enumeration work
+  // correctly (it will call getOwnPropertyDescriptor to check enumerability).
+  JS::Rooted<JS::Value> val(cx, JS::ObjectOrNullValue(method));
+  desc.initFields(proxy, val, JSPROP_ENUMERATE, nullptr, nullptr);
+  return true;
+}
+
+bool
+NPObjWrapperProxyHandler::ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
+                                          JS::AutoIdVector& properties) const
+{
+  NPObject *npobj = GetNPObject(cx, proxy);
   if (!npobj || !npobj->_class) {
     ThrowJSExceptionASCII(cx, "Bad NPObject as private data!");
     return false;
   }
 
   PluginDestructionGuard pdg(LookupNPP(npobj));
 
   if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) ||
@@ -1605,88 +1672,113 @@ NPObjWrapper_NewEnumerate(JSContext *cx,
     id = NPIdentifierToJSId(identifiers[i]);
     properties.infallibleAppend(id);
   }
 
   free(identifiers);
   return true;
 }
 
+// This function is very similar to a resolve hook for native objects. Instead
+// of defining properties on the object, it defines them on a resolvedProps
+// object (a plain JS object that's never exposed to script) that's stored in
+// the NPObjWrapper proxy's reserved slot. The behavior is as follows:
+//
+// - *resolvedp is set to true iff the plugin object has a property or method
+//   (or both) with this id.
+//
+// - If the plugin object has a *property* with this id, the caller is
+//   responsible for getting/setting its value. In this case we assign |null|
+//   to resolvedProps[id] so we don't have to call hasProperty each time.
+//
+// - If the plugin object has a *method* with this id, we create a JSFunction to
+//   call it and assign it to resolvedProps[id]. This function is also assigned
+//   to the |method| outparam so callers can return it directly if we're doing a
+//   |get|.
 static bool
 NPObjWrapper_Resolve(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                     bool *resolvedp)
+                     bool* resolvedp, JS::MutableHandle<JSObject*> method)
 {
   if (JSID_IS_SYMBOL(id))
     return true;
 
   AUTO_PROFILER_LABEL("NPObjWrapper_Resolve", JS);
 
   NPObject *npobj = GetNPObject(cx, obj);
 
   if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
       !npobj->_class->hasMethod) {
     ThrowJSExceptionASCII(cx, "Bad NPObject as private data!");
 
     return false;
   }
 
+  JS::Rooted<JSObject*> resolvedProps(cx, NPObjWrapper_GetResolvedProps(cx, obj));
+  if (!resolvedProps)
+    return false;
+  JS::Rooted<JS::Value> res(cx);
+  if (!JS_GetPropertyById(cx, resolvedProps, id, &res))
+    return false;
+  if (res.isObjectOrNull()) {
+    method.set(res.toObjectOrNull());
+    *resolvedp = true;
+    return true;
+  }
+
   PluginDestructionGuard pdg(LookupNPP(npobj));
 
   NPIdentifier identifier = JSIdToNPIdentifier(id);
 
   bool hasProperty = npobj->_class->hasProperty(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return false;
 
   if (hasProperty) {
-    NS_ASSERTION(JSID_IS_STRING(id) || JSID_IS_INT(id),
-                 "id must be either string or int!\n");
-    if (!::JS_DefinePropertyById(cx, obj, id, JS::UndefinedHandleValue,
-                                 JSPROP_ENUMERATE | JSPROP_SHARED)) {
-        return false;
-    }
-
+    if (!JS_SetPropertyById(cx, resolvedProps, id, JS::NullHandleValue))
+      return false;
     *resolvedp = true;
 
     return true;
   }
 
   bool hasMethod = npobj->_class->hasMethod(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return false;
 
   if (hasMethod) {
     NS_ASSERTION(JSID_IS_STRING(id) || JSID_IS_INT(id),
                  "id must be either string or int!\n");
 
-    JSFunction *fnc = ::JS_DefineFunctionById(cx, obj, id, CallNPMethod, 0,
+    JSFunction *fnc = ::JS_DefineFunctionById(cx, resolvedProps, id, CallNPMethod, 0,
                                               JSPROP_ENUMERATE);
-
+    if (!fnc)
+      return false;
+
+    method.set(JS_GetFunctionObject(fnc));
     *resolvedp = true;
-
-    return fnc != nullptr;
+    return true;
   }
 
   // no property or method
   return true;
 }
 
-static void
-NPObjWrapper_Finalize(js::FreeOp *fop, JSObject *obj)
+void
+NPObjWrapperProxyHandler::finalize(JSFreeOp* fop, JSObject* proxy) const
 {
   JS::AutoAssertGCCallback inCallback;
 
-  NPObject *npobj = (NPObject *)::JS_GetPrivate(obj);
+  NPObject *npobj = (NPObject *)js::GetProxyPrivate(proxy).toPrivate();
   if (npobj) {
     if (sNPObjWrappers) {
       // If the sNPObjWrappers map contains an entry that refers to this
       // wrapper, remove it.
       auto entry =
         static_cast<NPObjWrapperHashEntry*>(sNPObjWrappers->Search(npobj));
-      if (entry && entry->mJSObj == obj) {
+      if (entry && entry->mJSObj == proxy) {
         sNPObjWrappers->Remove(npobj);
       }
     }
   }
 
   if (!sDelayedReleases)
     sDelayedReleases = new nsTArray<NPObject*>;
   sDelayedReleases->AppendElement(npobj);
@@ -1697,45 +1789,45 @@ NPObjWrapper_ObjectMoved(JSObject *obj, 
 {
   // The wrapper JSObject has been moved, so we need to update the entry in the
   // sNPObjWrappers hash table, if present.
 
   if (!sNPObjWrappers) {
     return;
   }
 
-  NPObject *npobj = (NPObject *)::JS_GetPrivate(obj);
+  NPObject *npobj = (NPObject *)js::GetProxyPrivate(obj).toPrivate();
   if (!npobj) {
     return;
   }
 
   // Calling PLDHashTable::Search() will not result in GC.
   JS::AutoSuppressGCAnalysis nogc;
 
   auto entry =
     static_cast<NPObjWrapperHashEntry*>(sNPObjWrappers->Search(npobj));
   MOZ_ASSERT(entry && entry->mJSObj);
   MOZ_ASSERT(entry->mJSObj == old);
   entry->mJSObj = obj;
 }
 
-static bool
-NPObjWrapper_Call(JSContext *cx, unsigned argc, JS::Value *vp)
+bool
+NPObjWrapperProxyHandler::call(JSContext* cx, JS::Handle<JSObject*> proxy,
+                               const JS::CallArgs& args) const
 {
-  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
-  JS::Rooted<JSObject*> obj(cx, &args.callee());
-  return CallNPMethodInternal(cx, obj, args.length(), args.array(), vp, false);
+  return CallNPMethodInternal(cx, proxy, args.length(), args.array(),
+                              args.rval().address(), false);
 }
 
-static bool
-NPObjWrapper_Construct(JSContext *cx, unsigned argc, JS::Value *vp)
+bool
+NPObjWrapperProxyHandler::construct(JSContext* cx, JS::Handle<JSObject*> proxy,
+                                    const JS::CallArgs& args) const
 {
-  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
-  JS::Rooted<JSObject*> obj(cx, &args.callee());
-  return CallNPMethodInternal(cx, obj, args.length(), args.array(), vp, true);
+  return CallNPMethodInternal(cx, proxy, args.length(), args.array(),
+                              args.rval().address(), true);
 }
 
 static bool
 NPObjWrapper_toPrimitive(JSContext *cx, unsigned argc, JS::Value *vp)
 {
   // Plugins do not simply use the default OrdinaryToPrimitive behavior,
   // because that behavior involves calling toString or valueOf on objects
   // which weren't designed to accommodate this.  Usually this wouldn't be a
@@ -1768,17 +1860,17 @@ NPObjWrapper_toPrimitive(JSContext *cx, 
                             JSMSG_CANT_CONVERT_TO,
                             JS_GetClass(obj)->name, "primitive type");
   return false;
 }
 
 bool
 nsNPObjWrapper::IsWrapper(JSObject *obj)
 {
-  return js::GetObjectClass(obj) == &sNPObjectJSWrapperClass;
+  return js::GetObjectClass(obj) == &sNPObjWrapperProxyClass;
 }
 
 // An NPObject is going away, make sure we null out the JS object's
 // private data in case this is an NPObject that came from a plugin
 // and it's destroyed prematurely.
 
 // static
 void
@@ -1802,17 +1894,17 @@ nsNPObjWrapper::OnDestroy(NPObject *npob
 
   auto entry =
     static_cast<NPObjWrapperHashEntry*>(sNPObjWrappers->Search(npobj));
 
   if (entry && entry->mJSObj) {
     // Found a live NPObject wrapper, null out its JSObjects' private
     // data.
 
-    ::JS_SetPrivate(entry->mJSObj, nullptr);
+    js::SetProxyPrivate(entry->mJSObj, JS::PrivateValue(nullptr));
 
     // Remove the npobj from the hash now that it went away.
     sNPObjWrappers->RawRemove(entry);
 
     // The finalize hook will call OnWrapperDestroyed().
   }
 }
 
@@ -1883,17 +1975,21 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
 
   entry->mNPObj = npobj;
   entry->mNpp = npp;
 
   uint32_t generation = sNPObjWrappers->Generation();
 
   // No existing JSObject, create one.
 
-  JS::Rooted<JSObject*> obj(cx, ::JS_NewObject(cx, js::Jsvalify(&sNPObjectJSWrapperClass)));
+  JS::RootedValue priv(cx, JS::PrivateValue(nullptr));
+  js::ProxyOptions options;
+  options.setClass(&sNPObjWrapperProxyClass);
+  JS::Rooted<JSObject*> obj(cx, js::NewProxyObject(cx, &NPObjWrapperProxyHandler::singleton,
+                                                   priv, nullptr, options));
 
   if (generation != sNPObjWrappers->Generation()) {
       // Reload entry if the JS_NewObject call caused a GC and reallocated
       // the table (see bug 445229). This is guaranteed to succeed.
 
       entry =
          static_cast<NPObjWrapperHashEntry*>(sNPObjWrappers->Search(npobj));
       NS_ASSERTION(entry, "Hashtable didn't find what we just added?");
@@ -1906,17 +2002,17 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
 
     return nullptr;
   }
 
   OnWrapperCreated();
 
   entry->mJSObj = obj;
 
-  ::JS_SetPrivate(obj, npobj);
+  js::SetProxyPrivate(obj, JS::PrivateValue(npobj));
 
   // The new JSObject now holds on to npobj
   _retainobject(npobj);
 
   return obj;
 }
 
 // static
@@ -1974,17 +2070,17 @@ nsJSNPRuntime::OnPluginDestroy(NPP npp)
         // Force deallocation of plugin objects since the plugin they came
         // from is being torn down.
         if (npobj->_class && npobj->_class->deallocate) {
           npobj->_class->deallocate(npobj);
         } else {
           free(npobj);
         }
 
-        ::JS_SetPrivate(entry->mJSObj, nullptr);
+        js::SetProxyPrivate(entry->mJSObj, JS::PrivateValue(nullptr));
 
         sNPObjWrappers = tmp;
 
         if (sDelayedReleases && sDelayedReleases->RemoveElement(npobj)) {
           OnWrapperDestroyed();
         }
 
         i.Remove();
--- a/dom/webidl/WebExtensionPolicy.webidl
+++ b/dom/webidl/WebExtensionPolicy.webidl
@@ -30,16 +30,22 @@ interface WebExtensionPolicy {
   /**
    * The file: or jar: URL to use for the base of the extension's
    * moz-extension: URL root.
    */
   [Constant]
   readonly attribute ByteString baseURL;
 
   /**
+   * The extension's user-visible name.
+   */
+  [Constant]
+  readonly attribute DOMString name;
+
+  /**
    * The content security policy string to apply to all pages loaded from the
    * extension's moz-extension: protocol.
    */
   [Constant]
   readonly attribute DOMString contentSecurityPolicy;
 
 
   /**
@@ -137,16 +143,18 @@ interface WebExtensionPolicy {
 
 dictionary WebExtensionInit {
   required DOMString id;
 
   required ByteString mozExtensionHostname;
 
   required DOMString baseURL;
 
+  DOMString name = "";
+
   required WebExtensionLocalizeCallback localizeCallback;
 
   required MatchPatternSet allowedOrigins;
 
   sequence<DOMString> permissions = [];
 
   sequence<MatchGlob> webAccessibleResources = [];
 
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -348,17 +348,17 @@ partial interface Window {
   [ChromeOnly, Throws]
   readonly attribute WindowRoot? windowRoot;
 };
 
 Window implements TouchEventHandlers;
 
 Window implements OnErrorEventHandlerForWindow;
 
-#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
+#if defined(MOZ_WIDGET_ANDROID)
 // https://compat.spec.whatwg.org/#windoworientation-interface
 partial interface Window {
   [NeedsCallerType]
   readonly attribute short orientation;
            attribute EventHandler onorientationchange;
 };
 #endif
 
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -301,17 +301,18 @@ LoadContextOptions(const char* aPrefName
     return;
   }
 #endif
 
   // Context options.
   JS::ContextOptions contextOptions;
   contextOptions.setAsmJS(GetWorkerPref<bool>(NS_LITERAL_CSTRING("asmjs")))
                 .setWasm(GetWorkerPref<bool>(NS_LITERAL_CSTRING("wasm")))
-                .setWasmAlwaysBaseline(GetWorkerPref<bool>(NS_LITERAL_CSTRING("wasm_baselinejit")))
+                .setWasmBaseline(GetWorkerPref<bool>(NS_LITERAL_CSTRING("wasm_baselinejit")))
+                .setWasmIon(GetWorkerPref<bool>(NS_LITERAL_CSTRING("wasm_ionjit")))
                 .setThrowOnAsmJSValidationFailure(GetWorkerPref<bool>(
                       NS_LITERAL_CSTRING("throw_on_asmjs_validation_failure")))
                 .setBaseline(GetWorkerPref<bool>(NS_LITERAL_CSTRING("baselinejit")))
                 .setIon(GetWorkerPref<bool>(NS_LITERAL_CSTRING("ion")))
                 .setNativeRegExp(GetWorkerPref<bool>(NS_LITERAL_CSTRING("native_regexp")))
                 .setAsyncStack(GetWorkerPref<bool>(NS_LITERAL_CSTRING("asyncstack")))
                 .setWerror(GetWorkerPref<bool>(NS_LITERAL_CSTRING("werror")))
 #ifdef FUZZING
--- a/dom/xhr/tests/mochitest.ini
+++ b/dom/xhr/tests/mochitest.ini
@@ -99,17 +99,17 @@ skip-if = toolkit == 'android'
 skip-if = buildapp == 'b2g' # Requires webgl support
 [test_XHR_parameters.html]
 skip-if = buildapp == 'b2g' # b2g(86 total, 4 failing - testing mozAnon - got false, expected true) b2g-debug(86 total, 4 failing - testing mozAnon - got false, expected true) b2g-desktop(86 total, 4 failing - testing mozAnon - got false, expected true)
 [test_xhr_progressevents.html]
 skip-if = toolkit == 'android'
 [test_xhr_send.html]
 [test_xhr_send_readystate.html]
 [test_XHR_system.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(12 total, 2 failing - .mozSystem == true - got false, expected true + ) b2g-desktop(12 total, 2 failing - .mozSystem == true - got false, expected true + )
+skip-if = (buildapp == 'b2g') # b2g-debug(12 total, 2 failing - .mozSystem == true - got false, expected true + ) b2g-desktop(12 total, 2 failing - .mozSystem == true - got false, expected true + )
 [test_XHR_timeout.html]
 skip-if = buildapp == 'b2g' || (android_version == '18' && debug) # b2g(flaky on B2G, bug 960743) b2g-debug(flaky on B2G, bug 960743) b2g-desktop(flaky on B2G, bug 960743)
 support-files = test_XHR_timeout.js
 [test_xhr_withCredentials.html]
 [test_XHRDocURI.html]
 [test_XHRResponseURL.html]
 [test_XHRSendData.html]
 [test_sync_xhr_document_write_with_iframe.html]
--- a/dom/xul/templates/nsXULContentBuilder.cpp
+++ b/dom/xul/templates/nsXULContentBuilder.cpp
@@ -595,18 +595,17 @@ nsXULContentBuilder::BuildContentFromTem
         }
         else if (tag == nsGkAtoms::textnode &&
                  nameSpaceID == kNameSpaceID_XUL) {
             // <xul:text value="..."> is replaced by text of the
             // actual value of the 'rdf:resource' attribute for the
             // given node.
             // SynchronizeUsingTemplate contains code used to update textnodes,
             // so make sure to modify both when changing this
-            char16_t attrbuf[128];
-            nsFixedString attrValue(attrbuf, ArrayLength(attrbuf), 0);
+            nsAutoString attrValue;
             tmplKid->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue);
             if (!attrValue.IsEmpty()) {
                 nsAutoString value;
                 rv = SubstituteText(aChild, attrValue, value);
                 if (NS_FAILED(rv)) return rv;
 
                 RefPtr<nsTextNode> content =
                   new nsTextNode(mRoot->NodeInfo()->NodeInfoManager());
@@ -732,21 +731,17 @@ nsXULContentBuilder::CopyAttributesToEle
         const nsAttrName* name = aTemplateNode->GetAttrNameAt(attr);
         int32_t attribNameSpaceID = name->NamespaceID();
         // Hold a strong reference here so that the atom doesn't go away
         // during UnsetAttr.
         nsCOMPtr<nsIAtom> attribName = name->LocalName();
 
         // XXXndeakin ignore namespaces until bug 321182 is fixed
         if (attribName != nsGkAtoms::id && attribName != nsGkAtoms::uri) {
-            // Create a buffer here, because there's a chance that an
-            // attribute in the template is going to be an RDF URI, which is
-            // usually longish.
-            char16_t attrbuf[128];
-            nsFixedString attribValue(attrbuf, ArrayLength(attrbuf), 0);
+            nsAutoString attribValue;
             aTemplateNode->GetAttr(attribNameSpaceID, attribName, attribValue);
             if (!attribValue.IsEmpty()) {
                 nsAutoString value;
                 rv = SubstituteText(aResult, attribValue, value);
                 if (NS_FAILED(rv))
                     return rv;
 
                 // if the string is empty after substitutions, remove the
@@ -873,18 +868,17 @@ nsXULContentBuilder::SynchronizeUsingTem
         nsIContent *realKid = aRealElement->GetChildAt(loop);
         if (! realKid)
             break;
 
         // check for text nodes and update them accordingly.
         // This code is similar to that in BuildContentFromTemplate
         if (tmplKid->NodeInfo()->Equals(nsGkAtoms::textnode,
                                         kNameSpaceID_XUL)) {
-            char16_t attrbuf[128];
-            nsFixedString attrValue(attrbuf, ArrayLength(attrbuf), 0);
+            nsAutoString attrValue;
             tmplKid->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue);
             if (!attrValue.IsEmpty()) {
                 nsAutoString value;
                 rv = SubstituteText(aResult, attrValue, value);
                 if (NS_FAILED(rv)) return rv;
                 realKid->SetText(value, true);
             }
         }
--- a/dom/xul/templates/nsXULContentUtils.cpp
+++ b/dom/xul/templates/nsXULContentUtils.cpp
@@ -236,18 +236,17 @@ nsXULContentUtils::GetResource(int32_t a
 
     // XXX should we allow nodes with no namespace???
     //NS_PRECONDITION(aNameSpaceID != kNameSpaceID_Unknown, "no namespace");
     //if (aNameSpaceID == kNameSpaceID_Unknown)
     //    return NS_ERROR_UNEXPECTED;
 
     nsresult rv;
 
-    char16_t buf[256];
-    nsFixedString uri(buf, ArrayLength(buf), 0);
+    nsAutoStringN<256> uri;
     if (aNameSpaceID != kNameSpaceID_Unknown && aNameSpaceID != kNameSpaceID_None) {
         rv = nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, uri);
         // XXX ignore failure; treat as "no namespace"
     }
 
     // XXX check to see if we need to insert a '/' or a '#'. Oy.
     if (!uri.IsEmpty()  && uri.Last() != '#' && uri.Last() != '/' && aAttribute.First() != '#')
         uri.Append(char16_t('#'));
--- a/editor/libeditor/SelectionState.cpp
+++ b/editor/libeditor/SelectionState.cpp
@@ -642,16 +642,20 @@ RangeUpdater::DidMoveNode(nsINode* aOldP
 RangeItem::RangeItem()
 {
 }
 
 RangeItem::~RangeItem()
 {
 }
 
+NS_IMPL_CYCLE_COLLECTION(RangeItem, mStartContainer, mEndContainer)
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(RangeItem, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(RangeItem, Release)
+
 void
 RangeItem::StoreRange(nsRange* aRange)
 {
   MOZ_ASSERT(aRange);
   mStartContainer = aRange->GetStartContainer();
   mStartOffset = aRange->StartOffset();
   mEndContainer = aRange->GetEndContainer();
   mEndOffset = aRange->EndOffset();
@@ -663,23 +667,9 @@ RangeItem::GetRange()
   RefPtr<nsRange> range = new nsRange(mStartContainer);
   if (NS_FAILED(range->SetStartAndEnd(mStartContainer, mStartOffset,
                                       mEndContainer, mEndOffset))) {
     return nullptr;
   }
   return range.forget();
 }
 
-void
-RangeItem::Unlink()
-{
-  ImplCycleCollectionUnlink(mStartContainer);
-  ImplCycleCollectionUnlink(mEndContainer);
-}
-
-void
-RangeItem::Traverse(nsCycleCollectionTraversalCallback& aCallback, uint32_t aFlags)
-{
-  CycleCollectionNoteChild(aCallback, mStartContainer.get(), "mStartContainer", aFlags);
-  CycleCollectionNoteChild(aCallback, mEndContainer.get(), "mEndContainer", aFlags);
-}
-
 } // namespace mozilla
--- a/editor/libeditor/SelectionState.h
+++ b/editor/libeditor/SelectionState.h
@@ -32,57 +32,25 @@ struct RangeItem final
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~RangeItem();
 
 public:
   void StoreRange(nsRange* aRange);
   already_AddRefed<nsRange> GetRange();
 
-  NS_INLINE_DECL_REFCOUNTING(RangeItem)
-
-  void Unlink();
-  void Traverse(nsCycleCollectionTraversalCallback& aCallback, uint32_t aFlags);
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(RangeItem)
+  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(RangeItem)
 
   nsCOMPtr<nsINode> mStartContainer;
   int32_t mStartOffset;
   nsCOMPtr<nsINode> mEndContainer;
   int32_t mEndOffset;
 };
 
-inline void
-ImplCycleCollectionUnlink(RangeItem& aItem)
-{
-  aItem.Unlink();
-}
-
-inline void
-ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            RangeItem& aItem,
-                            const char* aName,
-                            uint32_t aFlags = 0)
-{
-  aItem.Traverse(aCallback, aFlags);
-}
-
-inline void
-ImplCycleCollectionUnlink(RefPtr<RangeItem>& aItem)
-{
-  aItem->Unlink();
-}
-
-inline void
-ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            RefPtr<RangeItem>& aItem,
-                            const char* aName,
-                            uint32_t aFlags = 0)
-{
-  aItem->Traverse(aCallback, aFlags);
-}
-
 /**
  * mozilla::SelectionState
  *
  * Class for recording selection info.  Stores selection as collection of
  * { {startnode, startoffset} , {endnode, endoffset} } tuples.  Can't store
  * ranges since dom gravity will possibly change the ranges.
  */
 
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -367,21 +367,20 @@ TextEditRules::DocumentIsEmpty()
   if (NS_WARN_IF(!mTextEditor)) {
     return true;
   }
   Element* rootElement = mTextEditor->GetRoot();
   if (!rootElement) {
     return true;
   }
 
-  uint32_t childCount = rootElement->GetChildCount();
-  for (uint32_t i = 0; i < childCount; i++) {
-    nsINode* node = rootElement->GetChildAt(i);
-    if (!EditorBase::IsTextNode(node) ||
-        node->Length()) {
+  for (nsIContent* child = rootElement->GetFirstChild();
+       child; child = child->GetNextSibling()) {
+    if (!EditorBase::IsTextNode(child) ||
+        child->Length()) {
       return false;
     }
   }
   return true;
 }
 
 void
 TextEditRules::WillInsert(Selection& aSelection, bool* aCancel)
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/file_bug289384-1.html
@@ -0,0 +1,1 @@
+<a href="file_bug289384-2.html">link</a>
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/file_bug289384-2.html
@@ -0,0 +1,1 @@
+<body contenteditable onload='opener.continueTest(window);'>foo bar</body>
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -1,15 +1,17 @@
 [DEFAULT]
 support-files =
   data/cfhtml-chromium.txt
   data/cfhtml-firefox.txt
   data/cfhtml-ie.txt
   data/cfhtml-ooo.txt
   data/cfhtml-nocontext.txt
+  file_bug289384-1.html
+  file_bug289384-2.html
   file_bug549262.html
   file_bug586662.html
   file_bug611182.html
   file_bug611182.sjs
   file_bug635636.xhtml
   file_bug674770-1.html
   file_bug795418-2.sjs
   file_bug915962.html
--- a/editor/libeditor/tests/test_bug289384.html
+++ b/editor/libeditor/tests/test_bug289384.html
@@ -14,17 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 
 addLoadEvent(function() {
-  var win = window.open("data:text/html,<a href=\"data:text/html,<body contenteditable onload='opener.continueTest(window);'>foo bar</body>\">link</a>", "", "test-289384");
+  var win = window.open("file_bug289384-1.html", "", "test-289384");
   win.addEventListener("load", function() {
     win.document.querySelector("a").click();
   }, {once: true});
 });
 
 function continueTest(win) {
   SimpleTest.waitForFocus(function() {
     var doc = win.document;
--- a/extensions/cookie/test/browser.ini
+++ b/extensions/cookie/test/browser.ini
@@ -2,8 +2,9 @@
 
 [browser_test_favicon.js]
 [browser_permmgr_sync.js]
 # The browser_permmgr_sync test tests e10s specific behavior, and runs code
 # paths which would hit the debug only assertion in
 # nsPermissionManager::PermissionKey::CreateFromPrincipal. Because of this, it
 # is only run in e10s opt builds.
 skip-if = debug || !e10s
+[browser_permmgr_viewsrc.js]
new file mode 100644
--- /dev/null
+++ b/extensions/cookie/test/browser_permmgr_viewsrc.js
@@ -0,0 +1,19 @@
+add_task(async function() {
+  // Add a permission for example.com, start a new content process, and make
+  // sure that the permission has been sent down.
+  Services.perms.add(Services.io.newURI("http://example.com"),
+                     "viewsourceTestingPerm",
+                     Services.perms.ALLOW_ACTION);
+
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser,
+                                                        "view-source:http://example.com",
+                                                        /* waitForLoad */ true,
+                                                        /* waitForStateStop */ false,
+                                                        /* forceNewProcess */ true);
+  await ContentTask.spawn(tab.linkedBrowser, null, async function() {
+    is(Services.perms.testPermission(Services.io.newURI("http://example.com"),
+                                     "viewsourceTestingPerm"),
+       Services.perms.ALLOW_ACTION);
+  });
+  await BrowserTestUtils.removeTab(tab);
+});
--- a/gfx/2d/InlineTranslator.cpp
+++ b/gfx/2d/InlineTranslator.cpp
@@ -68,26 +68,30 @@ InlineTranslator::TranslateRecording(cha
   ReadElement(reader, minorRevision);
   if (minorRevision > kMinorRevision) {
     return false;
   }
 
   int32_t eventType;
   ReadElement(reader, eventType);
   while (reader.good()) {
-    UniquePtr<RecordedEvent> recordedEvent(
-      RecordedEvent::LoadEvent(reader,
-      static_cast<RecordedEvent::EventType>(eventType)));
+    bool success = RecordedEvent::DoWithEvent(reader, static_cast<RecordedEvent::EventType>(eventType),
+                               [&] (RecordedEvent *recordedEvent) {
+                                 // Make sure that the whole event was read from the stream successfully.
+                                 if (!reader.good()) {
+                                     return false;
+                                 }
 
-    // Make sure that the whole event was read from the stream successfully.
-    if (!reader.good() || !recordedEvent) {
-      return false;
-    }
+                                 if (!recordedEvent->PlayEvent(this)) {
+                                     return false;
+                                 }
 
-    if (!recordedEvent->PlayEvent(this)) {
+                                 return true;
+                              });
+    if (!success) {
       return false;
     }
 
     ReadElement(reader, eventType);
   }
 
   return true;
 }
--- a/gfx/2d/RecordedEvent.h
+++ b/gfx/2d/RecordedEvent.h
@@ -288,16 +288,21 @@ public:
   virtual ReferencePtr GetDestinedDT() { return nullptr; }
 
   void OutputSimplePatternInfo(const PatternStorage &aStorage, std::stringstream &aOutput) const;
 
   template<class S>
   static RecordedEvent *LoadEvent(S &aStream, EventType aType);
   static RecordedEvent *LoadEventFromStream(std::istream &aStream, EventType aType);
 
+  // An alternative to LoadEvent that avoids a heap allocation for the event.
+  // This accepts a callable `f' that will take a RecordedEvent* as a single parameter
+  template<class S, class F>
+  static bool DoWithEvent(S &aStream, EventType aType, F f);
+
   EventType GetType() { return (EventType)mType; }
 protected:
   friend class DrawEventRecorderPrivate;
   friend class DrawEventRecorderFile;
   friend class DrawEventRecorderMemory;
 
   MOZ_IMPLICIT RecordedEvent(int32_t aType) : mType(aType)
   {}
--- a/gfx/2d/RecordedEventImpl.h
+++ b/gfx/2d/RecordedEventImpl.h
@@ -3118,62 +3118,80 @@ RecordedFilterNodeSetInput::OutputSimple
   }
 
   aStringStream << ")";
 }
 
 #define LOAD_EVENT_TYPE(_typeenum, _class) \
   case _typeenum: return new _class(aStream)
 
+#define FOR_EACH_EVENT(f) \
+    f(DRAWTARGETCREATION, RecordedDrawTargetCreation); \
+    f(DRAWTARGETDESTRUCTION, RecordedDrawTargetDestruction); \
+    f(FILLRECT, RecordedFillRect); \
+    f(STROKERECT, RecordedStrokeRect); \
+    f(STROKELINE, RecordedStrokeLine); \
+    f(CLEARRECT, RecordedClearRect); \
+    f(COPYSURFACE, RecordedCopySurface); \
+    f(SETTRANSFORM, RecordedSetTransform); \
+    f(PUSHCLIPRECT, RecordedPushClipRect); \
+    f(PUSHCLIP, RecordedPushClip); \
+    f(POPCLIP, RecordedPopClip); \
+    f(FILL, RecordedFill); \
+    f(FILLGLYPHS, RecordedFillGlyphs); \
+    f(MASK, RecordedMask); \
+    f(STROKE, RecordedStroke); \
+    f(DRAWSURFACE, RecordedDrawSurface); \
+    f(DRAWSURFACEWITHSHADOW, RecordedDrawSurfaceWithShadow); \
+    f(DRAWFILTER, RecordedDrawFilter); \
+    f(PATHCREATION, RecordedPathCreation); \
+    f(PATHDESTRUCTION, RecordedPathDestruction); \
+    f(SOURCESURFACECREATION, RecordedSourceSurfaceCreation); \
+    f(SOURCESURFACEDESTRUCTION, RecordedSourceSurfaceDestruction); \
+    f(FILTERNODECREATION, RecordedFilterNodeCreation); \
+    f(FILTERNODEDESTRUCTION, RecordedFilterNodeDestruction); \
+    f(GRADIENTSTOPSCREATION, RecordedGradientStopsCreation); \
+    f(GRADIENTSTOPSDESTRUCTION, RecordedGradientStopsDestruction); \
+    f(SNAPSHOT, RecordedSnapshot); \
+    f(SCALEDFONTCREATION, RecordedScaledFontCreation); \
+    f(SCALEDFONTDESTRUCTION, RecordedScaledFontDestruction); \
+    f(MASKSURFACE, RecordedMaskSurface); \
+    f(FILTERNODESETATTRIBUTE, RecordedFilterNodeSetAttribute); \
+    f(FILTERNODESETINPUT, RecordedFilterNodeSetInput); \
+    f(CREATESIMILARDRAWTARGET, RecordedCreateSimilarDrawTarget); \
+    f(FONTDATA, RecordedFontData); \
+    f(FONTDESC, RecordedFontDescriptor); \
+    f(PUSHLAYER, RecordedPushLayer); \
+    f(POPLAYER, RecordedPopLayer); \
+    f(UNSCALEDFONTCREATION, RecordedUnscaledFontCreation); \
+    f(UNSCALEDFONTDESTRUCTION, RecordedUnscaledFontDestruction);
+
 template<class S>
 RecordedEvent *
 RecordedEvent::LoadEvent(S &aStream, EventType aType)
 {
   switch (aType) {
-    LOAD_EVENT_TYPE(DRAWTARGETCREATION, RecordedDrawTargetCreation);
-    LOAD_EVENT_TYPE(DRAWTARGETDESTRUCTION, RecordedDrawTargetDestruction);
-    LOAD_EVENT_TYPE(FILLRECT, RecordedFillRect);
-    LOAD_EVENT_TYPE(STROKERECT, RecordedStrokeRect);
-    LOAD_EVENT_TYPE(STROKELINE, RecordedStrokeLine);
-    LOAD_EVENT_TYPE(CLEARRECT, RecordedClearRect);
-    LOAD_EVENT_TYPE(COPYSURFACE, RecordedCopySurface);
-    LOAD_EVENT_TYPE(SETTRANSFORM, RecordedSetTransform);
-    LOAD_EVENT_TYPE(PUSHCLIPRECT, RecordedPushClipRect);
-    LOAD_EVENT_TYPE(PUSHCLIP, RecordedPushClip);
-    LOAD_EVENT_TYPE(POPCLIP, RecordedPopClip);
-    LOAD_EVENT_TYPE(FILL, RecordedFill);
-    LOAD_EVENT_TYPE(FILLGLYPHS, RecordedFillGlyphs);
-    LOAD_EVENT_TYPE(MASK, RecordedMask);
-    LOAD_EVENT_TYPE(STROKE, RecordedStroke);
-    LOAD_EVENT_TYPE(DRAWSURFACE, RecordedDrawSurface);
-    LOAD_EVENT_TYPE(DRAWSURFACEWITHSHADOW, RecordedDrawSurfaceWithShadow);
-    LOAD_EVENT_TYPE(DRAWFILTER, RecordedDrawFilter);
-    LOAD_EVENT_TYPE(PATHCREATION, RecordedPathCreation);
-    LOAD_EVENT_TYPE(PATHDESTRUCTION, RecordedPathDestruction);
-    LOAD_EVENT_TYPE(SOURCESURFACECREATION, RecordedSourceSurfaceCreation);
-    LOAD_EVENT_TYPE(SOURCESURFACEDESTRUCTION, RecordedSourceSurfaceDestruction);
-    LOAD_EVENT_TYPE(FILTERNODECREATION, RecordedFilterNodeCreation);
-    LOAD_EVENT_TYPE(FILTERNODEDESTRUCTION, RecordedFilterNodeDestruction);
-    LOAD_EVENT_TYPE(GRADIENTSTOPSCREATION, RecordedGradientStopsCreation);
-    LOAD_EVENT_TYPE(GRADIENTSTOPSDESTRUCTION, RecordedGradientStopsDestruction);
-    LOAD_EVENT_TYPE(SNAPSHOT, RecordedSnapshot);
-    LOAD_EVENT_TYPE(SCALEDFONTCREATION, RecordedScaledFontCreation);
-    LOAD_EVENT_TYPE(SCALEDFONTDESTRUCTION, RecordedScaledFontDestruction);
-    LOAD_EVENT_TYPE(MASKSURFACE, RecordedMaskSurface);
-    LOAD_EVENT_TYPE(FILTERNODESETATTRIBUTE, RecordedFilterNodeSetAttribute);
-    LOAD_EVENT_TYPE(FILTERNODESETINPUT, RecordedFilterNodeSetInput);
-    LOAD_EVENT_TYPE(CREATESIMILARDRAWTARGET, RecordedCreateSimilarDrawTarget);
-    LOAD_EVENT_TYPE(FONTDATA, RecordedFontData);
-    LOAD_EVENT_TYPE(FONTDESC, RecordedFontDescriptor);
-    LOAD_EVENT_TYPE(PUSHLAYER, RecordedPushLayer);
-    LOAD_EVENT_TYPE(POPLAYER, RecordedPopLayer);
-    LOAD_EVENT_TYPE(UNSCALEDFONTCREATION, RecordedUnscaledFontCreation);
-    LOAD_EVENT_TYPE(UNSCALEDFONTDESTRUCTION, RecordedUnscaledFontDestruction);
+    FOR_EACH_EVENT(LOAD_EVENT_TYPE)
   default:
     return nullptr;
   }
 }
 
+#define DO_WITH_EVENT_TYPE(_typeenum, _class) \
+  case _typeenum: { auto e = _class(aStream); return f(&e); }
+
+template<class S, class F>
+bool
+RecordedEvent::DoWithEvent(S &aStream, EventType aType, F f)
+{
+  switch (aType) {
+    FOR_EACH_EVENT(DO_WITH_EVENT_TYPE)
+  default:
+    return false;
+  }
+}
+
+
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif
deleted file mode 100644
--- a/gfx/doc/B2GInputFlow.svg
+++ /dev/null
@@ -1,349 +0,0 @@
-<?xml version="1.0"?>
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="800">
- <title>Touch input event flow on B2G</title>
- <g id="arrows"></g>
- <style type="text/css"><![CDATA[
-    text {
-        fill: black;
-        text-anchor: middle;
-        white-space: pre-line;
-        font-size: 14px;
-    }
-    rect {
-        fill: none;
-    }
-    line {
-        stroke: black;
-    }
-    .parentinput rect {
-        stroke: black;
-    }
-    text.parentinput {
-        fill: black;
-        text-anchor: start;
-    }
-    .parentmain rect {
-        stroke: orange;
-    }
-    text.parentmain {
-        fill: orange;
-        text-anchor: start;
-    }
-    .parentcompositor rect {
-        stroke: green;
-    }
-    text.parentcompositor {
-        fill: green;
-        text-anchor: start;
-    }
-    .childmain rect {
-        stroke: red;
-    }
-    text.childmain {
-        fill: red;
-        text-anchor: start;
-    }
-    .bothmain rect {
-        stroke: blue;
-    }
-    text.bothmain {
-        fill: blue;
-        text-anchor: start;
-    }
- ]]></style>
- <script type="text/javascript"><![CDATA[
-    var svg = "http://www.w3.org/2000/svg";
-    var maxY = 0;
-
-    function breaks(text) {
-        var count = 0;
-        for (var i = text.length - 1; i >= 0; i--) {
-            if (text.charAt(i) == '\n') {
-                count++;
-            }
-        }
-        return count;
-    }
-
-    function makeAction(text, x, y, thread) {
-        maxY = Math.max(maxY, y);
-        var g = document.createElementNS(svg, "g");
-        g.setAttribute("class", "action " + thread);
-        g.setAttribute("transform", "translate(" + x + ", " + (y + 30) + ")");
-        var r = document.createElementNS(svg, "rect");
-        r.setAttribute("width", "100");
-        r.setAttribute("height", "40");
-        var t = document.createElementNS(svg, "text");
-        t.setAttribute("x", "50");
-        t.setAttribute("y", 25 - (7 * breaks(text)));
-        t.appendChild(document.createTextNode(text));
-        g.appendChild(r);
-        g.appendChild(t);
-        return g;
-    }
-
-    function makeChoice(text, x, y, thread) {
-        maxY = Math.max(maxY, y);
-        var g = document.createElementNS(svg, "g");
-        g.setAttribute("class", "choice " + thread);
-        g.setAttribute("transform", "translate(" + (x + 15) + ", " + (y + 15) + ")");
-        var g2 = document.createElementNS(svg, "g");
-        g2.setAttribute("transform", "rotate(-45, 35, 35)");
-        var r = document.createElementNS(svg, "rect");
-        r.setAttribute("width", "70");
-        r.setAttribute("height", "70");
-        g2.appendChild(r);
-        var t = document.createElementNS(svg, "text");
-        t.setAttribute("x", "35");
-        t.setAttribute("y", 40 - (7 * breaks(text)));
-        t.appendChild(document.createTextNode(text));
-        g.appendChild(g2);
-        g.appendChild(t);
-        return g;
-    }
-
-    function makeLabelChoice(label, point) {
-        var t = document.createElementNS(svg, "text");
-        t.setAttribute("x", point.x);
-        t.setAttribute("y", point.y);
-        t.appendChild(document.createTextNode(label));
-        return t;
-    }
-
-    function makeLine(sx, sy, ex, ey) {
-        maxY = Math.max(maxY, sy, ey);
-        var l = document.createElementNS(svg, "line");
-        l.setAttribute("x1", sx);
-        l.setAttribute("y1", sy);
-        l.setAttribute("x2", ex);
-        l.setAttribute("y2", ey);
-        return l;
-    }
-
-    function makeArrow(start, end) {
-        var g = document.createElementNS(svg, "g");
-        g.appendChild(makeLine(start.x, start.y, end.x, end.y));
-        if (start.x != end.x) {
-            start.x = end.x + (4 * Math.sign(start.x - end.x));
-            g.appendChild(makeLine(start.x, start.y - 4, end.x, end.y));
-            g.appendChild(makeLine(start.x, start.y + 4, end.x, end.y));
-        } else if (start.y != end.y) {
-            start.y = end.y + (4 * Math.sign(start.y - end.y));
-            g.appendChild(makeLine(start.x - 4, start.y, end.x, end.y));
-            g.appendChild(makeLine(start.x + 4, start.y, end.x, end.y));
-        }
-        return g;
-    }
-
-    function makeVHArrow(start, end) {
-        var g = document.createElementNS(svg, "g");
-        g.appendChild(makeLine(start.x, start.y, start.x, end.y));
-        start.y = end.y;
-        g.appendChild(makeArrow(start, end));
-        return g;
-    }
-
-    function makeHVArrow(start, end) {
-        var g = document.createElementNS(svg, "g");
-        g.appendChild(makeLine(start.x, start.y, end.x, start.y));
-        start.x = end.x;
-        g.appendChild(makeArrow(start, end));
-        return g;
-    }
-
-    function makeVHVArrow(start, end, length) {
-        var g = document.createElementNS(svg, "g");
-        g.appendChild(makeLine(start.x, start.y, start.x, start.y + length));
-        start.y += length;
-        g.appendChild(makeLine(start.x, start.y, end.x, start.y));
-        start.x = end.x;
-        g.appendChild(makeArrow(start, end));
-        return g;
-    }
-
-    function makeHVHArrow(start, end, length) {
-        var g = document.createElementNS(svg, "g");
-        g.appendChild(makeLine(start.x, start.y, start.x + length, start.y));
-        start.x += length;
-        g.appendChild(makeLine(start.x, start.y, start.x, end.y));
-        start.y = end.y;
-        g.appendChild(makeArrow(start, end));
-        return g;
-    }
-
-    function translation(group) {
-        var r = new RegExp("translate\\((\\d+), (\\d+)\\)");
-        var result = r.exec(group.getAttribute("transform"));
-        return { x: parseInt(result[1]), y: parseInt(result[2]) };
-    }
-
-    function isAction(group) {
-        return group.classList.contains("action");
-    }
-
-    function isChoice(group) {
-        return group.classList.contains("choice");
-    }
-
-    function offset(point, x, y) {
-        point.x += x;
-        point.y += y;
-        return point;
-    }
-
-    function rightOf(group) {
-        var t = translation(group);
-        if (isAction(group)) {
-            return offset(t, 100, 20);
-        }
-        if (isChoice(group)) {
-            return offset(t, 85, 35);
-        }
-        return t;
-    }
-
-    function leftOf(group) {
-        var t = translation(group);
-        if (isAction(group)) {
-            return offset(t, 0, 20);
-        }
-        if (isChoice(group)) {
-            return offset(t, -15, 35);
-        }
-        return t;
-    }
-
-    function topOf(group) {
-        var t = translation(group);
-        if (isAction(group)) {
-            return offset(t, 50, 0);
-        }
-        if (isChoice(group)) {
-            return offset(t, 35, -15);
-        }
-        return t;
-    }
-
-    function bottomOf(group) {
-        var t = translation(group);
-        if (isAction(group)) {
-            return offset(t, 50, 40);
-        }
-        if (isChoice(group)) {
-            return offset(t, 35, 85);
-        }
-        return t;
-    }
-
-    function midpoint(start, end) {
-        return { x: (start.x + end.x) / 2,
-                 y: (start.y + end.y) / 2 };
-    }
-
-    function makeLegend(label, thread) {
-        var t = document.createElementNS(svg, "text");
-        t.setAttribute("x", "10");
-        t.setAttribute("y", maxY);
-        t.setAttribute("class", thread);
-        maxY += 15;
-        t.appendChild(document.createTextNode(label));
-        return t;
-    }
-
-    var android = makeAction("Android/Gonk", 20, 0, "parentinput");
-    var sendNative = makeAction("DOMWindowUtils\nsendNativeTouchPoint", 20, 100, "parentmain");
-    var apzHitTest = makeAction("APZ hit test", 150, 0, "parentcompositor");
-    var apzUntransform = makeAction("APZ\nuntransform", 300, 0, "parentcompositor");
-    var apzGesture = makeAction("APZ gesture\ndetection", 450, 0, "parentcompositor");
-    var apzTransform = makeAction("APZ transform\nupdate", 600, 0, "parentcompositor");
-    var compositor = makeAction("Compositor", 750, 0, "parentcompositor");
-    var nsAppShell = makeAction("nsAppShell", 150, 100, "parentmain");
-    var rootHitTest = makeAction("Gecko hit test\n(root process)", 300, 100, "parentmain");
-    var rootEsm = makeAction("Gecko ESM\n(root process)", 450, 100, "parentmain");
-    var isEdgeGesture = makeChoice("Edge gesture?", 300, 200, "parentmain");
-    var edgeConsume = makeAction("Consume\nevent block", 150, 200, "parentmain");
-    var bepjsm = makeAction("BEParent.jsm\nsendTouchEvent", 450, 200, "parentmain");
-    var iframeSend = makeAction("HTMLIFrameElement\nsendTouchEvent", 20, 275, "parentmain");
-    var isApzTarget = makeChoice("Target\nhas APZ?", 600, 200, "parentmain");
-    var sendTouchEvent = makeAction("Target\nsendTouchEventToWindow", 750, 100, "parentmain");
-    var injectTouch = makeAction("injectTouchEvent", 750, 200, "parentmain");
-    var targetESM = makeAction("Target window\nESM", 750, 450, "bothmain");
-    var tabParent = makeAction("TabParent", 750, 350, "parentmain");
-    var geckoUntransform = makeAction("Gecko\nuntransform", 600, 350, "parentmain");
-    var tabChild = makeAction("TabChild", 450, 350, "childmain");
-    var isApzcEnabled = makeChoice("APZ\nenabled?", 300, 350, "childmain");
-    var tabGesture = makeAction("TabChild gesture\ndetection", 150, 350, "childmain");
-    var childHitTest = makeAction("Gecko hit test\n(child process)", 300, 450, "childmain");
-    var childEsm = makeAction("Gecko ESM\n(child process)", 450, 450, "childmain");
-    var childContent = makeAction("Content\n(child process)", 600, 450, "childmain");
-
-    document.documentElement.appendChild(android);
-    document.documentElement.appendChild(sendNative);
-    document.documentElement.appendChild(apzHitTest);
-    document.documentElement.appendChild(apzUntransform);
-    document.documentElement.appendChild(apzGesture);
-    document.documentElement.appendChild(apzTransform);
-    document.documentElement.appendChild(compositor);
-    document.documentElement.appendChild(nsAppShell);
-    document.documentElement.appendChild(rootHitTest);
-    document.documentElement.appendChild(rootEsm);
-    document.documentElement.appendChild(isEdgeGesture);
-    document.documentElement.appendChild(edgeConsume);
-    document.documentElement.appendChild(bepjsm);
-    document.documentElement.appendChild(iframeSend);
-    document.documentElement.appendChild(isApzTarget);
-    document.documentElement.appendChild(sendTouchEvent);
-    document.documentElement.appendChild(injectTouch);
-    document.documentElement.appendChild(targetESM);
-    document.documentElement.appendChild(tabParent);
-    document.documentElement.appendChild(geckoUntransform);
-    document.documentElement.appendChild(tabChild);
-    document.documentElement.appendChild(isApzcEnabled);
-    document.documentElement.appendChild(tabGesture);
-    document.documentElement.appendChild(childHitTest);
-    document.documentElement.appendChild(childEsm);
-    document.documentElement.appendChild(childContent);
-
-    document.documentElement.appendChild(makeLabelChoice("Y", offset(leftOf(isEdgeGesture), -5, -5)));
-    document.documentElement.appendChild(makeLabelChoice("N", offset(rightOf(isEdgeGesture), 5, -5)));
-    document.documentElement.appendChild(makeLabelChoice("N", offset(topOf(isApzTarget), 8, -10)));
-    document.documentElement.appendChild(makeLabelChoice("Y", offset(rightOf(isApzTarget), 10, 14)));
-    document.documentElement.appendChild(makeLabelChoice("N", offset(leftOf(isApzcEnabled), -5, -5)));
-    document.documentElement.appendChild(makeLabelChoice("Y", offset(bottomOf(isApzcEnabled), 10, 14)));
-
-    var arrows = document.getElementById('arrows');
-    arrows.appendChild(makeArrow(rightOf(android), leftOf(apzHitTest)));
-    arrows.appendChild(makeVHVArrow(topOf(sendNative), midpoint(rightOf(android), leftOf(apzHitTest)), -20));
-    arrows.appendChild(makeArrow(rightOf(apzHitTest), leftOf(apzUntransform)));
-    arrows.appendChild(makeArrow(rightOf(apzUntransform), leftOf(apzGesture)));
-    arrows.appendChild(makeArrow(rightOf(apzGesture), leftOf(apzTransform)));
-    arrows.appendChild(makeArrow(rightOf(apzTransform), leftOf(compositor)));
-    arrows.appendChild(makeVHVArrow(midpoint(leftOf(apzUntransform), rightOf(apzGesture)), topOf(nsAppShell), 40));
-    arrows.appendChild(makeArrow(rightOf(nsAppShell), leftOf(rootHitTest)));
-    arrows.appendChild(makeArrow(rightOf(rootHitTest), leftOf(rootEsm)));
-    arrows.appendChild(makeVHVArrow(bottomOf(rootEsm), topOf(isEdgeGesture), 15));
-    arrows.appendChild(makeArrow(leftOf(isEdgeGesture), rightOf(edgeConsume)));
-    arrows.appendChild(makeArrow(rightOf(isEdgeGesture), leftOf(bepjsm), 20));
-    arrows.appendChild(makeHVArrow(rightOf(iframeSend), bottomOf(bepjsm)));
-    arrows.appendChild(makeArrow(rightOf(bepjsm), leftOf(isApzTarget)));
-    arrows.appendChild(makeArrow(rightOf(isApzTarget), leftOf(injectTouch)));
-    arrows.appendChild(makeArrow(bottomOf(injectTouch), topOf(tabParent)));
-    arrows.appendChild(makeVHArrow(topOf(isApzTarget), leftOf(sendTouchEvent)));
-    arrows.appendChild(makeHVHArrow(rightOf(sendTouchEvent), rightOf(targetESM), 30));
-    arrows.appendChild(makeArrow(leftOf(tabParent), rightOf(geckoUntransform)));
-    arrows.appendChild(makeArrow(leftOf(geckoUntransform), rightOf(tabChild)));
-    arrows.appendChild(makeArrow(leftOf(tabChild), rightOf(isApzcEnabled)));
-    arrows.appendChild(makeArrow(leftOf(isApzcEnabled), rightOf(tabGesture)));
-    arrows.appendChild(makeArrow(bottomOf(isApzcEnabled), topOf(childHitTest)));
-    arrows.appendChild(makeVHArrow(bottomOf(tabGesture), leftOf(childHitTest)));
-    arrows.appendChild(makeArrow(rightOf(childHitTest), leftOf(childEsm)));
-    arrows.appendChild(makeArrow(rightOf(childEsm), leftOf(childContent)));
-    arrows.appendChild(makeVHVArrow(midpoint(leftOf(apzGesture), rightOf(apzTransform)), topOf(tabChild), 300));
-
-    document.documentElement.appendChild(makeLegend("Main process input thread", "parentinput"));
-    document.documentElement.appendChild(makeLegend("Main process main thread", "parentmain"));
-    document.documentElement.appendChild(makeLegend("Main process compositor thread", "parentcompositor"));
-    document.documentElement.appendChild(makeLegend("Child process main thread", "childmain"));
-    document.documentElement.appendChild(makeLegend("Undetermined process main thread", "bothmain"));
- ]]></script>
-</svg>
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -1,24 +1,26 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebRenderLayerManager.h"
 
+#include "BasicLayers.h"
 #include "gfxPrefs.h"
 #include "GeckoProfiler.h"
 #include "LayersLogging.h"
 #include "mozilla/gfx/DrawEventRecorder.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/layers/UpdateImageHelper.h"
+#include "nsDisplayList.h"
 #include "WebRenderCanvasLayer.h"
 #include "WebRenderCanvasRenderer.h"
 #include "WebRenderColorLayer.h"
 #include "WebRenderContainerLayer.h"
 #include "WebRenderImageLayer.h"
 #include "WebRenderPaintedLayer.h"
 #include "WebRenderPaintedLayerBlob.h"
 #include "WebRenderTextLayer.h"
@@ -100,16 +102,18 @@ WebRenderLayerManager::DoDestroy(bool aI
   if (WrBridge()) {
     // Just clear ImageKeys, they are deleted during WebRenderAPI destruction.
     mImageKeysToDelete.clear();
     // CompositorAnimations are cleared by WebRenderBridgeParent.
     mDiscardedCompositorAnimationsIds.Clear();
     WrBridge()->Destroy(aIsSync);
   }
 
+  mLastCanvasDatas.Clear();
+
   if (mTransactionIdAllocator) {
     // Make sure to notify the refresh driver just in case it's waiting on a
     // pending transaction. Do this at the top of the event loop so we don't
     // cause a paint to occur during compositor shutdown.
     RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator;
     uint64_t id = mLatestTransactionId;
 
     RefPtr<Runnable> task = NS_NewRunnableFunction(
@@ -385,21 +389,43 @@ PaintItemByDrawTarget(nsDisplayItem* aIt
                       nsDisplayListBuilder* aDisplayListBuilder)
 {
   MOZ_ASSERT(aDT);
 
   aDT->ClearRect(aImageRect.ToUnknownRect());
   RefPtr<gfxContext> context = gfxContext::CreateOrNull(aDT, aOffset.ToUnknownPoint());
   MOZ_ASSERT(context);
 
-  if (aItem->GetType() == DisplayItemType::TYPE_MASK) {
+  switch (aItem->GetType()) {
+  case DisplayItemType::TYPE_MASK:
     context->SetMatrix(gfxMatrix::Translation(-aOffset.x, -aOffset.y));
     static_cast<nsDisplayMask*>(aItem)->PaintMask(aDisplayListBuilder, context);
-  } else {
+    break;
+  case DisplayItemType::TYPE_FILTER:
+    {
+      RefPtr<BasicLayerManager> tempManager = new BasicLayerManager(BasicLayerManager::BLM_INACTIVE);
+      FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
+      layerBuilder->Init(aDisplayListBuilder, tempManager);
+
+      tempManager->BeginTransactionWithTarget(context);
+      ContainerLayerParameters param;
+      RefPtr<Layer> layer = aItem->BuildLayer(aDisplayListBuilder, tempManager, param);
+      if (layer) {
+        tempManager->SetRoot(layer);
+        static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(aDisplayListBuilder, context, tempManager);
+      }
+
+      if (tempManager->InTransaction()) {
+        tempManager->AbortTransaction();
+      }
+      break;
+    }
+  default:
     aItem->Paint(aDisplayListBuilder, context);
+    break;
   }
 
   if (gfxPrefs::WebRenderHighlightPaintedLayers()) {
     aDT->SetTransform(Matrix());
     aDT->FillRect(Rect(0, 0, aImageRect.Width(), aImageRect.Height()), ColorPattern(Color(1.0, 0.0, 0.0, 0.5)));
   }
   if (aItem->Frame()->PresContext()->GetPaintFlashing()) {
     aDT->SetTransform(Matrix());
@@ -905,16 +931,19 @@ WebRenderLayerManager::DidComposite(uint
 
 void
 WebRenderLayerManager::ClearLayer(Layer* aLayer)
 {
   aLayer->ClearCachedResources();
   if (aLayer->GetMaskLayer()) {
     aLayer->GetMaskLayer()->ClearCachedResources();
   }
+  for (size_t i = 0; i < aLayer->GetAncestorMaskLayerCount(); i++) {
+    aLayer->GetAncestorMaskLayerAt(i)->ClearCachedResources();
+  }
   for (Layer* child = aLayer->GetFirstChild(); child;
        child = child->GetNextSibling()) {
     ClearLayer(child);
   }
 }
 
 void
 WebRenderLayerManager::ClearCachedResources(Layer* aSubtree)
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -201,17 +201,17 @@ public:
     if (!frame->HasProperty(nsIFrame::WebRenderUserDataProperty())) {
       frame->AddProperty(nsIFrame::WebRenderUserDataProperty(),
                          new nsIFrame::WebRenderUserDataTable());
     }
 
     nsIFrame::WebRenderUserDataTable* userDataTable =
       frame->GetProperty(nsIFrame::WebRenderUserDataProperty());
     RefPtr<WebRenderUserData>& data = userDataTable->GetOrInsert(aItem->GetPerFrameKey());
-    if (!data || (data->GetType() != T::Type())) {
+    if (!data || (data->GetType() != T::Type()) || !data->IsDataValid(this)) {
       data = new T(this);
       if (aOutIsRecycled) {
         *aOutIsRecycled = false;
       }
     }
 
     MOZ_ASSERT(data);
     MOZ_ASSERT(data->GetType() == T::Type());
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -19,16 +19,22 @@ WebRenderUserData::WebRenderUserData(Web
   : mWRManager(aWRManager)
 {
 }
 
 WebRenderUserData::~WebRenderUserData()
 {
 }
 
+bool
+WebRenderUserData::IsDataValid(WebRenderLayerManager* aManager)
+{
+  return aManager == mWRManager;
+}
+
 WebRenderBridgeChild*
 WebRenderUserData::WrBridge() const
 {
   return mWRManager->WrBridge();
 }
 
 WebRenderImageData::WebRenderImageData(WebRenderLayerManager* aWRManager)
   : WebRenderUserData(aWRManager)
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -39,16 +39,18 @@ public:
     eImage,
     eFallback,
     eAnimation,
     eCanvas,
   };
 
   virtual UserDataType GetType() = 0;
 
+  bool IsDataValid(WebRenderLayerManager* aManager);
+
 protected:
   virtual ~WebRenderUserData();
 
   WebRenderBridgeChild* WrBridge() const;
 
   RefPtr<WebRenderLayerManager> mWRManager;
 };
 
--- a/gfx/tests/mochitest/test_acceleration.html
+++ b/gfx/tests/mochitest/test_acceleration.html
@@ -118,17 +118,17 @@ switch(osName)
     }
     break;
 
   case "Linux":
     todo(false, "Acceleration supported on Linux, but only on taskcluster instances (bug 1296086)");
     break;
 
   default:
-    if (xr.OS == "Android" && xr.widgetToolkit != "gonk") {
+    if (xr.OS == "Android") {
       isnot(acceleratedWindows, 0, "Acceleration enabled on Android");
     } else {
       is(acceleratedWindows, 0, "Acceleration not supported on '" + osName + "'");
     }
 }
 
 </script>
 </pre>
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -216,17 +216,21 @@ MacOSFontEntry::ReadCMAP(FontInfoData *a
             }
         }
 
         // Bug 1360309: several of Apple's Chinese fonts have spurious blank
         // glyphs for obscure Tibetan codepoints. Blacklist these so that font
         // fallback will not use them.
         if (mRequiresAAT && (FamilyName().EqualsLiteral("Songti SC") ||
                              FamilyName().EqualsLiteral("Songti TC") ||
-                             FamilyName().EqualsLiteral("STSong"))) {
+                             FamilyName().EqualsLiteral("STSong") ||
+        // Bug 1390980: on 10.11, the Kaiti fonts are also affected.
+                             FamilyName().EqualsLiteral("Kaiti SC") ||
+                             FamilyName().EqualsLiteral("Kaiti TC") ||
+                             FamilyName().EqualsLiteral("STKaiti"))) {
             charmap->ClearRange(0x0f8c, 0x0f8f);
         }
     }
 
     mHasCmapTable = NS_SUCCEEDED(rv);
     if (mHasCmapTable) {
         gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
         mCharacterMap = pfl->FindCharMap(charmap);
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -590,18 +590,16 @@ public:
      * Return the layer debugging options to use browser-wide.
      */
     mozilla::layers::DiagnosticTypes GetLayerDiagnosticTypes();
 
     mozilla::gl::SkiaGLGlue* GetSkiaGLGlue();
     void PurgeSkiaGPUCache();
     static void PurgeSkiaFontCache();
 
-    virtual bool IsInGonkEmulator() const { return false; }
-
     static bool UsesOffMainThreadCompositing();
 
     bool HasEnoughTotalSystemMemoryForSkiaGL();
 
     /**
      * Get the hardware vsync source for each platform.
      * Should only exist and be valid on the parent process
      */
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -58,18 +58,18 @@ enum ProcessPriority {
   PROCESS_PRIORITY_MASTER,
   NUM_PROCESS_PRIORITY
 };
 
 /**
  * Values that can be passed to hal::SetCurrentThreadPriority().  These should be
  * functional in nature, such as COMPOSITOR, instead of levels, like LOW/HIGH.
  * This allows us to tune our priority scheme for the system in one place such
- * that it makes sense holistically for the overall operating system.  On gonk
- * or android we may want different priority schemes than on windows, etc.
+ * that it makes sense holistically for the overall operating system.  On
+ * android we may want different priority schemes than on windows, etc.
  */
 enum ThreadPriority {
   THREAD_PRIORITY_COMPOSITOR,
   NUM_THREAD_PRIORITY
 };
 
 /**
  * Convert a ProcessPriority enum value to a string.  The strings returned by
--- a/hal/moz.build
+++ b/hal/moz.build
@@ -90,17 +90,17 @@ elif CONFIG['OS_TARGET'] in ('OpenBSD', 
 else:
     UNIFIED_SOURCES += [
         'fallback/FallbackBattery.cpp',
         'fallback/FallbackScreenConfiguration.cpp',
         'fallback/FallbackSensor.cpp',
         'fallback/FallbackVibration.cpp',
     ]
 
-# Fallbacks for backends implemented on Gonk only.
+# Fallbacks for backends no longer implemented.
 UNIFIED_SOURCES += [
     'fallback/FallbackDiskSpaceWatcher.cpp',
     'fallback/FallbackProcessPriority.cpp',
     'fallback/FallbackSwitch.cpp',
     'fallback/FallbackThreadPriority.cpp',
     'fallback/FallbackTime.cpp',
 ]
 
--- a/image/ImageFactory.cpp
+++ b/image/ImageFactory.cpp
@@ -70,16 +70,24 @@ ComputeImageFlags(ImageURL* uri, const n
   }
   if (doDecodeImmediately) {
     imageFlags |= Image::INIT_FLAG_DECODE_IMMEDIATELY;
   }
   if (isMultiPart) {
     imageFlags |= Image::INIT_FLAG_TRANSIENT;
   }
 
+  // Synchronously decode metadata (including size) if we have a data URI since
+  // the data is immediately available.
+  bool isDataURI = false;
+  rv = uri->SchemeIs("data", &isDataURI);
+  if (NS_SUCCEEDED(rv) && isDataURI) {
+    imageFlags |= Image::INIT_FLAG_SYNC_LOAD;
+  }
+
   return imageFlags;
 }
 
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateImage(nsIRequest* aRequest,
                           ProgressTracker* aProgressTracker,
                           const nsCString& aMimeType,
                           ImageURL* aURI,
--- a/image/test/mochitest/mochitest.ini
+++ b/image/test/mochitest/mochitest.ini
@@ -120,16 +120,17 @@ skip-if = true # disabled - See bug 5791
 [test_bug767779.html]
 [test_bug865919.html]
 [test_bug89419-1.html]
 [test_bug89419-2.html]
 [test_bug1132427.html]
 skip-if = os == 'android'
 [test_bug1180105.html]
 [test_bug1217571.html]
+[test_bug1325080.html]
 [test_bullet_animation.html]
 skip-if = os == 'android'
 [test_changeOfSource.html]
 skip-if = os == 'android'
 [test_changeOfSource2.html]
 skip-if = os == 'android'
 [test_discardAnimatedImage.html]
 [test_drawDiscardedImage.html]
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_bug1325080.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1325080
+-->
+<head>
+  <title>Test for Bug 1325080</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1325080">Mozilla Bug 1325080</a>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 1325080 **/
+
+SimpleTest.waitForExplicitFinish();
+
+function createImage() {
+  // This function's code comes from the Acid3 test #72
+  document.open();
+  document.write('<!DOCTYPE html><head><style>img { height: 10px; }</style></head><body><img src="data:image/gif;base64,R0lGODlhAQABAID%2FAMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw%3D%3D" alt="alt-text"></body>');
+  document.close();
+}
+
+window.onload = function() {
+  createImage();
+  SimpleTest.executeSoon(() => {
+    ok(document.images[0].height == 10, "Style should set height of image.");
+    SimpleTest.finish();
+  });
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/ipc/dbus/RawDBusConnection.h
+++ b/ipc/dbus/RawDBusConnection.h
@@ -1,16 +1,16 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_ipc_dbus_gonk_rawdbusconnection_h__
-#define mozilla_ipc_dbus_gonk_rawdbusconnection_h__
+#ifndef mozilla_ipc_dbus_rawdbusconnection_h__
+#define mozilla_ipc_dbus_rawdbusconnection_h__
 
 #include <dbus/dbus.h>
 #include "mozilla/ipc/DBusConnectionRefPtr.h"
 
 namespace mozilla {
 namespace ipc {
 
 typedef void (*DBusReplyCallback)(DBusMessage*, void*);
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -61,16 +61,17 @@ enum ThreadType {
     THREAD_TYPE_WASM,           // 2
     THREAD_TYPE_ION,            // 3
     THREAD_TYPE_PARSE,          // 4
     THREAD_TYPE_COMPRESS,       // 5
     THREAD_TYPE_GCHELPER,       // 6
     THREAD_TYPE_GCPARALLEL,     // 7
     THREAD_TYPE_PROMISE_TASK,   // 8
     THREAD_TYPE_ION_FREE,       // 9
+    THREAD_TYPE_WASM_TIER2,     // 10
     THREAD_TYPE_MAX             // Used to check shell function arguments
 };
 
 namespace oom {
 
 /*
  * Theads are tagged only in certain debug contexts.  Notably, to make testing
  * OOM in certain helper threads more effective, we allow restricting the OOM
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -1227,17 +1227,17 @@ InterpretDollar(JSLinearString* matched,
 {
     MOZ_ASSERT(*currentDollar == '$');
 
     /* If there is only a dollar, bail now. */
     if (currentDollar + 1 >= replacementEnd)
         return false;
 
     /* ES 2016 draft Mar 25, 2016 Table 46. */
-    CharT c = currentDollar[1];
+    char16_t c = currentDollar[1];
     if (JS7_ISDEC(c)) {
         /* $n, $nn */
         unsigned num = JS7_UNDEC(c);
         if (num > captures.length()) {
             // The result is implementation-defined, do not substitute.
             return false;
         }
 
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -47,16 +47,17 @@
 #include "vm/StringBuffer.h"
 #include "vm/TraceLogging.h"
 #include "wasm/AsmJS.h"
 #include "wasm/WasmBinaryToText.h"
 #include "wasm/WasmJS.h"
 #include "wasm/WasmModule.h"
 #include "wasm/WasmSignalHandlers.h"
 #include "wasm/WasmTextToBinary.h"
+#include "wasm/WasmTypes.h"
 
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
@@ -524,16 +525,24 @@ static bool
 WasmIsSupported(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setBoolean(wasm::HasSupport(cx));
     return true;
 }
 
 static bool
+WasmDebuggingIsSupported(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    args.rval().setBoolean(wasm::HasSupport(cx) && cx->options().wasmBaseline());
+    return true;
+}
+
+static bool
 WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject callee(cx, &args.callee());
 
     if (!args.requireAtLeast(cx, "wasmTextToBinary", 1))
         return false;
 
@@ -645,18 +654,53 @@ WasmExtractCode(JSContext* cx, unsigned 
 
     JSObject* unwrapped = CheckedUnwrap(&args.get(0).toObject());
     if (!unwrapped || !unwrapped->is<WasmModuleObject>()) {
         JS_ReportErrorASCII(cx, "argument is not a WebAssembly.Module");
         return false;
     }
 
     Rooted<WasmModuleObject*> module(cx, &unwrapped->as<WasmModuleObject>());
+
+    bool stableTier = false;
+    bool bestTier = false;
+    bool baselineTier = false;
+    bool ionTier = false;
+    if (args.length() > 1) {
+        JSString* opt = JS::ToString(cx, args[1]);
+        if (!opt)
+            return false;
+        if (!JS_StringEqualsAscii(cx, opt, "stable", &stableTier) ||
+            !JS_StringEqualsAscii(cx, opt, "best", &bestTier) ||
+            !JS_StringEqualsAscii(cx, opt, "baseline", &baselineTier) ||
+            !JS_StringEqualsAscii(cx, opt, "ion", &ionTier))
+        {
+            return false;
+        }
+        // You can omit the argument but you can't pass just anything you like
+        if (!(stableTier || bestTier || baselineTier || ionTier)) {
+            args.rval().setNull();
+            return true;
+        }
+    } else {
+        stableTier = true;
+    }
+
+    wasm::Tier tier;
+    if (stableTier)
+        tier = module->module().code().stableTier();
+    else if (bestTier)
+        tier = module->module().code().bestTier();
+    else if (baselineTier)
+        tier = wasm::Tier::Baseline;
+    else
+        tier = wasm::Tier::Ion;
+
     RootedValue result(cx);
-    if (!module->module().extractCode(cx, &result))
+    if (!module->module().extractCode(cx, tier, &result))
         return false;
 
     args.rval().set(result);
     return true;
 }
 
 static bool
 IsLazyFunction(JSContext* cx, unsigned argc, Value* vp)
@@ -4665,27 +4709,35 @@ gc::ZealModeHelpText),
 "isAsmJSFunction(fn)",
 "  Returns whether the given value is a nested function in an asm.js module that has been\n"
 "  both compile- and link-time validated."),
 
     JS_FN_HELP("wasmIsSupported", WasmIsSupported, 0, 0,
 "wasmIsSupported()",
 "  Returns a boolean indicating whether WebAssembly is supported on the current device."),
 
+    JS_FN_HELP("wasmDebuggingIsSupported", WasmDebuggingIsSupported, 0, 0,
+"wasmDebuggingIsSupported()",
+"  Returns a boolean indicating whether WebAssembly debugging is supported on the current device;\n"
+"  returns false also if WebAssembly is not supported"),
+
     JS_FN_HELP("wasmTextToBinary", WasmTextToBinary, 1, 0,
 "wasmTextToBinary(str)",
 "  Translates the given text wasm module into its binary encoding."),
 
     JS_FN_HELP("wasmBinaryToText", WasmBinaryToText, 1, 0,
 "wasmBinaryToText(bin)",
 "  Translates binary encoding to text format"),
 
     JS_FN_HELP("wasmExtractCode", WasmExtractCode, 1, 0,
-"wasmExtractCode(module)",
-"  Extracts generated machine code from WebAssembly.Module."),
+"wasmExtractCode(module[, tier])",
+"  Extracts generated machine code from WebAssembly.Module.  The tier is a string,\n"
+"  'stable', 'best', 'baseline', or 'ion'; the default is 'stable'.  If the request\n"
+"  cannot be satisfied then null is returned.  If the request is 'ion' then block\n"
+"  until background compilation is complete."),
 
     JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0,
 "isLazyFunction(fun)",
 "  True if fun is a lazy JSFunction."),
 
     JS_FN_HELP("isRelazifiableFunction", IsRelazifiableFunction, 1, 0,
 "isRelazifiableFunction(fun)",
 "  Ture if fun is a JSFunction with a relazifiable JSScript."),
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2278,21 +2278,16 @@ BytecodeEmitter::locationOfNameBoundInFu
     return source->locationBoundInScope(this, name, funScope);
 }
 
 bool
 BytecodeEmitter::emitCheck(ptrdiff_t delta, ptrdiff_t* offset)
 {
     *offset = code().length();
 
-    // Start it off moderately large to avoid repeated resizings early on.
-    // ~98% of cases fit within 1024 bytes.
-    if (code().capacity() == 0 && !code().reserve(1024))
-        return false;
-
     if (!code().growBy(delta)) {
         ReportOutOfMemory(cx);
         return false;
     }
     return true;
 }
 
 void
@@ -11296,21 +11291,16 @@ BytecodeEmitter::emitTreeInBranch(ParseN
     // cache.
     TDZCheckCache tdzCache(this);
     return emitTree(pn, valueUsage);
 }
 
 static bool
 AllocSrcNote(JSContext* cx, SrcNotesVector& notes, unsigned* index)
 {
-    // Start it off moderately large to avoid repeated resizings early on.
-    // ~99% of cases fit within 256 bytes.
-    if (notes.capacity() == 0 && !notes.reserve(256))
-        return false;
-
     if (!notes.growBy(1)) {
         ReportOutOfMemory(cx);
         return false;
     }
 
     *index = notes.length() - 1;
     return true;
 }
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -100,20 +100,20 @@ struct CGYieldAndAwaitOffsetList {
     uint32_t numAwaits;
     explicit CGYieldAndAwaitOffsetList(JSContext* cx) : list(cx), numYields(0), numAwaits(0) {}
 
     MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); }
     size_t length() const { return list.length(); }
     void finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength);
 };
 
-// Use zero inline elements because these go on the stack and affect how many
-// nested functions are possible.
-typedef Vector<jsbytecode, 0> BytecodeVector;
-typedef Vector<jssrcnote, 0> SrcNotesVector;
+// Have a few inline elements, so as to avoid heap allocation for tiny
+// sequences.  See bug 1390526.
+typedef Vector<jsbytecode, 64> BytecodeVector;
+typedef Vector<jssrcnote, 64> SrcNotesVector;
 
 // Linked list of jump instructions that need to be patched. The linked list is
 // stored in the bytes of the incomplete bytecode that will be patched, so no
 // extra memory is needed, and patching the instructions destroys the list.
 //
 // Example:
 //
 //     JumpList brList;
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -157,19 +157,28 @@ class GCSchedulingTunables
      * JSGC_ALLOCATION_THRESHOLD
      *
      * The base value used to compute zone->threshold.gcTriggerBytes(). When
      * usage.gcBytes() surpasses threshold.gcTriggerBytes() for a zone, the
      * zone may be scheduled for a GC, depending on the exact circumstances.
      */
     ActiveThreadOrGCTaskData<size_t> gcZoneAllocThresholdBase_;
 
-    /* Fraction of threshold.gcBytes() which triggers an incremental GC. */
+    /*
+     * JSGC_ALLOCATION_THRESHOLD_FACTOR
+     *
+     * Fraction of threshold.gcBytes() which triggers an incremental GC.
+     */
     UnprotectedData<float> zoneAllocThresholdFactor_;
-    /* The same except when doing so would interrupt an already running GC. */
+
+    /*
+     * JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT
+     *
+     * The same except when doing so would interrupt an already running GC.
+     */
     UnprotectedData<float> zoneAllocThresholdFactorAvoidInterrupt_;
 
     /*
      * Number of bytes to allocate between incremental slices in GCs triggered
      * by the zone allocation threshold.
      *
      * This value does not have a JSGCParamKey parameter yet.
      */
--- a/js/src/jit-test/tests/debug/Script-format-01.js
+++ b/js/src/jit-test/tests/debug/Script-format-01.js
@@ -1,11 +1,14 @@
 // Tests that JavaScript scripts have a "js" format and wasm scripts have a
 // "wasm" format.
 
+if (!wasmDebuggingIsSupported())
+    quit(0);
+
 var g = newGlobal();
 var dbg = new Debugger(g);
 
 var gotScript;
 dbg.onNewScript = (script) => {
   gotScript = script;
 };
 
--- a/js/src/jit-test/tests/debug/bug1257045.js
+++ b/js/src/jit-test/tests/debug/bug1257045.js
@@ -1,9 +1,9 @@
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
   quit();
 
 fullcompartmentchecks(true);
 var g = newGlobal();
 var dbg = new Debugger(g);
 dbg.onNewScript = (function(script) {
     s = script;
 })
--- a/js/src/jit-test/tests/debug/bug1330339.js
+++ b/js/src/jit-test/tests/debug/bug1330339.js
@@ -1,11 +1,11 @@
-// |jit-test| test-also-wasm-baseline; error: TestComplete
+// |jit-test| test-also-no-wasm-baseline; error: TestComplete
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
      throw "TestComplete";
 
 let module = new WebAssembly.Module(wasmTextToBinary(`
     (module
         (import "global" "func")
         (func (export "test")
          call 0 ;; calls the import, which is func #0
         )
--- a/js/src/jit-test/tests/debug/bug1330489-sps.js
+++ b/js/src/jit-test/tests/debug/bug1330489-sps.js
@@ -1,13 +1,13 @@
-// |jit-test| test-also-wasm-baseline; error: TestComplete
+// |jit-test| test-also-no-wasm-baseline; error: TestComplete
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
     throw "TestComplete";
 
 // Single-step profiling currently only works in the ARM simulator
 if (!getBuildConfiguration()["arm-simulator"])
     throw "TestComplete";
 
 enableGeckoProfiling();
 enableSingleStepProfiling();
--- a/js/src/jit-test/tests/debug/bug1330489.js
+++ b/js/src/jit-test/tests/debug/bug1330489.js
@@ -1,13 +1,13 @@
-// |jit-test| test-also-wasm-baseline; error: TestComplete
+// |jit-test| test-also-no-wasm-baseline; error: TestComplete
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
     throw "TestComplete";
 
 var g = newGlobal();
 g.parent = this;
 g.eval("Debugger(parent).onExceptionUnwind = function () {};");
 
 let module = new WebAssembly.Module(wasmTextToBinary(`
     (module
--- a/js/src/jit-test/tests/debug/bug1330491.js
+++ b/js/src/jit-test/tests/debug/bug1330491.js
@@ -1,11 +1,11 @@
-// |jit-test| test-also-wasm-baseline; error: TestComplete
+// |jit-test| test-also-no-wasm-baseline; error: TestComplete
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
      throw "TestComplete";
 
 (function createShortLivedDebugger() {
     var g = newGlobal();
     g.debuggeeGlobal = this;
     g.eval("(" + function () {
         dbg = new Debugger(debuggeeGlobal);
     } + ")();");
@@ -13,9 +13,9 @@ if (!wasmIsSupported())
 
 let module = new WebAssembly.Module(wasmTextToBinary('(module (func))'));
 new WebAssembly.Instance(module);
 
 gcslice(1000000);
 
 new WebAssembly.Instance(module);
 
-throw "TestComplete";
\ No newline at end of file
+throw "TestComplete";
--- a/js/src/jit-test/tests/debug/bug1331064.js
+++ b/js/src/jit-test/tests/debug/bug1331064.js
@@ -1,14 +1,14 @@
-// |jit-test| test-also-wasm-baseline; exitstatus: 3
+// |jit-test| test-also-no-wasm-baseline; exitstatus: 3
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
-     quit(3);
+if (!wasmDebuggingIsSupported())
+    quit(3);
 
 var g = newGlobal();
 g.parent = this;
 g.eval("new Debugger(parent).onExceptionUnwind = function () {  some_error; };");
 
 var module = new WebAssembly.Module(wasmTextToBinary(`
 (module
     (import $imp "a" "b" (result i32))
--- a/js/src/jit-test/tests/debug/bug1331592.js
+++ b/js/src/jit-test/tests/debug/bug1331592.js
@@ -1,11 +1,11 @@
-// |jit-test| test-also-wasm-baseline; error: TestComplete
+// |jit-test| test-also-no-wasm-baseline; error: TestComplete
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
      throw "TestComplete";
 
 var module = new WebAssembly.Module(wasmTextToBinary(`
     (module
         (import "global" "func" (result i32))
         (func (export "func_0") (result i32)
          call 0 ;; calls the import, which is func #0
         )
--- a/js/src/jit-test/tests/debug/bug1332493.js
+++ b/js/src/jit-test/tests/debug/bug1332493.js
@@ -1,12 +1,12 @@
-// |jit-test| test-also-wasm-baseline; exitstatus: 3
+// |jit-test| test-also-no-wasm-baseline; exitstatus: 3
 // Checking in debug frame is initialized properly during stack overflow.
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
     quit(3);
 
 var dbg;
 (function () { dbg = new (newGlobal().Debugger)(this); })();
 
 if (!wasmIsSupported())
      throw "TestComplete";
 
--- a/js/src/jit-test/tests/debug/bug1343579.js
+++ b/js/src/jit-test/tests/debug/bug1343579.js
@@ -1,13 +1,16 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Checking if Debugger.Script.isInCatchScope return false for wasm.
 
 load(libdir + "wasm.js");
 
+if (!wasmDebuggingIsSupported())
+    quit();
+
 var results;
 wasmRunWithDebugger(
     '(module (memory 1) ' +
     '(func $func0 i32.const 1000000 i32.load drop) ' +
     '(func (export "test") call $func0))',
     undefined,
     function ({dbg, wasmScript}) {
         results = [];
--- a/js/src/jit-test/tests/debug/bug1351059.js
+++ b/js/src/jit-test/tests/debug/bug1351059.js
@@ -1,14 +1,14 @@
 // Tests that onEnterFrame events are enabled when Debugger callbacks set
 // before Instance creation.
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
   quit();
 
 var g = newGlobal();
 g.parent = this;
 g.onEnterFrameCalled = false;
 g.eval(`
     var dbg = new Debugger(parent);
     dbg.onEnterFrame = frame => {
--- a/js/src/jit-test/tests/debug/wasm-01.js
+++ b/js/src/jit-test/tests/debug/wasm-01.js
@@ -1,11 +1,11 @@
 // Tests that wasm module scripts are available via findScripts.
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
   quit();
 
 var g = newGlobal();
 g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func) (export "" 0))')));`);
 
 function isWasm(script) { return script.format === "wasm"; }
 
 var dbg = new Debugger(g);
--- a/js/src/jit-test/tests/debug/wasm-02.js
+++ b/js/src/jit-test/tests/debug/wasm-02.js
@@ -1,11 +1,11 @@
 // Tests that wasm module scripts are available via onNewScript.
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
   quit();
 
 var g = newGlobal();
 var dbg = new Debugger(g);
 
 var gotScript;
 dbg.onNewScript = (script) => {
   gotScript = script;
--- a/js/src/jit-test/tests/debug/wasm-03.js
+++ b/js/src/jit-test/tests/debug/wasm-03.js
@@ -1,13 +1,13 @@
 // Tests that wasm module scripts have synthesized sources.
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
   quit();
 
 var g = newGlobal();
 var dbg = new Debugger(g);
 
 var s;
 dbg.onNewScript = (script) => {
   s = script;
--- a/js/src/jit-test/tests/debug/wasm-04.js
+++ b/js/src/jit-test/tests/debug/wasm-04.js
@@ -1,13 +1,13 @@
 // Tests that wasm module scripts throw for everything except text.
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
   quit();
 
 var g = newGlobal();
 var dbg = new Debugger(g);
 
 var s;
 dbg.onNewScript = (script) => {
   s = script;
--- a/js/src/jit-test/tests/debug/wasm-05.js
+++ b/js/src/jit-test/tests/debug/wasm-05.js
@@ -1,15 +1,15 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Tests that wasm module scripts have text line to bytecode offset information
 // when source text is generated.
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
      quit();
 
 // Checking if experimental format generates internal source map to binary file
 // by querying debugger scripts getLineOffsets.
 // (Notice that the source map will not be produced by wasmBinaryToText)
 function getAllOffsets(wast) {
   var sandbox = newGlobal('');
   var dbg = new Debugger();
--- a/js/src/jit-test/tests/debug/wasm-06-onEnterFrame-null.js
+++ b/js/src/jit-test/tests/debug/wasm-06-onEnterFrame-null.js
@@ -1,14 +1,14 @@
-// |jit-test| test-also-wasm-baseline; exitstatus: 3
+// |jit-test| test-also-no-wasm-baseline; exitstatus: 3
 // Checking resumption values for 'null' at onEnterFrame.
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
      quit(3);
 
 var g = newGlobal('');
 var dbg = new Debugger();
 dbg.addDebuggee(g);
 sandbox.eval(`
 var wasm = wasmTextToBinary('(module (func (nop)) (export "test" 0))');
 var m = new WebAssembly.Instance(new WebAssembly.Module(wasm));`);
--- a/js/src/jit-test/tests/debug/wasm-06-onPop-null.js
+++ b/js/src/jit-test/tests/debug/wasm-06-onPop-null.js
@@ -1,15 +1,15 @@
-// |jit-test| test-also-wasm-baseline; exitstatus: 3
+// |jit-test| test-also-no-wasm-baseline; exitstatus: 3
 // Checking resumption values for 'null' at frame's onPop.
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
-     quit(3);
+if (!wasmDebuggingIsSupported())
+    quit(3);
 
 var g = newGlobal('');
 var dbg = new Debugger();
 dbg.addDebuggee(g);
 sandbox.eval(`
 var wasm = wasmTextToBinary('(module (func (nop)) (export "test" 0))');
 var m = new WebAssembly.Instance(new WebAssembly.Module(wasm));`);
 dbg.onEnterFrame = function (frame) {
--- a/js/src/jit-test/tests/debug/wasm-06.js
+++ b/js/src/jit-test/tests/debug/wasm-06.js
@@ -1,15 +1,15 @@
-// |jit-test| test-also-wasm-baseline; error: TestComplete
+// |jit-test| test-also-no-wasm-baseline; error: TestComplete
 // Tests that wasm module scripts raises onEnterFrame and onLeaveFrame events.
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
-     throw "TestComplete";
+if (!wasmDebuggingIsSupported())
+    throw "TestComplete";
 
 function runWasmWithDebugger(wast, lib, init, done) {
     let g = newGlobal('');
     let dbg = new Debugger(g);
 
     g.eval(`
 var wasm = wasmTextToBinary('${wast}');
 var lib = ${lib || 'undefined'};
--- a/js/src/jit-test/tests/debug/wasm-07.js
+++ b/js/src/jit-test/tests/debug/wasm-07.js
@@ -1,15 +1,18 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Checking existence of all frame.offset references during onEnterFrame,
 // onLeaveFrame and onStep events in the source code, and that we can
 // potentially resolve offset back to the line/column.
 
 load(libdir + "wasm.js");
 
+if (!wasmDebuggingIsSupported())
+    quit();
+
 var offsets;
 wasmRunWithDebugger(
     '(module (func (nop) (nop)) (export "test" 0))',
     undefined,
     function ({dbg}) {
         offsets = [];
         dbg.onEnterFrame = function (frame) {
             if (frame.type != 'wasmcall') return;
--- a/js/src/jit-test/tests/debug/wasm-08.js
+++ b/js/src/jit-test/tests/debug/wasm-08.js
@@ -1,13 +1,16 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Checking if we destroying work registers by breakpoint/step handler.
 
 load(libdir + "wasm.js");
 
+if (!wasmDebuggingIsSupported())
+    quit();
+
 // Running the following code compiled from C snippet:
 //
 //     signed func0(signed n) {
 //         double a = 1; float b = 0; signed c = 1; long long d = 1;
 //         for (;n > 0; n--) {
 //             a *= c; b += c; c++; d <<= 1;
 //         }
 //         return (signed)a + (signed)b + c + (signed)d;
--- a/js/src/jit-test/tests/debug/wasm-09.js
+++ b/js/src/jit-test/tests/debug/wasm-09.js
@@ -1,15 +1,15 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Tests debugEnabled state of wasm when allowUnobservedAsmJS == true.
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
-     quit();
+if (!wasmDebuggingIsSupported())
+    quit();
 
 // Checking that there are no offsets are present in a wasm instance script for
 // which debug mode was not enabled.
 function getWasmScriptWithoutAllowUnobservedAsmJS(wast) {
     var sandbox = newGlobal('');
     var dbg = new Debugger();
     dbg.allowUnobservedAsmJS = true;
     dbg.addDebuggee(sandbox);
--- a/js/src/jit-test/tests/debug/wasm-10.js
+++ b/js/src/jit-test/tests/debug/wasm-10.js
@@ -1,14 +1,17 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Tests that wasm module scripts has inspectable locals.
 
 load(libdir + "wasm.js");
 load(libdir + 'eqArrayHelper.js');
 
+if (!wasmDebuggingIsSupported())
+    quit();
+
 function monitorLocalValues(wast, lib, expected) {
     function setupFrame(frame) {
         var locals = {};
         framesLocals.push(locals);
         frame.environment.names().forEach(n => {
             locals[n] = [frame.environment.getVariable(n)];
         });
         frame.onStep = function () {
--- a/js/src/jit-test/tests/debug/wasm-11.js
+++ b/js/src/jit-test/tests/debug/wasm-11.js
@@ -1,12 +1,13 @@
+// |jit-test| test-also-no-wasm-baseline
 // Test single-stepping where the TLS register can be evicted by a non-trivial
 // function body.
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
   quit();
 
 var g = newGlobal();
 g.parent = this;
 g.eval(`
     var dbg = new Debugger(parent);
 `);
 
--- a/js/src/jit-test/tests/debug/wasm-12.js
+++ b/js/src/jit-test/tests/debug/wasm-12.js
@@ -1,11 +1,12 @@
+// |jit-test| test-also-no-wasm-baseline
 // Tests that wasm module scripts have special URLs.
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
   quit();
 
 var g = newGlobal();
 g.eval(`
 function initWasm(s) { return new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(s))); }
 o1 = initWasm('(module (func) (export "" 0))');
 o2 = initWasm('(module (func) (func) (export "" 1))');
 `);
--- a/js/src/jit-test/tests/debug/wasm-13.js
+++ b/js/src/jit-test/tests/debug/wasm-13.js
@@ -1,9 +1,9 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Tests that wasm module scripts has inspectable globals and memory.
 
 load(libdir + "wasm.js");
 load(libdir + 'eqArrayHelper.js');
 
 function monitorGlobalValues(wast, lib, expected) {
     function setupFrame(frame) {
         var globals = {};
--- a/js/src/jit-test/tests/debug/wasm-binary-sources.js
+++ b/js/src/jit-test/tests/debug/wasm-binary-sources.js
@@ -1,14 +1,14 @@
 // Tests that wasm module scripts have access to binary sources.
 
 load(libdir + "asserts.js");
 load(libdir + "array-compare.js");
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
   quit();
 
 var g = newGlobal();
 var dbg = new Debugger(g);
 
 var s;
 dbg.onNewScript = (script) => {
   s = script;
--- a/js/src/jit-test/tests/debug/wasm-breakpoint.js
+++ b/js/src/jit-test/tests/debug/wasm-breakpoint.js
@@ -1,13 +1,16 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Tests that wasm module scripts handles basic breakpoint operations.
 
 load(libdir + "wasm.js");
 
+if (!wasmDebuggingIsSupported())
+    quit();
+
 // Checking if we can stop at specified breakpoint.
 var onBreakpointCalled;
 wasmRunWithDebugger(
     '(module (func (nop) (nop)) (export "test" 0))',
     undefined,
     function ({wasmScript}) {
         var breakpoints = wasmGetScriptBreakpoints(wasmScript);
         assertEq(breakpoints.length, 3);
--- a/js/src/jit-test/tests/debug/wasm-get-return.js
+++ b/js/src/jit-test/tests/debug/wasm-get-return.js
@@ -1,14 +1,17 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Tests that wasm frame opPop event can access function resumption value.
 
 load(libdir + "wasm.js");
 load(libdir + 'eqArrayHelper.js');
 
+if (!wasmDebuggingIsSupported())
+  quit();
+
 function monitorFrameOnPopReturns(wast, expected) {
     var values = [];
     wasmRunWithDebugger(
         wast,
         undefined,
         function ({dbg}) {
             dbg.onEnterFrame = function (frame) {
                 if (frame.type != 'wasmcall') return;
--- a/js/src/jit-test/tests/debug/wasm-getAllColumnOffsets.js
+++ b/js/src/jit-test/tests/debug/wasm-getAllColumnOffsets.js
@@ -1,15 +1,15 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Tests that wasm module scripts have column and line to bytecode offset
 // information when source text is generated.
 
 load(libdir + "asserts.js");
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
      quit();
 
 // Checking if experimental format generates internal source map to binary file
 // by querying debugger scripts getAllColumnOffsets.
 // (Notice that the source map will not be produced by wasmBinaryToText)
 function getAllOffsets(wast) {
   var sandbox = newGlobal('');
   var dbg = new Debugger();
--- a/js/src/jit-test/tests/debug/wasm-jseval.js
+++ b/js/src/jit-test/tests/debug/wasm-jseval.js
@@ -1,9 +1,9 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Tests that JS can be evaluated on wasm module scripts frames.
 
 load(libdir + "wasm.js");
 
 wasmRunWithDebugger(
     '(module (memory 1 1)\
      (global (mut f64) (f64.const 0.5))\
      (global f32 (f32.const 3.5))\
--- a/js/src/jit-test/tests/debug/wasm-onExceptionUnwind-gc.js
+++ b/js/src/jit-test/tests/debug/wasm-onExceptionUnwind-gc.js
@@ -1,10 +1,10 @@
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
     quit();
 
 var sandbox = newGlobal();
 var dbg = new Debugger(sandbox);
 var counter = 0;
 dbg.onExceptionUnwind = (frame, value) => {
     if (frame.type !== "wasmcall")
         return;
--- a/js/src/jit-test/tests/debug/wasm-sourceMappingURL.js
+++ b/js/src/jit-test/tests/debug/wasm-sourceMappingURL.js
@@ -1,12 +1,12 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Tests that wasm module sourceMappingURL section is parsed.
 
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
   quit();
 
 load(libdir + "asserts.js");
 load(libdir + "wasm-binary.js");
 
 var g = newGlobal();
 var dbg = new Debugger(g);
 
--- a/js/src/jit-test/tests/debug/wasm-step.js
+++ b/js/src/jit-test/tests/debug/wasm-step.js
@@ -1,13 +1,16 @@
-// |jit-test| test-also-wasm-baseline
+// |jit-test| test-also-no-wasm-baseline
 // Tests that wasm module scripts raises onEnterFrame and onLeaveFrame events.
 
 load(libdir + "wasm.js");
 
+if (!wasmDebuggingIsSupported())
+    quit();
+
 // Checking if we stop at every wasm instruction during step.
 var onEnterFrameCalled, onLeaveFrameCalled, onStepCalled;
 wasmRunWithDebugger(
     '(module (func (nop) (nop)) (export "test" 0))',
     undefined,
     function ({dbg}) {
         onEnterFrameCalled = 0;
         onLeaveFrameCalled = 0;
@@ -57,9 +60,8 @@ wasmRunWithDebugger(
     },
     function ({error}) {
         assertEq(error, undefined);
         assertEq(onEnterFrameCalled, 1);
         assertEq(onLeaveFrameCalled, 0);
         assertEq(onStepCalled.length, 0);
     }
 );
-
--- a/js/src/jit-test/tests/wasm/bench/directives.txt
+++ b/js/src/jit-test/tests/wasm/bench/directives.txt
@@ -1,1 +1,1 @@
-|jit-test| test-also-wasm-baseline; test-also-wasm-check-bce; include:wasm.js
+|jit-test| test-also-no-wasm-baseline; test-also-wasm-check-bce; include:wasm.js
--- a/js/src/jit-test/tests/wasm/directives.txt
+++ b/js/src/jit-test/tests/wasm/directives.txt
@@ -1,1 +1,1 @@
-|jit-test| test-also-wasm-baseline; include:wasm.js
+|jit-test| test-also-no-wasm-baseline; include:wasm.js
--- a/js/src/jit-test/tests/wasm/extract-code.js
+++ b/js/src/jit-test/tests/wasm/extract-code.js
@@ -1,10 +1,10 @@
 var module = new WebAssembly.Module(wasmTextToBinary(`(module (func (nop)))`));
-var exp = wasmExtractCode(module);
+var exp = wasmExtractCode(module, "stable");
 assertEq(exp.code instanceof Uint8Array, true);
 assertEq(Array.isArray(exp.segments), true);
 var funcs = exp.segments.filter(s => s.kind === 0);
 assertEq(funcs.length, 1);
 assertEq(funcs[0].funcIndex, 0);
 assertEq(funcs[0].begin >= 0, true);
 assertEq(funcs[0].begin <= funcs[0].funcBodyBegin, true);
 assertEq(funcs[0].funcBodyBegin < funcs[0].funcBodyEnd, true);
--- a/js/src/jit-test/tests/wasm/regress/directives.txt
+++ b/js/src/jit-test/tests/wasm/regress/directives.txt
@@ -1,1 +1,1 @@
-|jit-test| test-also-wasm-baseline; include:wasm.js
+|jit-test| test-also-no-wasm-baseline; include:wasm.js
--- a/js/src/jit-test/tests/wasm/spec/directives.txt
+++ b/js/src/jit-test/tests/wasm/spec/directives.txt
@@ -1,1 +1,1 @@
-|jit-test| test-also-wasm-baseline; include:wasm-testharness.js
+|jit-test| test-also-no-wasm-baseline; include:wasm-testharness.js
--- a/js/src/jit-test/tests/wasm/timeout/debug-interrupt-1.js
+++ b/js/src/jit-test/tests/wasm/timeout/debug-interrupt-1.js
@@ -1,13 +1,13 @@
 // |jit-test| exitstatus: 6;
 
 // Don't include wasm.js in timeout tests: when wasm isn't supported, it will
 // quit(0) which will cause the test to fail.
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
     quit(6);
 
 var g = newGlobal();
 g.parent = this;
 g.eval("Debugger(parent).onEnterFrame = function() {};");
 timeout(0.01);
 var code = wasmTextToBinary(`(module
     (func (export "f1")
--- a/js/src/jit-test/tests/wasm/timeout/debug-interrupt-2.js
+++ b/js/src/jit-test/tests/wasm/timeout/debug-interrupt-2.js
@@ -1,13 +1,13 @@
 // |jit-test| exitstatus: 6;
 
 // Don't include wasm.js in timeout tests: when wasm isn't supported, it will
 // quit(0) which will cause the test to fail.
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
     quit(6);
 
 var g = newGlobal();
 g.parent = this;
 g.eval("Debugger(parent).onEnterFrame = function() {};");
 timeout(0.01);
 var code = wasmTextToBinary(`(module
     (func $f2
--- a/js/src/jit-test/tests/wasm/timeout/debug-noprofiling.js
+++ b/js/src/jit-test/tests/wasm/timeout/debug-noprofiling.js
@@ -1,13 +1,13 @@
 // |jit-test| exitstatus: 6;
 
 // Don't include wasm.js in timeout tests: when wasm isn't supported, it will
 // quit(0) which will cause the test to fail.
-if (!wasmIsSupported())
+if (!wasmDebuggingIsSupported())
     quit(6);
 
 newGlobal().Debugger().addDebuggee(this);
 
 var t = new WebAssembly.Table({
     initial: 1,
     element: "anyfunc"
 });
--- a/js/src/jit-test/tests/wasm/timeout/directives.txt
+++ b/js/src/jit-test/tests/wasm/timeout/directives.txt
@@ -1,2 +1,2 @@
-|jit-test| test-also-wasm-baseline
+|jit-test| test-also-no-wasm-baseline
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11897,28 +11897,32 @@ CodeGenerator::visitSetDOMProperty(LSetD
 
     masm.adjustStack(IonDOMExitFrameLayout::Size());
 
     MOZ_ASSERT(masm.framePushed() == initialStack);
 }
 
 class OutOfLineIsCallable : public OutOfLineCodeBase<CodeGenerator>
 {
-    LIsCallable* ins_;
+    Register object_;
+    Register output_;
 
   public:
-    explicit OutOfLineIsCallable(LIsCallable* ins)
-      : ins_(ins)
+    OutOfLineIsCallable(Register object, Register output)
+      : object_(object), output_(output)
     { }
 
     void accept(CodeGenerator* codegen) {
         codegen->visitOutOfLineIsCallable(this);
     }
-    LIsCallable* ins() const {
-        return ins_;
+    Register object() const {
+        return object_;
+    }
+    Register output() const {
+        return output_;
     }
 };
 
 template <CodeGenerator::CallableOrConstructor mode>
 void
 CodeGenerator::emitIsCallableOrConstructor(Register object, Register output, Label* failure)
 {
     Label notFunction, hasCOps, done;
@@ -11961,35 +11965,57 @@ CodeGenerator::emitIsCallableOrConstruct
                        : offsetof(js::ClassOps, construct);
     masm.cmpPtrSet(Assembler::NonZero, Address(output, opsOffset),
                    ImmPtr(nullptr), output);
 
     masm.bind(&done);
 }
 
 void
-CodeGenerator::visitIsCallable(LIsCallable* ins)
+CodeGenerator::visitIsCallableO(LIsCallableO* ins)
 {
     Register object = ToRegister(ins->object());
     Register output = ToRegister(ins->output());
 
-    OutOfLineIsCallable* ool = new(alloc()) OutOfLineIsCallable(ins);
+    OutOfLineIsCallable* ool = new(alloc()) OutOfLineIsCallable(object, output);
     addOutOfLineCode(ool, ins->mir());
 
     emitIsCallableOrConstructor<Callable>(object, output, ool->entry());
 
     masm.bind(ool->rejoin());
 }
 
 void
+CodeGenerator::visitIsCallableV(LIsCallableV* ins)
+{
+    ValueOperand val = ToValue(ins, LIsCallableV::Value);
+    Register output = ToRegister(ins->output());
+    Register temp = ToRegister(ins->temp());
+
+    Label notObject;
+    masm.branchTestObject(Assembler::NotEqual, val, &notObject);
+    masm.unboxObject(val, temp);
+
+    OutOfLineIsCallable* ool = new(alloc()) OutOfLineIsCallable(temp, output);
+    addOutOfLineCode(ool, ins->mir());
+
+    emitIsCallableOrConstructor<Callable>(temp, output, ool->entry());
+    masm.jump(ool->rejoin());
+
+    masm.bind(&notObject);
+    masm.move32(Imm32(0), output);
+
+    masm.bind(ool->rejoin());
+}
+
+void
 CodeGenerator::visitOutOfLineIsCallable(OutOfLineIsCallable* ool)
 {
-    LIsCallable* ins = ool->ins();
-    Register object = ToRegister(ins->object());
-    Register output = ToRegister(ins->output());
+    Register object = ool->object();
+    Register output = ool->output();
 
     saveVolatile(output);
     masm.setupUnalignedABICall(output);
     masm.passABIArg(object);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectIsCallable));
     masm.storeCallBoolResult(output);
     restoreVolatile(output);
     masm.jump(ool->rejoin());
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -381,17 +381,18 @@ class CodeGenerator final : public CodeG
     void visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir);
     void visitCallBindVar(LCallBindVar* lir);
     enum CallableOrConstructor {
         Callable,
         Constructor
     };
     template <CallableOrConstructor mode>
     void emitIsCallableOrConstructor(Register object, Register output, Label* failure);
-    void visitIsCallable(LIsCallable* lir);
+    void visitIsCallableO(LIsCallableO* lir);
+    void visitIsCallableV(LIsCallableV* lir);
     void visitOutOfLineIsCallable(OutOfLineIsCallable* ool);
     void visitIsConstructor(LIsConstructor* lir);
     void visitOutOfLineIsConstructor(OutOfLineIsConstructor* ool);
     void visitIsArrayO(LIsArrayO* lir);
     void visitIsArrayV(LIsArrayV* lir);
     void visitIsTypedArray(LIsTypedArray* lir);
     void visitIsObject(LIsObject* lir);
     void visitIsObjectAndBranch(LIsObjectAndBranch* lir);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4354,19 +4354,24 @@ LIRGenerator::visitIsTypedArray(MIsTyped
 
     auto* lir = new(alloc()) LIsTypedArray(useRegister(ins->value()));
     define(lir, ins);
 }
 
 void
 LIRGenerator::visitIsCallable(MIsCallable* ins)
 {
-    MOZ_ASSERT(ins->object()->type() == MIRType::Object);
     MOZ_ASSERT(ins->type() == MIRType::Boolean);
-    define(new(alloc()) LIsCallable(useRegister(ins->object())), ins);
+
+    if (ins->object()->type() == MIRType::Object) {
+        define(new(alloc()) LIsCallableO(useRegister(ins->object())), ins);
+    } else {
+        MOZ_ASSERT(ins->object()->type() == MIRType::Value);
+        define(new(alloc()) LIsCallableV(useBox(ins->object()), temp()), ins);
+    }
 }
 
 void
 LIRGenerator::visitIsConstructor(MIsConstructor* ins)
 {
     MOZ_ASSERT(ins->object()->type() == MIRType::Object);
     MOZ_ASSERT(ins->type() == MIRType::Boolean);
     define(new(alloc()) LIsConstructor(useRegister(ins->object())), ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -2977,35 +2977,34 @@ IonBuilder::inlineIsCallable(CallInfo& c
         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
         return InliningStatus_NotInlined;
     }
 
     if (getInlineReturnType() != MIRType::Boolean)
         return InliningStatus_NotInlined;
 
     MDefinition* arg = callInfo.getArg(0);
-    // Do not inline if the type of arg is neither primitive nor object.
-    if (arg->type() > MIRType::Object)
-        return InliningStatus_NotInlined;
 
     // Try inlining with constant true/false: only objects may be callable at
     // all, and if we know the class check if it is callable.
     bool isCallableKnown = false;
     bool isCallableConstant;
-    if (arg->type() != MIRType::Object) {
-        // Primitive (including undefined and null).
-        isCallableKnown = true;
-        isCallableConstant = false;
-    } else {
+    if (arg->type() == MIRType::Object) {
         TemporaryTypeSet* types = arg->resultTypeSet();
         const Class* clasp = types ? types->getKnownClass(constraints()) : nullptr;
         if (clasp && !clasp->isProxy()) {
             isCallableKnown = true;
             isCallableConstant = clasp->nonProxyCallable();
         }
+    } else if (!arg->mightBeType(MIRType::Object)) {
+        // Primitive (including undefined and null).
+        isCallableKnown = true;
+        isCallableConstant = false;
+    } else if (arg->type() != MIRType::Value) {
+        return InliningStatus_NotInlined;
     }
 
     callInfo.setImplicitlyUsedUnchecked();
 
     if (isCallableKnown) {
         MConstant* constant = MConstant::New(alloc(), BooleanValue(isCallableConstant));
         current->add(constant);
         current->push(constant);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -13439,21 +13439,22 @@ class MResumePoint final :
     }
 
     virtual void dump(GenericPrinter& out) const override;
     virtual void dump() const override;
 };
 
 class MIsCallable
   : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
+    public BoxExceptPolicy<0, MIRType::Object>::Data
 {
     explicit MIsCallable(MDefinition* object)
       : MUnaryInstruction(object)
     {
+        MOZ_ASSERT(object->type() == MIRType::Object || object->type() == MIRType::Value);
         setResultType(MIRType::Boolean);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(IsCallable)
     TRIVIAL_NEW_WRAPPERS
     NAMED_OPERANDS((0, object))
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -1592,17 +1592,24 @@ bool
 Simulator::handleWasmFault(int32_t addr, unsigned numBytes)
 {
     WasmActivation* act = wasm::ActivationIfInnermost(cx_);
     if (!act)
         return false;
 
     void* pc = reinterpret_cast<void*>(get_pc());
     uint8_t* fp = reinterpret_cast<uint8_t*>(get_register(r11));
-    wasm::Instance* instance = wasm::LookupFaultingInstance(act, pc, fp);
+
+    // Cache the wasm::Code to avoid lookup on every load/store.
+    if (!wasm_code_ || !wasm_code_->containsCodePC(pc))
+        wasm_code_ = act->compartment()->wasm.lookupCode(pc);
+    if (!wasm_code_)
+        return false;
+
+    wasm::Instance* instance = wasm::LookupFaultingInstance(*wasm_code_, pc, fp);
     if (!instance || !instance->memoryAccessInGuardRegion((uint8_t*)addr, numBytes))
         return false;
 
     const wasm::CodeSegment* segment;
     const wasm::MemoryAccess* memoryAccess = instance->code().lookupMemoryAccess(pc, &segment);
     if (!memoryAccess) {
         startInterrupt(act);
         if (!instance->code().containsCodePC(pc, &segment))
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -33,16 +33,17 @@
 
 #include "mozilla/Atomics.h"
 
 #include "jit/arm/Architecture-arm.h"
 #include "jit/arm/disasm/Disasm-arm.h"
 #include "jit/IonTypes.h"
 #include "threading/Thread.h"
 #include "vm/MutexIDs.h"
+#include "wasm/WasmCode.h"
 
 namespace js {
 
 class WasmActivation;
 
 namespace jit {
 
 class Simulator;
@@ -418,18 +419,19 @@ class Simulator
     bool inexact_vfp_flag_;
 
     // Simulator support.
     char* stack_;
     uintptr_t stackLimit_;
     bool pc_modified_;
     int64_t icount_;
 
-    // wasm async interrupt support
+    // wasm async interrupt / fault support
     bool wasm_interrupt_;
+    wasm::SharedCode wasm_code_;
 
     // Debugger input.
     char* lastDebuggerInput_;
 
     // Registered breakpoints.
     SimInstruction* break_pc_;
     Instr break_instr_;
 
--- a/js/src/jit/mips64/MacroAssembler-mips64.cpp
+++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp
@@ -1852,20 +1852,26 @@ MacroAssemblerMIPS64Compat::storeValue(V
     storePtr(val.valueReg(), Address(dest.base, dest.offset));
 }
 
 void
 MacroAssemblerMIPS64Compat::storeValue(JSValueType type, Register reg, Address dest)
 {
     MOZ_ASSERT(dest.base != SecondScratchReg);
 
-    ma_li(SecondScratchReg, ImmTag(JSVAL_TYPE_TO_TAG(type)));
-    ma_dsll(SecondScratchReg, SecondScratchReg, Imm32(JSVAL_TAG_SHIFT));
-    ma_dins(SecondScratchReg, reg, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
-    storePtr(SecondScratchReg, Address(dest.base, dest.offset));
+    if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
+        store32(reg, dest);
+        JSValueShiftedTag tag = (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type);
+        store32(((Imm64(tag)).secondHalf()), Address(dest.base, dest.offset + 4));
+    } else {
+        ma_li(SecondScratchReg, ImmTag(JSVAL_TYPE_TO_TAG(type)));
+        ma_dsll(SecondScratchReg, SecondScratchReg, Imm32(JSVAL_TAG_SHIFT));
+        ma_dins(SecondScratchReg, reg, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
+        storePtr(SecondScratchReg, Address(dest.base, dest.offset));
+    }
 }
 
 void
 MacroAssemblerMIPS64Compat::storeValue(const Value& val, Address dest)
 {
     if (val.isGCThing()) {
         writeDataRelocation(val);
         movWithPatch(ImmWord(val.asRawBits()), SecondScratchReg);
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -8003,32 +8003,50 @@ class LCallInstanceOf : public LCallInst
     const LAllocation* rhs() {
         return getOperand(RHS);
     }
 
     static const size_t LHS = 0;
     static const size_t RHS = BOX_PIECES;
 };
 
-class LIsCallable : public LInstructionHelper<1, 1, 0>
-{
-  public:
-    LIR_HEADER(IsCallable);
-    explicit LIsCallable(const LAllocation& object) {
+class LIsCallableO : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(IsCallableO);
+    explicit LIsCallableO(const LAllocation& object) {
         setOperand(0, object);
     }
 
     const LAllocation* object() {
         return getOperand(0);
     }
     MIsCallable* mir() const {
         return mir_->toIsCallable();
     }
 };
 
+class LIsCallableV : public LInstructionHelper<1, BOX_PIECES, 1>
+{
+  public:
+    LIR_HEADER(IsCallableV);
+    static const size_t Value = 0;
+
+    LIsCallableV(const LBoxAllocation& value, const LDefinition& temp) {
+        setBoxOperand(0, value);
+        setTemp(0, temp);
+    }
+    const LDefinition* temp() {
+        return getTemp(0);
+    }
+    MIsCallable* mir() const {
+        return mir_->toIsCallable();
+    }
+};
+
 class LIsConstructor : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(IsConstructor);
     explicit LIsConstructor(const LAllocation& object) {
         setOperand(0, object);
     }
 
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -385,17 +385,18 @@
     _(InterruptCheck)               \
     _(Rotate)                       \
     _(RotateI64)                    \
     _(GetDOMProperty)               \
     _(GetDOMMemberV)                \
     _(GetDOMMemberT)                \
     _(SetDOMProperty)               \
     _(CallDOMNative)                \
-    _(IsCallable)                   \
+    _(IsCallableO)                  \
+    _(IsCallableV)                  \
     _(IsConstructor)                \
     _(IsArrayO)                     \
     _(IsArrayV)                     \
     _(IsTypedArray)                 \
     _(IsObject)                     \
     _(IsObjectAndBranch)            \
     _(HasClass)                     \
     _(ObjectClassToString)          \
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1145,17 +1145,18 @@ namespace JS {
 
 class JS_PUBLIC_API(ContextOptions) {
   public:
     ContextOptions()
       : baseline_(true),
         ion_(true),
         asmJS_(true),
         wasm_(false),
-        wasmAlwaysBaseline_(false),
+        wasmBaseline_(false),
+        wasmIon_(false),
         throwOnAsmJSValidationFailure_(false),
         nativeRegExp_(true),
         unboxedArrays_(false),
         asyncStack_(true),
         throwOnDebuggeeWouldRun_(true),
         dumpStackOnDebuggeeWouldRun_(false),
         werror_(false),
         strictMode_(false),
@@ -1209,23 +1210,33 @@ class JS_PUBLIC_API(ContextOptions) {
         streams_ = flag;
         return *this;
     }
     ContextOptions& toggleStreams() {
         streams_ = !streams_;
         return *this;
     }
 
-    bool wasmAlwaysBaseline() const { return wasmAlwaysBaseline_; }
-    ContextOptions& setWasmAlwaysBaseline(bool flag) {
-        wasmAlwaysBaseline_ = flag;
+    bool wasmBaseline() const { return wasmBaseline_; }
+    ContextOptions& setWasmBaseline(bool flag) {
+        wasmBaseline_ = flag;
+        return *this;
+    }
+    ContextOptions& toggleWasmBaseline() {
+        wasmBaseline_ = !wasmBaseline_;
         return *this;
     }
-    ContextOptions& toggleWasmAlwaysBaseline() {
-        wasmAlwaysBaseline_ = !wasmAlwaysBaseline_;
+
+    bool wasmIon() const { return wasmIon_; }
+    ContextOptions& setWasmIon(bool flag) {
+        wasmIon_ = flag;
+        return *this;
+    }
+    ContextOptions& toggleWasmIon() {
+        wasmIon_ = !wasmIon_;
         return *this;
     }
 
     bool throwOnAsmJSValidationFailure() const { return throwOnAsmJSValidationFailure_; }
     ContextOptions& setThrowOnAsmJSValidationFailure(bool flag) {
         throwOnAsmJSValidationFailure_ = flag;
         return *this;
     }
@@ -1308,17 +1319,18 @@ class JS_PUBLIC_API(ContextOptions) {
     }
 #endif
 
   private:
     bool baseline_ : 1;
     bool ion_ : 1;
     bool asmJS_ : 1;
     bool wasm_ : 1;
-    bool wasmAlwaysBaseline_ : 1;
+    bool wasmBaseline_ : 1;
+    bool wasmIon_ : 1;
     bool throwOnAsmJSValidationFailure_ : 1;
     bool nativeRegExp_ : 1;
     bool unboxedArrays_ : 1;
     bool asyncStack_ : 1;
     bool throwOnDebuggeeWouldRun_ : 1;
     bool dumpStackOnDebuggeeWouldRun_ : 1;
     bool werror_ : 1;
     bool strictMode_ : 1;
@@ -1968,16 +1980,33 @@ typedef enum JSGCParamKey {
 
     /**
      * If true, painting can trigger IGC slices.
      *
      * Pref: javascript.options.mem.gc_refresh_frame_slices_enabled
      * Default: RefreshFrameSlicesEnabled
      */
     JSGC_REFRESH_FRAME_SLICES_ENABLED = 24,
+
+    /**
+     * Factor for triggering a GC based on JSGC_ALLOCATION_THRESHOLD
+     *
+     * Default: ZoneAllocThresholdFactorDefault
+     * Pref: None
+     */
+    JSGC_ALLOCATION_THRESHOLD_FACTOR = 25,
+
+    /**
+     * Factor for triggering a GC based on JSGC_ALLOCATION_THRESHOLD.
+     * Used if another GC (in different zones) is already running.
+     *
+     * Default: ZoneAllocThresholdFactorAvoidInterruptDefault
+     * Pref: None
+     */
+    JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT = 26,
 } JSGCParamKey;
 
 extern JS_PUBLIC_API(void)
 JS_SetGCParameter(JSContext* cx, JSGCParamKey key, uint32_t value);
 
 extern JS_PUBLIC_API(void)
 JS_ResetGCParameter(JSContext* cx, JSGCParamKey key);
 
--- a/js/src/jsatominlines.h
+++ b/js/src/jsatominlines.h
@@ -59,18 +59,18 @@ ValueToIdPure(const Value& v, jsid* id)
     }
 
     int32_t i;
     if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) {
         *id = INT_TO_JSID(i);
         return true;
     }
 
-    if (js::IsSymbolOrSymbolWrapper(v)) {
-        *id = SYMBOL_TO_JSID(js::ToSymbolPrimitive(v));
+    if (v.isSymbol()) {
+        *id = SYMBOL_TO_JSID(v.toSymbol());
         return true;
     }
 
     return false;
 }
 
 template <AllowGC allowGC>
 inline bool
@@ -84,18 +84,18 @@ ValueToId(JSContext* cx, typename MaybeR
         }
     } else {
         int32_t i;
         if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) {
             idp.set(INT_TO_JSID(i));
             return true;
         }
 
-        if (js::IsSymbolOrSymbolWrapper(v)) {
-            idp.set(SYMBOL_TO_JSID(js::ToSymbolPrimitive(v)));
+        if (v.isSymbol()) {
+            idp.set(SYMBOL_TO_JSID(v.toSymbol()));
             return true;
         }
     }
 
     JSAtom* atom = ToAtom<allowGC>(cx, v);
     if (!atom)
         return false;
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -273,17 +273,21 @@ using JS::AutoGCRooter;
  * preferences.
  */
 namespace js {
 namespace gc {
 namespace TuningDefaults {
 
     /* JSGC_ALLOCATION_THRESHOLD */
     static const size_t GCZoneAllocThresholdBase = 30 * 1024 * 1024;
+
+    /* JSGC_ALLOCATION_THRESHOLD_FACTOR */
     static const float ZoneAllocThresholdFactor = 0.9f;
+
+    /* JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT */
     static const float ZoneAllocThresholdFactorAvoidInterrupt = 0.9f;
 
     /* no parameter */
     static const size_t ZoneAllocDelayBytes = 1024 * 1024;
 
     /* JSGC_DYNAMIC_HEAP_GROWTH */
     static const bool DynamicHeapGrowthEnabled = false;
 
@@ -1337,16 +1341,30 @@ GCSchedulingTunables::setParameter(JSGCP
         dynamicHeapGrowthEnabled_ = value != 0;
         break;
       case JSGC_DYNAMIC_MARK_SLICE:
         dynamicMarkSliceEnabled_ = value != 0;
         break;
       case JSGC_ALLOCATION_THRESHOLD:
         gcZoneAllocThresholdBase_ = value * 1024 * 1024;
         break;
+      case JSGC_ALLOCATION_THRESHOLD_FACTOR: {
+        float newFactor = value / 100.0;
+        if (newFactor <= 0.1 || newFactor > 1.0)
+            return false;
+        zoneAllocThresholdFactor_ = newFactor;
+        break;
+      }
+      case JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT: {
+        float newFactor = value / 100.0;
+        if (newFactor <= 0.1 || newFactor > 1.0)
+            return false;
+        zoneAllocThresholdFactorAvoidInterrupt_ = newFactor;
+        break;
+      }
       case JSGC_MIN_EMPTY_CHUNK_COUNT:
         setMinEmptyChunkCount(value);
         break;
       case JSGC_MAX_EMPTY_CHUNK_COUNT:
         setMaxEmptyChunkCount(value);
         break;
       case JSGC_REFRESH_FRAME_SLICES_ENABLED:
         refreshFrameSlicesEnabled_ = value != 0;
@@ -1483,16 +1501,23 @@ GCSchedulingTunables::resetParameter(JSG
         dynamicHeapGrowthEnabled_ = TuningDefaults::DynamicHeapGrowthEnabled;
         break;
       case JSGC_DYNAMIC_MARK_SLICE:
         dynamicMarkSliceEnabled_ = TuningDefaults::DynamicMarkSliceEnabled;
         break;
       case JSGC_ALLOCATION_THRESHOLD:
         gcZoneAllocThresholdBase_ = TuningDefaults::GCZoneAllocThresholdBase;
         break;
+      case JSGC_ALLOCATION_THRESHOLD_FACTOR:
+        zoneAllocThresholdFactor_ = TuningDefaults::ZoneAllocThresholdFactor;
+        break;
+      case JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT:
+        zoneAllocThresholdFactorAvoidInterrupt_ =
+            TuningDefaults::ZoneAllocThresholdFactorAvoidInterrupt;
+        break;
       case JSGC_MIN_EMPTY_CHUNK_COUNT:
         setMinEmptyChunkCount(TuningDefaults::MinEmptyChunkCount);
         break;
       case JSGC_MAX_EMPTY_CHUNK_COUNT:
         setMaxEmptyChunkCount(TuningDefaults::MaxEmptyChunkCount);
         break;
       case JSGC_REFRESH_FRAME_SLICES_ENABLED:
         refreshFrameSlicesEnabled_ = TuningDefaults::RefreshFrameSlicesEnabled;
@@ -1543,16 +1568,20 @@ GCRuntime::getParameter(JSGCParamKey key
       case JSGC_LOW_FREQUENCY_HEAP_GROWTH:
         return uint32_t(tunables.lowFrequencyHeapGrowth() * 100);
       case JSGC_DYNAMIC_HEAP_GROWTH:
         return tunables.isDynamicHeapGrowthEnabled();
       case JSGC_DYNAMIC_MARK_SLICE:
         return tunables.isDynamicMarkSliceEnabled();
       case JSGC_ALLOCATION_THRESHOLD:
         return tunables.gcZoneAllocThresholdBase() / 1024 / 1024;
+      case JSGC_ALLOCATION_THRESHOLD_FACTOR:
+        return uint32_t(tunables.zoneAllocThresholdFactor() * 100);
+      case JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT:
+        return uint32_t(tunables.zoneAllocThresholdFactorAvoidInterrupt() * 100);
       case JSGC_MIN_EMPTY_CHUNK_COUNT:
         return tunables.minEmptyChunkCount(lock);
       case JSGC_MAX_EMPTY_CHUNK_COUNT:
         return tunables.maxEmptyChunkCount();
       case JSGC_COMPACTING_ENABLED:
         return compactingEnabled;
       case JSGC_REFRESH_FRAME_SLICES_ENABLED:
         return tunables.areRefreshFrameSlicesEnabled();
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3146,17 +3146,17 @@ js::ToPrimitiveSlow(JSContext* cx, JSTyp
     RootedObject obj(cx, &vp.toObject());
 
     // Steps 4-5.
     RootedValue method(cx);
     if (!GetInterestingSymbolProperty(cx, obj, cx->wellKnownSymbols().toPrimitive, &method))
         return false;
 
     // Step 6.
-    if (!method.isUndefined()) {
+    if (!method.isNullOrUndefined()) {
         // Step 6 of GetMethod. js::Call() below would do this check and throw a
         // TypeError anyway, but this produces a better error message.
         if (!IsCallable(method))
             return ReportCantConvert(cx, JSMSG_TOPRIMITIVE_NOT_CALLABLE, obj, preferredType);
 
         // Steps 1-3, 6.a-b.
         RootedValue arg0(cx, StringValue(preferredType == JSTYPE_STRING
                                          ? cx->names().string
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -258,17 +258,18 @@ static bool enableDisassemblyDumps = fal
 static bool offthreadCompilation = false;
 static bool enableBaseline = false;
 static bool enableIon = false;
 static bool enableAsmJS = false;
 static bool enableWasm = false;
 static bool enableNativeRegExp = false;
 static bool enableUnboxedArrays = false;
 static bool enableSharedMemory = SHARED_MEMORY_DEFAULT;
-static bool enableWasmAlwaysBaseline = false;
+static bool enableWasmBaseline = false;
+static bool enableWasmIon = false;
 static bool enableAsyncStacks = false;
 static bool enableStreams = false;
 #ifdef JS_GC_ZEAL
 static uint32_t gZealBits = 0;
 static uint32_t gZealFrequency = 0;
 #endif
 static bool printTiming = false;
 static const char* jsCacheDir = nullptr;
@@ -7806,25 +7807,27 @@ static bool
 SetContextOptions(JSContext* cx, const OptionParser& op)
 {
     enableBaseline = !op.getBoolOption("no-baseline");
     enableIon = !op.getBoolOption("no-ion");
     enableAsmJS = !op.getBoolOption("no-asmjs");
     enableWasm = !op.getBoolOption("no-wasm");
     enableNativeRegExp = !op.getBoolOption("no-native-regexp");
     enableUnboxedArrays = op.getBoolOption("unboxed-arrays");
-    enableWasmAlwaysBaseline = op.getBoolOption("wasm-always-baseline");
+    enableWasmBaseline = !op.getBoolOption("no-wasm-baseline");
+    enableWasmIon = !op.getBoolOption("no-wasm-ion");
     enableAsyncStacks = !op.getBoolOption("no-async-stacks");
     enableStreams = op.getBoolOption("enable-streams");
 
     JS::ContextOptionsRef(cx).setBaseline(enableBaseline)
                              .setIon(enableIon)
                              .setAsmJS(enableAsmJS)
                              .setWasm(enableWasm)
-                             .setWasmAlwaysBaseline(enableWasmAlwaysBaseline)
+                             .setWasmBaseline(enableWasmBaseline)
+                             .setWasmIon(enableWasmIon)
                              .setNativeRegExp(enableNativeRegExp)
                              .setUnboxedArrays(enableUnboxedArrays)
                              .setAsyncStack(enableAsyncStacks)
                              .setStreams(enableStreams);
 
     if (op.getBoolOption("wasm-check-bce"))
         jit::JitOptions.wasmAlwaysCheckBounds = true;
 
@@ -8100,17 +8103,18 @@ SetContextOptions(JSContext* cx, const O
 static void
 SetWorkerContextOptions(JSContext* cx)
 {
     // Copy option values from the main thread.
     JS::ContextOptionsRef(cx).setBaseline(enableBaseline)
                              .setIon(enableIon)
                              .setAsmJS(enableAsmJS)
                              .setWasm(enableWasm)
-                             .setWasmAlwaysBaseline(enableWasmAlwaysBaseline)
+                             .setWasmBaseline(enableWasmBaseline)
+                             .setWasmIon(enableWasmIon)
                              .setNativeRegExp(enableNativeRegExp)
                              .setUnboxedArrays(enableUnboxedArrays)
                              .setStreams(enableStreams);
     cx->runtime()->setOffthreadIonCompilationEnabled(offthreadCompilation);
     cx->runtime()->profilingScripts = enableCodeCoverage || enableDisassemblyDumps;
 
 #ifdef JS_GC_ZEAL
     if (gZealBits && gZealFrequency) {
@@ -8296,20 +8300,21 @@ main(int argc, char** argv, char** envp)
                                          "String arguments to bind as |scriptArgs| in the "
                                          "shell's global")
         || !op.addIntOption('\0', "thread-count", "COUNT", "Use COUNT auxiliary threads "
                             "(default: # of cores - 1)", -1)
         || !op.addBoolOption('\0', "ion", "Enable IonMonkey (default)")
         || !op.addBoolOption('\0', "no-ion", "Disable IonMonkey")
         || !op.addBoolOption('\0', "no-asmjs", "Disable asm.js compilation")
         || !op.addBoolOption('\0', "no-wasm", "Disable WebAssembly compilation")
+        || !op.addBoolOption('\0', "no-wasm-baseline", "Disable wasm baseline compiler")
+        || !op.addBoolOption('\0', "no-wasm-ion", "Disable wasm ion compiler")
         || !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
         || !op.addBoolOption('\0', "no-unboxed-objects", "Disable creating unboxed plain objects")
         || !op.addBoolOption('\0', "unboxed-arrays", "Allow creating unboxed arrays")
-        || !op.addBoolOption('\0', "wasm-always-baseline", "Enable wasm baseline compiler when possible")
         || !op.addBoolOption('\0', "wasm-check-bce", "Always generate wasm bounds check, even redundant ones.")
         || !op.addBoolOption('\0', "wasm-test-mode", "Enable wasm testing mode, creating synthetic "
                                    "objects for non-canonical NaNs and i64 returned from wasm.")
         || !op.addBoolOption('\0', "enable-streams", "Enable WHATWG Streams")
 #ifdef ENABLE_SHARED_ARRAY_BUFFER
         || !op.addStringOption('\0', "shared-memory", "on/off",
                                "SharedArrayBuffer and Atomics "
 #  if SHARED_MEMORY_DEFAULT
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Symbol/symbol-object-not-unboxed-for-value-to-id.js
@@ -0,0 +1,31 @@
+// Create a symbol and a wrapper for it.
+var s = Symbol();
+var so = Object(s);
+
+// Create a symbol-valued property key using |s|.
+var o = {[s]: 0};
+
+// The default Symbol.prototype[@@toPrimitive] will unbox the symbol object as needed.
+assertEq(o.propertyIsEnumerable(so), true);
+assertEq(o.hasOwnProperty(so), true);
+
+// After redefining Symbol.prototype[@@toPrimitive], any calls to the ToPropertyKey
+// abstract operation will no longer unbox the symbol object.
+Object.defineProperty(Symbol.prototype, Symbol.toPrimitive, {
+    value: function() {
+        return "foo";
+    }
+});
+
+// |o| doesn't have a string-valued property named "foo".
+assertEq(o.propertyIsEnumerable(so), false);
+assertEq(o.hasOwnProperty(so), false);
+
+o.foo = 123;
+
+// After |o.foo| was added, both calls should return true again.
+assertEq(o.propertyIsEnumerable(so), true);
+assertEq(o.hasOwnProperty(so), true);
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Symbol/toPrimitive-undefined-or-null.js
@@ -0,0 +1,18 @@
+for (let method of [undefined, null]) {
+    let obj = {
+        [Symbol.toPrimitive]: method,
+        toString: () => "pass",
+    };
+    assertEq("" + obj, "pass");
+}
+
+for (let method of [true, false, 0, 123, "", "abc", Symbol(), {}]) {
+    let obj = {
+        [Symbol.toPrimitive]: method,
+        toString: () => "pass",
+    };
+    assertThrowsInstanceOf(() => "" + obj, TypeError);
+}
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);
--- a/js/src/tests/lib/jittests.py
+++ b/js/src/tests/lib/jittests.py
@@ -246,19 +246,19 @@ class JitTest:
                         test.allow_overrecursed = True
                     elif name == 'valgrind':
                         test.valgrind = options.valgrind
                     elif name == 'tz-pacific':
                         test.tz_pacific = True
                     elif name == 'test-also-noasmjs':
                         if options.asmjs_enabled:
                             test.test_also.append(['--no-asmjs'])
-                    elif name == 'test-also-wasm-baseline':
+                    elif name == 'test-also-no-wasm-baseline':
                         if options.wasm_enabled:
-                            test.test_also.append(['--wasm-always-baseline'])
+                            test.test_also.append(['--no-wasm-baseline'])
                     elif name == 'test-also-wasm-check-bce':
                         if options.wasm_enabled:
                             test.test_also.append(['--wasm-check-bce'])
                     elif name.startswith('test-also='):
                         test.test_also.append([name[len('test-also='):]])
                     elif name.startswith('test-join='):
                         test.test_join.append([name[len('test-join='):]])
                     elif name == 'module':
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -85,27 +85,86 @@ js::SetFakeCPUCount(size_t count)
     // This must be called before the threads have been initialized.
     MOZ_ASSERT(!HelperThreadState().threads);
 
     HelperThreadState().cpuCount = count;
     HelperThreadState().threadCount = ThreadCountForCPUCount(count);
 }
 
 bool
-js::StartOffThreadWasmCompile(wasm::CompileTask* task)
+js::StartOffThreadWasmCompile(wasm::CompileTask* task, wasm::CompileMode mode)
 {
     AutoLockHelperThreadState lock;
 
-    if (!HelperThreadState().wasmWorklist(lock).append(task))
+    if (!HelperThreadState().wasmWorklist(lock, mode).append(task))
+        return false;
+
+    HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
+    return true;
+}
+
+bool
+js::StartOffThreadWasmTier2Generator(wasm::Tier2GeneratorTask* task)
+{
+    AutoLockHelperThreadState lock;
+
+    if (!HelperThreadState().wasmTier2GeneratorWorklist(lock).append(task))
         return false;
 
     HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
     return true;
 }
 
+void
+js::CancelOffThreadWasmTier2Generator()
+{
+    AutoLockHelperThreadState lock;
+
+    if (!HelperThreadState().threads)
+        return;
+
+    // Remove pending tasks from the tier2 generator worklist and cancel and
+    // delete them.
+    {
+        wasm::Tier2GeneratorTaskPtrVector& worklist =
+            HelperThreadState().wasmTier2GeneratorWorklist(lock);
+        for (size_t i = 0; i < worklist.length(); i++) {
+            wasm::Tier2GeneratorTask* task = worklist[i];
+            HelperThreadState().remove(worklist, &i);
+            CancelTier2GeneratorTask(task);
+            DeleteTier2GeneratorTask(task);
+        }
+    }
+
+    // There is at most one running Tier2Generator task and we assume that
+    // below.
+    static_assert(GlobalHelperThreadState::MaxTier2GeneratorTasks == 1,
+                  "code must be generalized");
+
+    // If there is a running Tier2 generator task, shut it down in a predictable
+    // way.  The task will be deleted by the normal deletion logic.
+    for (auto& helper : *HelperThreadState().threads) {
+        if (helper.wasmTier2GeneratorTask()) {
+            // Set a flag that causes compilation to shortcut itself.
+            CancelTier2GeneratorTask(helper.wasmTier2GeneratorTask());
+
+            // Wait for the generator task to finish.  This avoids a shutdown race where
+            // the shutdown code is trying to shut down helper threads and the ongoing
+            // tier2 compilation is trying to finish, which requires it to have access
+            // to helper threads.
+            uint32_t oldFinishedCount = HelperThreadState().wasmTier2GeneratorsFinished(lock);
+            while (HelperThreadState().wasmTier2GeneratorsFinished(lock) == oldFinishedCount)
+                HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
+
+            // At most one of these tasks.
+            break;
+        }
+    }
+}
+
 bool
 js::StartOffThreadIonCompile(JSContext* cx, jit::IonBuilder* builder)
 {
     AutoLockHelperThreadState lock;
 
     if (!HelperThreadState().ionWorklist(lock).append(builder))
         return false;
 
@@ -860,29 +919,33 @@ GlobalHelperThreadState::ensureInitializ
 
     return true;
 }
 
 GlobalHelperThreadState::GlobalHelperThreadState()
  : cpuCount(0),
    threadCount(0),
    threads(nullptr),
-   wasmCompilationInProgress(false),
-   numWasmFailedJobs(0),
+   wasmCompilationInProgress_tier1(false),
+   wasmCompilationInProgress_tier2(false),
+   wasmTier2GeneratorsFinished_(0),
+   numWasmFailedJobs_tier1(0),
+   numWasmFailedJobs_tier2(0),
    helperLock(mutexid::GlobalHelperThreadState)
 {
     cpuCount = GetCPUCount();
     threadCount = ThreadCountForCPUCount(cpuCount);
 
     MOZ_ASSERT(cpuCount > 0, "GetCPUCount() seems broken");
 }
 
 void
 GlobalHelperThreadState::finish()
 {
+    CancelOffThreadWasmTier2Generator();
     finishThreads();
 
     // Make sure there are no Ion free tasks left. We check this here because,
     // unlike the other tasks, we don't explicitly block on this when
     // destroying a runtime.
     AutoLockHelperThreadState lock;
     auto& freeList = ionFreeList(lock);
     while (!freeList.empty())
@@ -953,16 +1016,17 @@ GlobalHelperThreadState::hasActiveThread
 
     return false;
 }
 
 void
 GlobalHelperThreadState::waitForAllThreads()
 {
     CancelOffThreadIonCompile();
+    CancelOffThreadWasmTier2Generator();
 
     AutoLockHelperThreadState lock;
     while (hasActiveThreads(lock))
         wait(lock, CONSUMER);
 }
 
 // A task can be a "master" task, ie, it will block waiting for other worker
 // threads that perform work on its behalf.  If so it must not take the last
@@ -1055,16 +1119,22 @@ size_t
 GlobalHelperThreadState::maxWasmCompilationThreads() const
 {
     if (IsHelperThreadSimulatingOOM(js::THREAD_TYPE_WASM))
         return 1;
     return cpuCount;
 }
 
 size_t
+GlobalHelperThreadState::maxWasmTier2GeneratorThreads() const
+{
+    return MaxTier2GeneratorTasks;
+}
+
+size_t
 GlobalHelperThreadState::maxParseThreads() const
 {
     if (IsHelperThreadSimulatingOOM(js::THREAD_TYPE_PARSE))
         return 1;
 
     // Don't allow simultaneous off thread parses, to reduce contention on the
     // atoms table. Note that wasm compilation depends on this to avoid
     // stalling the helper thread, as off thread parse tasks can trigger and
@@ -1095,31 +1165,64 @@ size_t
 GlobalHelperThreadState::maxGCParallelThreads() const
 {
     if (IsHelperThreadSimulatingOOM(js::THREAD_TYPE_GCPARALLEL))
         return 1;
     return threadCount;
 }
 
 bool
-GlobalHelperThreadState::canStartWasmCompile(const AutoLockHelperThreadState& lock)
+GlobalHelperThreadState::canStartWasmCompile(const AutoLockHelperThreadState& lock,
+                                             wasm::CompileMode mode)
 {
-    // Don't execute an wasm job if an earlier one failed.
-    if (wasmWorklist(lock).empty() || numWasmFailedJobs)
+    // Don't execute a wasm job if an earlier one failed.
+    if (wasmWorklist(lock, mode).empty() || wasmFailed(lock, mode))
         return false;
 
-    // Honor the maximum allowed threads to compile wasm jobs at once,
-    // to avoid oversaturating the machine.
-    if (!checkTaskThreadLimit<wasm::CompileTask*>(maxWasmCompilationThreads()))
+    // For Tier1 and Once compilation, honor the maximum allowed threads to
+    // compile wasm jobs at once, to avoid oversaturating the machine.
+    //
+    // For Tier2 compilation we need to allow other things to happen too, so for
+    // now we only allow one thread.
+    //
+    // TODO: We should investigate more intelligent strategies, see bug 1380033.
+    //
+    // If Tier2 is very backlogged we must give priority to it, since the Tier2
+    // queue holds onto Tier1 tasks.  Indeed if Tier2 is backlogged we will
+    // devote more resources to Tier2 and not start any Tier1 work at all.
+
+    bool tier2oversubscribed = wasmTier2GeneratorWorklist(lock).length() > 20;
+
+    size_t threads;
+    if (mode == wasm::CompileMode::Tier2) {
+        if (tier2oversubscribed)
+            threads = maxWasmCompilationThreads();
+        else
+            threads = 1;
+    } else {
+        if (tier2oversubscribed)
+            threads = 0;
+        else
+            threads = maxWasmCompilationThreads();
+    }
+
+    if (!threads || !checkTaskThreadLimit<wasm::CompileTask*>(threads))
         return false;
 
     return true;
 }
 
 bool
+GlobalHelperThreadState::canStartWasmTier2Generator(const AutoLockHelperThreadState& lock)
+{
+    return !wasmTier2GeneratorWorklist(lock).empty() &&
+           checkTaskThreadLimit<wasm::Tier2GeneratorTask*>(maxWasmTier2GeneratorThreads());
+}
+
+bool
 GlobalHelperThreadState::canStartPromiseHelperTask(const AutoLockHelperThreadState& lock)
 {
     return !promiseHelperTasks(lock).empty();
 }
 
 static bool
 IonBuilderHasHigherPriority(jit::IonBuilder* first, jit::IonBuilder* second)
 {
@@ -1720,47 +1823,77 @@ HelperThread::ThreadMain(void* arg)
 {
     ThisThread::SetName("JS Helper");
 
     static_cast<HelperThread*>(arg)->threadLoop();
     Mutex::ShutDown();
 }
 
 void
-HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked)
+HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked, wasm::CompileMode mode)
 {
-    MOZ_ASSERT(HelperThreadState().canStartWasmCompile(locked));
+    MOZ_ASSERT(HelperThreadState().canStartWasmCompile(locked, mode));
     MOZ_ASSERT(idle());
 
-    currentTask.emplace(HelperThreadState().wasmWorklist(locked).popCopy());
+    currentTask.emplace(HelperThreadState().wasmWorklist(locked, mode).popCopy());
     bool success = false;
     UniqueChars error;
 
     wasm::CompileTask* task = wasmTask();
     {
         AutoUnlockHelperThreadState unlock(locked);
         success = wasm::CompileFunction(task, &error);
     }
 
     // On success, try to move work to the finished list.
     if (success)
-        success = HelperThreadState().wasmFinishedList(locked).append(task);
+        success = HelperThreadState().wasmFinishedList(locked, mode).append(task);
 
     // On failure, note the failure for harvesting by the parent.
     if (!success) {
-        HelperThreadState().noteWasmFailure(locked);
-        HelperThreadState().setWasmError(locked, Move(error));
+        HelperThreadState().noteWasmFailure(locked, mode);
+        HelperThreadState().setWasmError(locked, mode, Move(error));
     }
 
     // Notify the active thread in case it's waiting.
     HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
     currentTask.reset();
 }
 
 void
+HelperThread::handleWasmTier2GeneratorWorkload(AutoLockHelperThreadState& locked)
+{
+    MOZ_ASSERT(HelperThreadState().canStartWasmTier2Generator(locked));
+    MOZ_ASSERT(idle());
+
+    currentTask.emplace(HelperThreadState().wasmTier2GeneratorWorklist(locked).popCopy());
+    bool success = false;
+
+    wasm::Tier2GeneratorTask* task = wasmTier2GeneratorTask();
+    {
+        AutoUnlockHelperThreadState unlock(locked);
+        success = wasm::GenerateTier2(task);
+    }
+
+    // We silently ignore failures.  Such failures must be resource exhaustion
+    // or cancellation, because all error checking was performed by the initial
+    // compilation.
+    mozilla::Unused << success;
+
+    // During shutdown the main thread will wait for any ongoing (cancelled)
+    // tier-2 generation to shut down normally.  To do so, it waits on the
+    // CONSUMER condition for the count of finished generators to rise.
+    HelperThreadState().incWasmTier2GeneratorsFinished(locked);
+    HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
+
+    wasm::DeleteTier2GeneratorTask(task);
+    currentTask.reset();
+}
+
+void
 HelperThread::handlePromiseHelperTaskWorkload(AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().canStartPromiseHelperTask(locked));
     MOZ_ASSERT(idle());
 
     PromiseHelperTask* task = HelperThreadState().promiseHelperTasks(locked).popCopy();
     currentTask.emplace(task);
 
@@ -2162,48 +2295,56 @@ HelperThread::threadLoop()
             oomUnsafe.crash("HelperThread cx.init()");
     }
     cx.setHelperThread(this);
     JS_SetNativeStackQuota(&cx, HELPER_STACK_QUOTA);
 
     while (true) {
         MOZ_ASSERT(idle());
 
+        wasm::CompileMode tier;
         js::ThreadType task;
         while (true) {
             if (terminate)
                 return;
 
             // Select the task type to run.  Task priority is determined
             // exclusively here.
             //
             // The selectors may depend on the HelperThreadState not changing
             // between task selection and task execution, in particular, on new
             // tasks not being added (because of the lifo structure of the work
             // lists).  Unlocking the HelperThreadState between task selection
             // and execution is not well-defined.
 
-            if (HelperThreadState().canStartGCParallelTask(lock))
+            if (HelperThreadState().canStartGCParallelTask(lock)) {
                 task = js::THREAD_TYPE_GCPARALLEL;
-            else if (HelperThreadState().canStartGCHelperTask(lock))
+            } else if (HelperThreadState().canStartGCHelperTask(lock)) {
                 task = js::THREAD_TYPE_GCHELPER;
-            else if (HelperThreadState().pendingIonCompileHasSufficientPriority(lock))
+            } else if (HelperThreadState().pendingIonCompileHasSufficientPriority(lock)) {
                 task = js::THREAD_TYPE_ION;
-            else if (HelperThreadState().canStartWasmCompile(lock))
+            } else if (HelperThreadState().canStartWasmCompile(lock, wasm::CompileMode::Tier1)) {
                 task = js::THREAD_TYPE_WASM;
-            else if (HelperThreadState().canStartPromiseHelperTask(lock))
+                tier = wasm::CompileMode::Tier1;
+            } else if (HelperThreadState().canStartPromiseHelperTask(lock)) {
                 task = js::THREAD_TYPE_PROMISE_TASK;
-            else if (HelperThreadState().canStartParseTask(lock))
+            } else if (HelperThreadState().canStartParseTask(lock)) {
                 task = js::THREAD_TYPE_PARSE;
-            else if (HelperThreadState().canStartCompressionTask(lock))
+            } else if (HelperThreadState().canStartCompressionTask(lock)) {
                 task = js::THREAD_TYPE_COMPRESS;
-            else if (HelperThreadState().canStartIonFreeTask(lock))
+            } else if (HelperThreadState().canStartIonFreeTask(lock)) {
                 task = js::THREAD_TYPE_ION_FREE;
-            else
+            } else if (HelperThreadState().canStartWasmCompile(lock, wasm::CompileMode::Tier2)) {
+                task = js::THREAD_TYPE_WASM;
+                tier = wasm::CompileMode::Tier2;
+            } else if (HelperThreadState().canStartWasmTier2Generator(lock)) {
+                task = js::THREAD_TYPE_WASM_TIER2;
+            } else {
                 task = js::THREAD_TYPE_NONE;
+            }
 
             if (task != js::THREAD_TYPE_NONE)
                 break;
 
             HelperThreadState().wait(lock, GlobalHelperThreadState::PRODUCER);
         }
 
         js::oom::SetThreadType(task);
@@ -2213,28 +2354,31 @@ HelperThread::threadLoop()
             break;
           case js::THREAD_TYPE_GCHELPER:
             handleGCHelperWorkload(lock);
             break;
           case js::THREAD_TYPE_ION:
             handleIonWorkload(lock);
             break;
           case js::THREAD_TYPE_WASM:
-            handleWasmWorkload(lock);
+            handleWasmWorkload(lock, tier);
             break;
           case js::THREAD_TYPE_PROMISE_TASK:
             handlePromiseHelperTaskWorkload(lock);
             break;
           case js::THREAD_TYPE_PARSE:
             handleParseWorkload(lock);
             break;
           case js::THREAD_TYPE_COMPRESS:
             handleCompressionWorkload(lock);
             break;
           case js::THREAD_TYPE_ION_FREE:
             handleIonFreeWorkload(lock);
             break;
+          case js::THREAD_TYPE_WASM_TIER2:
+            handleWasmTier2GeneratorWorkload(lock);
+            break;
           default:
             MOZ_CRASH("No task to perform");
         }
         js::oom::SetThreadType(js::THREAD_TYPE_NONE);
     }
 }
--- a/js/src/vm/HelperThreads.h
+++ b/js/src/vm/HelperThreads.h
@@ -41,17 +41,19 @@ struct ParseTask;
 struct PromiseHelperTask;
 namespace jit {
   class IonBuilder;
 } // namespace jit
 namespace wasm {
   class FuncIR;
   class FunctionCompileResults;
   class CompileTask;
+  struct Tier2GeneratorTask;
   typedef Vector<CompileTask*, 0, SystemAllocPolicy> CompileTaskPtrVector;
+  typedef Vector<Tier2GeneratorTask*, 0, SystemAllocPolicy> Tier2GeneratorTaskPtrVector;
 } // namespace wasm
 
 enum class ParseTaskKind
 {
     Script,
     Module,
     ScriptDecode,
     MultiScriptsDecode
@@ -59,16 +61,20 @@ enum class ParseTaskKind
 
 // Per-process state for off thread work items.
 class GlobalHelperThreadState
 {
     friend class AutoLockHelperThreadState;
     friend class AutoUnlockHelperThreadState;
 
   public:
+    // A single tier-2 ModuleGenerator job spawns many compilation jobs, and we
+    // do not want to allow more than one such ModuleGenerator to run at a time.
+    static const size_t MaxTier2GeneratorTasks = 1;
+
     // Number of CPUs to treat this machine as having when creating threads.
     // May be accessed without locking.
     size_t cpuCount;
 
     // Number of threads to create. May be accessed without locking.
     size_t threadCount;
 
     typedef Vector<jit::IonBuilder*, 0, SystemAllocPolicy> IonBuilderVector;
@@ -84,22 +90,42 @@ class GlobalHelperThreadState
 
   private:
     // The lists below are all protected by |lock|.
 
     // Ion compilation worklist and finished jobs.
     IonBuilderVector ionWorklist_, ionFinishedList_, ionFreeList_;
 
     // wasm worklist and finished jobs.
-    wasm::CompileTaskPtrVector wasmWorklist_, wasmFinishedList_;
+    wasm::CompileTaskPtrVector wasmWorklist_tier1_, wasmFinishedList_tier1_;
+    wasm::CompileTaskPtrVector wasmWorklist_tier2_, wasmFinishedList_tier2_;
+    wasm::Tier2GeneratorTaskPtrVector wasmTier2GeneratorWorklist_;
+
+    // For now, only allow a single parallel wasm compilation at each tier to
+    // happen at a time.  This avoids race conditions on
+    // wasmWorklist/wasmFinishedList/etc, for which there is one for each tier.
+    //
+    // TODO: remove this restriction by making the work and finish lists
+    // per-compilation state, not part of the global state.
+
+    mozilla::Atomic<bool> wasmCompilationInProgress_tier1;
+    mozilla::Atomic<bool> wasmCompilationInProgress_tier2;
 
   public:
-    // For now, only allow a single parallel wasm compilation to happen at a
-    // time. This avoids race conditions on wasmWorklist/wasmFinishedList/etc.
-    mozilla::Atomic<bool> wasmCompilationInProgress;
+    mozilla::Atomic<bool>& wasmCompilationInProgress(wasm::CompileMode m) {
+        switch (m) {
+          case wasm::CompileMode::Once:
+          case wasm::CompileMode::Tier1:
+            return wasmCompilationInProgress_tier1;
+          case wasm::CompileMode::Tier2:
+            return wasmCompilationInProgress_tier2;
+          default:
+            MOZ_CRASH();
+        }
+    }
 
   private:
     // Async tasks that, upon completion, are dispatched back to the JSContext's
     // owner thread via embedding callbacks instead of a finished list.
     PromiseHelperTaskVector promiseHelperTasks_;
 
     // Script parsing/emitting worklist and finished jobs.
     ParseTaskVector parseWorklist_, parseFinishedList_;
@@ -117,22 +143,26 @@ class GlobalHelperThreadState
     SourceCompressionTaskVector compressionFinishedList_;
 
     // Runtimes which have sweeping / allocating work to do.
     GCHelperStateVector gcHelperWorklist_;
 
     // GC tasks needing to be done in parallel.
     GCParallelTaskVector gcParallelWorklist_;
 
+    // Count of finished Tier2Generator tasks.
+    uint32_t wasmTier2GeneratorsFinished_;
+
     ParseTask* removeFinishedParseTask(ParseTaskKind kind, void* token);
 
   public:
     size_t maxIonCompilationThreads() const;
     size_t maxUnpausedIonCompilationThreads() const;
     size_t maxWasmCompilationThreads() const;
+    size_t maxWasmTier2GeneratorThreads() const;
     size_t maxParseThreads() const;
     size_t maxCompressionThreads() const;
     size_t maxGCHelperThreads() const;
     size_t maxGCParallelThreads() const;
 
     GlobalHelperThreadState();
 
     bool ensureInitialized();
@@ -182,21 +212,49 @@ class GlobalHelperThreadState
     }
     IonBuilderVector& ionFinishedList(const AutoLockHelperThreadState&) {
         return ionFinishedList_;
     }
     IonBuilderVector& ionFreeList(const AutoLockHelperThreadState&) {
         return ionFreeList_;
     }
 
-    wasm::CompileTaskPtrVector& wasmWorklist(const AutoLockHelperThreadState&) {
-        return wasmWorklist_;
+    wasm::CompileTaskPtrVector& wasmWorklist(const AutoLockHelperThreadState&, wasm::CompileMode m) {
+        switch (m) {
+          case wasm::CompileMode::Once:
+          case wasm::CompileMode::Tier1:
+            return wasmWorklist_tier1_;
+          case wasm::CompileMode::Tier2:
+            return wasmWorklist_tier2_;
+          default:
+            MOZ_CRASH();
+        }
     }
-    wasm::CompileTaskPtrVector& wasmFinishedList(const AutoLockHelperThreadState&) {
-        return wasmFinishedList_;
+    wasm::CompileTaskPtrVector& wasmFinishedList(const AutoLockHelperThreadState&, wasm::CompileMode m) {
+        switch (m) {
+          case wasm::CompileMode::Once:
+          case wasm::CompileMode::Tier1:
+            return wasmFinishedList_tier1_;
+          case wasm::CompileMode::Tier2:
+            return wasmFinishedList_tier2_;
+          default:
+            MOZ_CRASH();
+        }
+    }
+
+    wasm::Tier2GeneratorTaskPtrVector& wasmTier2GeneratorWorklist(const AutoLockHelperThreadState&) {
+        return wasmTier2GeneratorWorklist_;
+    }
+
+    void incWasmTier2GeneratorsFinished(const AutoLockHelperThreadState&) {
+        wasmTier2GeneratorsFinished_++;
+    }
+
+    uint32_t wasmTier2GeneratorsFinished(const AutoLockHelperThreadState&) const {
+        return wasmTier2GeneratorsFinished_;
     }
 
     PromiseHelperTaskVector& promiseHelperTasks(const AutoLockHelperThreadState&) {
         return promiseHelperTasks_;
     }
 
     ParseTaskVector& parseWorklist(const AutoLockHelperThreadState&) {
         return parseWorklist_;
@@ -223,17 +281,18 @@ class GlobalHelperThreadState
     GCHelperStateVector& gcHelperWorklist(const AutoLockHelperThreadState&) {
         return gcHelperWorklist_;
     }
 
     GCParallelTaskVector& gcParallelWorklist(const AutoLockHelperThreadState&) {
         return gcParallelWorklist_;
     }
 
-    bool canStartWasmCompile(const AutoLockHelperThreadState& lock);
+    bool canStartWasmCompile(const AutoLockHelperThreadState& lock, wasm::CompileMode mode);
+    bool canStartWasmTier2Generator(const AutoLockHelperThreadState& lock);
     bool canStartPromiseHelperTask(const AutoLockHelperThreadState& lock);
     bool canStartIonCompile(const AutoLockHelperThreadState& lock);
     bool canStartIonFreeTask(const AutoLockHelperThreadState& lock);
     bool canStartParseTask(const AutoLockHelperThreadState& lock);
     bool canStartCompressionTask(const AutoLockHelperThreadState& lock);
     bool canStartGCHelperTask(const AutoLockHelperThreadState& lock);
     bool canStartGCParallelTask(const AutoLockHelperThreadState& lock);
 
@@ -250,34 +309,83 @@ class GlobalHelperThreadState
     bool pendingIonCompileHasSufficientPriority(const AutoLockHelperThreadState& lock);
 
     jit::IonBuilder* highestPriorityPendingIonCompile(const AutoLockHelperThreadState& lock,
                                                       bool remove = false);
     HelperThread* lowestPriorityUnpausedIonCompileAtThreshold(
         const AutoLockHelperThreadState& lock);
     HelperThread* highestPriorityPausedIonCompile(const AutoLockHelperThreadState& lock);
 
-    uint32_t harvestFailedWasmJobs(const AutoLockHelperThreadState&) {
-        uint32_t n = numWasmFailedJobs;
-        numWasmFailedJobs = 0;
-        return n;
+    uint32_t harvestFailedWasmJobs(const AutoLockHelperThreadState&, wasm::CompileMode m) {
+        switch (m) {
+          case wasm::CompileMode::Once:
+          case wasm::CompileMode::Tier1: {
+              uint32_t n = numWasmFailedJobs_tier1;
+              numWasmFailedJobs_tier1 = 0;
+              return n;
+          }
+          case wasm::CompileMode::Tier2: {
+              uint32_t n = numWasmFailedJobs_tier2;
+              numWasmFailedJobs_tier2 = 0;
+              return n;
+          }
+          default:
+            MOZ_CRASH();
+        }
     }
-    UniqueChars harvestWasmError(const AutoLockHelperThreadState&) {
-        return Move(firstWasmError);
+    UniqueChars harvestWasmError(const AutoLockHelperThreadState&, wasm::CompileMode m) {
+        switch (m) {
+          case wasm::CompileMode::Once:
+          case wasm::CompileMode::Tier1:
+            return Move(firstWasmError_tier1);
+          case wasm::CompileMode::Tier2:
+            return Move(firstWasmError_tier2);
+          default:
+            MOZ_CRASH();
+        }
     }
-    void noteWasmFailure(const AutoLockHelperThreadState&) {
+    void noteWasmFailure(const AutoLockHelperThreadState&, wasm::CompileMode m) {
         // Be mindful to signal the active thread after calling this function.
-        numWasmFailedJobs++;
+        switch (m) {
+          case wasm::CompileMode::Once:
+          case wasm::CompileMode::Tier1:
+            numWasmFailedJobs_tier1++;
+            break;
+          case wasm::CompileMode::Tier2:
+            numWasmFailedJobs_tier2++;
+            break;
+          default:
+            MOZ_CRASH();
+        }
     }
-    void setWasmError(const AutoLockHelperThreadState&, UniqueChars error) {
-        if (!firstWasmError)
-            firstWasmError = Move(error);
+    void setWasmError(const AutoLockHelperThreadState&, wasm::CompileMode m, UniqueChars error) {
+        switch (m) {
+          case wasm::CompileMode::Once:
+          case wasm::CompileMode::Tier1:
+            if (!firstWasmError_tier1)
+                firstWasmError_tier1 = Move(error);
+            break;
+          case wasm::CompileMode::Tier2:
+            if (!firstWasmError_tier2)
+                firstWasmError_tier2 = Move(error);
+            break;
+          default:
+            MOZ_CRASH();
+        }
     }
-    bool wasmFailed(const AutoLockHelperThreadState&) {
-        return bool(numWasmFailedJobs);
+    bool wasmFailed(const AutoLockHelperThreadState&, wasm::CompileMode m) {
+        switch (m) {
+          case wasm::CompileMode::Once:
+          case wasm::CompileMode::Tier1:
+            return bool(numWasmFailedJobs_tier1);
+          case wasm::CompileMode::Tier2:
+            return bool(numWasmFailedJobs_tier2);
+          default:
+            MOZ_CRASH();
+        }
     }
 
     template <
         typename F,
         typename = typename mozilla::EnableIf<
             // Matches when the type is a function or lambda with the signature `bool(ParseTask*)`
             mozilla::IsSame<bool, decltype((*(F*)nullptr)((ParseTask*)nullptr))>::value
         >::Type
@@ -296,22 +404,24 @@ class GlobalHelperThreadState
 
     void trace(JSTracer* trc);
 
   private:
     /*
      * Number of wasm jobs that encountered failure for the active module.
      * Their parent is logically the active thread, and this number serves for harvesting.
      */
-    uint32_t numWasmFailedJobs;
+    uint32_t numWasmFailedJobs_tier1;
+    uint32_t numWasmFailedJobs_tier2;
     /*
      * Error string from wasm validation. Arbitrarily choose to keep the first one that gets
      * reported. Nondeterministic if multiple threads have errors.
      */
-    UniqueChars firstWasmError;
+    UniqueChars firstWasmError_tier1;
+    UniqueChars firstWasmError_tier2;
 
   public:
     JSScript* finishScriptParseTask(JSContext* cx, void* token);
     JSScript* finishScriptDecodeTask(JSContext* cx, void* token);
     bool finishMultiScriptsDecodeTask(JSContext* cx, void* token, MutableHandle<ScriptVector> scripts);
     JSObject* finishModuleParseTask(JSContext* cx, void* token);
 
     bool hasActiveThreads(const AutoLockHelperThreadState&);
@@ -349,16 +459,17 @@ HelperThreadState()
     extern GlobalHelperThreadState* gHelperThreadState;
 
     MOZ_ASSERT(gHelperThreadState);
     return *gHelperThreadState;
 }
 
 typedef mozilla::Variant<jit::IonBuilder*,
                          wasm::CompileTask*,
+                         wasm::Tier2GeneratorTask*,
                          PromiseHelperTask*,
                          ParseTask*,
                          SourceCompressionTask*,
                          GCHelperState*,
                          GCParallelTask*> HelperTaskUnion;
 
 /* Individual helper thread, one allocated per core. */
 struct HelperThread
@@ -390,16 +501,20 @@ struct HelperThread
         return maybeCurrentTaskAs<jit::IonBuilder*>();
     }
 
     /* Any wasm data currently being optimized on this thread. */
     wasm::CompileTask* wasmTask() {
         return maybeCurrentTaskAs<wasm::CompileTask*>();
     }
 
+    wasm::Tier2GeneratorTask* wasmTier2GeneratorTask() {
+        return maybeCurrentTaskAs<wasm::Tier2GeneratorTask*>();
+    }
+
     /* Any source being parsed/emitted on this thread. */
     ParseTask* parseTask() {
         return maybeCurrentTaskAs<ParseTask*>();
     }
 
     /* Any source being compressed on this thread. */
     SourceCompressionTask* compressionTask() {
         return maybeCurrentTaskAs<SourceCompressionTask*>();
@@ -424,17 +539,18 @@ struct HelperThread
     template <typename T>
     T maybeCurrentTaskAs() {
         if (currentTask.isSome() && currentTask->is<T>())
             return currentTask->as<T>();
 
         return nullptr;
     }
 
-    void handleWasmWorkload(AutoLockHelperThreadState& locked);
+    void handleWasmWorkload(AutoLockHelperThreadState& locked, wasm::CompileMode mode);
+    void handleWasmTier2GeneratorWorkload(AutoLockHelperThreadState& locked);
     void handlePromiseHelperTaskWorkload(AutoLockHelperThreadState& locked);
     void handleIonWorkload(AutoLockHelperThreadState& locked);
     void handleIonFreeWorkload(AutoLockHelperThreadState& locked);
     void handleParseWorkload(AutoLockHelperThreadState& locked);
     void handleCompressionWorkload(AutoLockHelperThreadState& locked);
     void handleGCHelperWorkload(AutoLockHelperThreadState& locked);
     void handleGCParallelWorkload(AutoLockHelperThreadState& locked);
 };
@@ -463,24 +579,40 @@ HelperThread*
 CurrentHelperThread();
 
 // Pause the current thread until it's pause flag is unset.
 void
 PauseCurrentHelperThread();
 
 // Enqueues a wasm compilation task.
 bool
-StartOffThreadWasmCompile(wasm::CompileTask* task);
+StartOffThreadWasmCompile(wasm::CompileTask* task, wasm::CompileMode mode);
+
+// Enqueues a wasm compilation task.
+bool
+StartOffThreadWasmTier2Generator(wasm::Tier2GeneratorTask* task);
+
+// Cancel all background Wasm Tier-2 compilations.
+void
+CancelOffThreadWasmTier2Generator();
 
 namespace wasm {
 
 // Performs MIR optimization and LIR generation on one or several functions.
 MOZ_MUST_USE bool
 CompileFunction(CompileTask* task, UniqueChars* error);
 
+MOZ_MUST_USE bool
+GenerateTier2(Tier2GeneratorTask* task);
+
+void
+CancelTier2GeneratorTask(Tier2GeneratorTask* task);
+
+void
+DeleteTier2GeneratorTask(Tier2GeneratorTask* task);
 }
 
 /*
  * If helper threads are available, call execute() then dispatchResolve() on the
  * given task in a helper thread. If no helper threads are available, the given
  * task is executed and resolved synchronously.
  */
 bool
--- a/js/src/vm/MutexIDs.h
+++ b/js/src/vm/MutexIDs.h
@@ -38,16 +38,17 @@
   _(PerfSpewer,                  500) \
   _(CacheIRSpewer,               500) \
   _(TraceLoggerThreadState,      500) \
   _(DateTimeInfoMutex,           500) \
   _(IcuTimeZoneStateMutex,       500) \
   _(ProcessExecutableRegion,     500) \
   _(WasmCodeProfilingLabels,     500) \
   _(OffThreadPromiseState,       500) \
+  _(WasmTier2GeneratorComplete,  500) \
                                       \
   _(TraceLoggerGraphState,       600) \
   _(VTuneLock,                   600)
 
 namespace js {
 namespace mutexid {
 
 #define DEFINE_MUTEX_ID(name, order)  \
--- a/js/src/vm/Symbol.cpp
+++ b/js/src/vm/Symbol.cpp
@@ -138,30 +138,16 @@ js::SymbolDescriptiveString(JSContext* c
     // step 6
     str = sb.finishString();
     if (!str)
         return false;
     result.setString(str);
     return true;
 }
 
-bool
-js::IsSymbolOrSymbolWrapper(const Value& v)
-{
-    return v.isSymbol() || (v.isObject() && v.toObject().is<SymbolObject>());
-}
-
-JS::Symbol*
-js::ToSymbolPrimitive(const Value& v)
-{
-    MOZ_ASSERT(IsSymbolOrSymbolWrapper(v));
-    return v.isSymbol() ? v.toSymbol() : v.toObject().as<SymbolObject>().unbox();
-}
-
-
 JS::ubi::Node::Size
 JS::ubi::Concrete<JS::Symbol>::size(mozilla::MallocSizeOf mallocSizeOf) const
 {
     // If we start allocating symbols in the nursery, we will need to update
     // this method.
     MOZ_ASSERT(get().isTenured());
     return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
 }
--- a/js/src/vm/Symbol.h
+++ b/js/src/vm/Symbol.h
@@ -134,25 +134,15 @@ struct HashSymbolsByDescription
 class SymbolRegistry : public GCHashSet<ReadBarrieredSymbol,
                                         HashSymbolsByDescription,
                                         SystemAllocPolicy>
 {
   public:
     SymbolRegistry() {}
 };
 
-} /* namespace js */
-
-namespace js {
-
 // ES6 rev 27 (2014 Aug 24) 19.4.3.3
 bool
 SymbolDescriptiveString(JSContext* cx, JS::Symbol* sym, JS::MutableHandleValue result);
 
-bool
-IsSymbolOrSymbolWrapper(const JS::Value& v);
-
-JS::Symbol*
-ToSymbolPrimitive(const JS::Value& v);
-
 } /* namespace js */
 
 #endif /* vm_Symbol_h */
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -1725,17 +1725,17 @@ class MOZ_STACK_CLASS ModuleValidator
         functions_(cx),
         funcPtrTables_(cx),
         globalMap_(cx),
         sigMap_(cx),
         importMap_(cx),
         arrayViews_(cx),
         atomicsPresent_(false),
         simdPresent_(false),
-        mg_(nullptr),
+        mg_(nullptr, nullptr),
         errorString_(nullptr),
         errorOffset_(UINT32_MAX),
         errorOverRecursed_(false)
     {}
 
     ~ModuleValidator() {
         if (errorString_) {
             MOZ_ASSERT(errorOffset_ != UINT32_MAX);
@@ -1858,34 +1858,34 @@ class MOZ_STACK_CLASS ModuleValidator
         ScriptedCaller scriptedCaller;
         if (parser_.ss->filename()) {
             scriptedCaller.line = scriptedCaller.column = 0;  // unused
             scriptedCaller.filename = DuplicateString(parser_.ss->filename());
             if (!scriptedCaller.filename)
                 return false;
         }
 
-        CompileArgs args;
-        if (!args.initFromContext(cx_, Move(scriptedCaller)))
+        MutableCompileArgs args = cx_->new_<CompileArgs>();
+        if (!args || !args->initFromContext(cx_, Move(scriptedCaller)))
             return false;
 
         auto env = MakeUnique<ModuleEnvironment>(ModuleKind::AsmJS);
         if (!env ||
             !env->sigs.resize(AsmJSMaxTypes) ||
             !env->funcSigs.resize(AsmJSMaxFuncs) ||
             !env->funcImportGlobalDataOffsets.resize(AsmJSMaxImports) ||
             !env->tables.resize(AsmJSMaxTables) ||
             !env->asmJSSigToTableIndex.resize(AsmJSMaxTypes))
         {
             return false;
         }
 
         env->minMemoryLength = RoundUpToNextValidAsmJSHeapLength(0);
 
-        if (!mg_.init(Move(env), args, asmJSMetadata_.get()))
+        if (!mg_.init(Move(env), *args, CompileMode::Once, asmJSMetadata_.get()))
             return false;
 
         return true;
     }
 
     JSContext* cx() const                    { return cx_; }
     PropertyName* moduleFunctionName() const { return moduleFunctionName_; }
     PropertyName* globalArgumentName() const { return globalArgumentName_; }
@@ -2397,21 +2397,21 @@ class MOZ_STACK_CLASS ModuleValidator
 
         TokenPos pos;
         JS_ALWAYS_TRUE(tokenStream().peekTokenPos(&pos, TokenStream::Operand));
         uint32_t endAfterCurly = pos.end;
         asmJSMetadata_->srcLengthWithRightBrace = endAfterCurly - asmJSMetadata_->srcStart;
 
         // asm.js does not have any wasm bytecode to save; view-source is
         // provided through the ScriptSource.
-        SharedBytes bytes = js_new<ShareableBytes>();
+        SharedBytes bytes = cx_->new_<ShareableBytes>();
         if (!bytes)
             return nullptr;
 
-        return mg_.finish(*bytes);
+        return mg_.finishModule(*bytes);
     }
 };
 
 /*****************************************************************************/
 // Numeric literal utilities
 
 static bool
 IsNumericNonFloatLiteral(ParseNode* pn)
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -20,20 +20,16 @@
  *
  * General status notes:
  *
  * "FIXME" indicates a known or suspected bug.  Always has a bug#.
  *
  * "TODO" indicates an opportunity for a general improvement, with an additional
  * tag to indicate the area of improvement.  Usually has a bug#.
  *
- * Unimplemented functionality:
- *
- *  - Tiered compilation (bug 1277562)
- *
  * There are lots of machine dependencies here but they are pretty well isolated
  * to a segment of the compiler.  Many dependencies will eventually be factored
  * into the MacroAssembler layer and shared with other code generators.
  *
  *
  * High-value compiler performance improvements:
  *
  * - (Bug 1316802) The specific-register allocator (the needI32(r), needI64(r)
@@ -587,16 +583,17 @@ class BaseCompiler
     ValTypeVector               SigI64I64_;
     ValTypeVector               SigD_;
     ValTypeVector               SigF_;
     MIRTypeVector               SigPI_;
     MIRTypeVector               SigP_;
     NonAssertingLabel           returnLabel_;
     NonAssertingLabel           stackOverflowLabel_;
     CodeOffset                  stackAddOffset_;
+    CompileMode                 mode_;
 
     LatentOp                    latentOp_;       // Latent operation for branch (seen next)
     ValType                     latentType_;     // Operand type, if latentOp_ is true
     Assembler::Condition        latentIntCmp_;   // Comparison operator, if latentOp_ == Compare, int types
     Assembler::DoubleCondition  latentDoubleCmp_;// Comparison operator, if latentOp_ == Compare, float types
 
     FuncOffsets                 offsets_;
     MacroAssembler&             masm;            // No '_' suffix - too tedious...
@@ -646,17 +643,18 @@ class BaseCompiler
 
   public:
     BaseCompiler(const ModuleEnvironment& env,
                  Decoder& decoder,
                  const FuncBytes& func,
                  const ValTypeVector& locals,
                  bool debugEnabled,
                  TempAllocator* alloc,
-                 MacroAssembler* masm);
+                 MacroAssembler* masm,
+                 CompileMode mode);
 
     MOZ_MUST_USE bool init();
 
     FuncOffsets finish();
 
     MOZ_MUST_USE bool emitFunction();
 
     // Used by some of the ScratchRegister implementations.
@@ -2201,17 +2199,20 @@ class BaseCompiler
     //////////////////////////////////////////////////////////////////////
     //
     // Function prologue and epilogue.
 
     void beginFunction() {
         JitSpew(JitSpew_Codegen, "# Emitting wasm baseline code");
 
         SigIdDesc sigId = env_.funcSigs[func_.index()]->id;
-        GenerateFunctionPrologue(masm, localSize_, sigId, &offsets_);
+        if (mode_ == CompileMode::Tier1)
+            GenerateFunctionPrologue(masm, localSize_, sigId, &offsets_, mode_, func_.index());
+        else
+            GenerateFunctionPrologue(masm, localSize_, sigId, &offsets_);
 
         MOZ_ASSERT(masm.framePushed() == uint32_t(localSize_));
 
         maxFramePushed_ = localSize_;
 
         if (debugEnabled_) {
             // Initialize funcIndex and flag fields of DebugFrame.
             size_t debugFrame = masm.framePushed() - DebugFrame::offsetOfFrame();
@@ -7404,31 +7405,33 @@ BaseCompiler::emitFunction()
 }
 
 BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
                            Decoder& decoder,
                            const FuncBytes& func,
                            const ValTypeVector& locals,
                            bool debugEnabled,
                            TempAllocator* alloc,
-                           MacroAssembler* masm)
+                           MacroAssembler* masm,
+                           CompileMode mode)
     : env_(env),
       iter_(env, decoder),
       func_(func),
       lastReadCallSite_(0),
       alloc_(*alloc),
       locals_(locals),
       localSize_(0),
       varLow_(0),
       varHigh_(0),
       maxFramePushed_(0),
       deadCode_(false),
       debugEnabled_(debugEnabled),
       bceSafe_(0),
       stackAddOffset_(0),
+      mode_(mode),
       latentOp_(LatentOp::None),
       latentType_(ValType::I32),
       latentIntCmp_(Assembler::Equal),
       latentDoubleCmp_(Assembler::DoubleEqual),
       masm(*masm),
       availGPR_(GeneralRegisterSet::All()),
       availFPU_(FloatRegisterSet::All()),
 #ifdef DEBUG
@@ -7579,17 +7582,18 @@ js::wasm::BaselineCompileFunction(Compil
         return false;
 
     // The MacroAssembler will sometimes access the jitContext.
 
     JitContext jitContext(&task->alloc());
 
     // One-pass baseline compilation.
 
-    BaseCompiler f(task->env(), d, func, locals, task->debugEnabled(), &task->alloc(), &task->masm());
+    BaseCompiler f(task->env(), d, func, locals, task->debugEnabled(), &task->alloc(),
+                   &task->masm(), task->mode());
     if (!f.init())
         return false;
 
     if (!f.emitFunction())
         return false;
 
     unit->finish(f.finish());
     return true;
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -267,17 +267,16 @@ bool
 CodeSegment::initialize(Tier tier,
                         UniqueCodeBytes codeBytes,
                         uint32_t codeLength,
                         const ShareableBytes& bytecode,
                         const LinkDataTier& linkData,
                         const Metadata& metadata)
 {
     MOZ_ASSERT(bytes_ == nullptr);
-    MOZ_ASSERT(tier == Tier::Baseline || tier == Tier::Ion);
 
     tier_ = tier;
     bytes_ = Move(codeBytes);
     functionLength_ = linkData.functionCodeLength;
     length_ = codeLength;
     interruptCode_ = bytes_.get() + linkData.interruptOffset;
     outOfBoundsCode_ = bytes_.get() + linkData.outOfBoundsOffset;
     unalignedAccessCode_ = bytes_.get() + linkData.unalignedAccessOffset;
@@ -307,17 +306,17 @@ CodeSegment::addSizeOfMisc(mozilla::Mall
 {
     *data += mallocSizeOf(this);
     *code += RoundupCodeLength(length_);
 }
 
 uint8_t*
 CodeSegment::serialize(uint8_t* cursor, const LinkDataTier& linkData) const
 {
-    MOZ_ASSERT(tier() == Tier::Ion);
+    MOZ_ASSERT(tier() == Tier::Serialized);
 
     cursor = WriteScalar<uint32_t>(cursor, length_);
     uint8_t* base = cursor;
     cursor = WriteBytes(cursor, bytes_.get(), length_);
     StaticallyUnlink(base, linkData);
     return cursor;
 }
 
@@ -334,17 +333,17 @@ CodeSegment::deserialize(const uint8_t* 
     UniqueCodeBytes bytes = AllocateCodeBytes(length);
     if (!bytes)
         return nullptr;
 
     cursor = ReadBytes(cursor, bytes.get(), length);
     if (!cursor)
         return nullptr;
 
-    if (!initialize(Tier::Ion, Move(bytes), length, bytecode, linkData, metadata))
+    if (!initialize(Tier::Serialized, Move(bytes), length, bytecode, linkData, metadata))
         return nullptr;
 
     return cursor;
 }
 
 size_t
 FuncExport::serializedSize() const
 {
@@ -489,63 +488,83 @@ MetadataTier::deserialize(const uint8_t*
     (cursor = DeserializePodVector(cursor, &callSites)) &&
     (cursor = DeserializeVector(cursor, &funcImports)) &&
     (cursor = DeserializeVector(cursor, &funcExports));
     debugTrapFarJumpOffsets.clear();
     debugFuncToCodeRange.clear();
     return cursor;
 }
 
+void
+Metadata::commitTier2() const
+{
+    MOZ_RELEASE_ASSERT(metadata2_.get());
+    MOZ_RELEASE_ASSERT(!hasTier2_);
+    hasTier2_ = true;
+}
+
+void
+Metadata::setTier2(UniqueMetadataTier metadata) const
+{
+    MOZ_RELEASE_ASSERT(metadata->tier == Tier::Ion && metadata1_->tier != Tier::Ion);
+    MOZ_RELEASE_ASSERT(!metadata2_.get());
+    metadata2_ = Move(metadata);
+}
+
 Tiers
 Metadata::tiers() const
 {
-    return Tiers(tier_->tier);
+    if (hasTier2())
+        return Tiers(metadata1_->tier, metadata2_->tier);
+    return Tiers(metadata1_->tier);
 }
 
 const MetadataTier&
 Metadata::metadata(Tier t) const
 {
     switch (t) {
-      case Tier::Debug:
       case Tier::Baseline:
-        MOZ_RELEASE_ASSERT(tier_->tier == Tier::Baseline);
-        return *tier_;
+        if (metadata1_->tier == Tier::Baseline)
+            return *metadata1_;
+        MOZ_CRASH("No metadata at this tier");
       case Tier::Ion:
-        MOZ_RELEASE_ASSERT(tier_->tier == Tier::Ion);
-        return *tier_;
-      case Tier::TBD:
-        return *tier_;
+        if (metadata1_->tier == Tier::Ion)
+            return *metadata1_;
+        if (hasTier2())
+            return *metadata2_;
+        MOZ_CRASH("No metadata at this tier");
       default:
         MOZ_CRASH();
     }
 }
 
 MetadataTier&
 Metadata::metadata(Tier t)
 {
     switch (t) {
-      case Tier::Debug:
       case Tier::Baseline:
-        MOZ_RELEASE_ASSERT(tier_->tier == Tier::Baseline);
-        return *tier_;
+        if (metadata1_->tier == Tier::Baseline)
+            return *metadata1_;
+        MOZ_CRASH("No metadata at this tier");
       case Tier::Ion:
-        MOZ_RELEASE_ASSERT(tier_->tier == Tier::Ion);
-        return *tier_;
-      case Tier::TBD:
-        return *tier_;
+        if (metadata1_->tier == Tier::Ion)
+            return *metadata1_;
+        if (hasTier2())
+            return *metadata2_;
+        MOZ_CRASH("No metadata at this tier");
       default:
         MOZ_CRASH();
     }
 }
 
 size_t
 Metadata::serializedSize() const
 {
     return sizeof(pod()) +
-           metadata(Tier::Ion).serializedSize() +
+           metadata(Tier::Serialized).serializedSize() +
            SerializedVectorSize(sigIds) +
            SerializedPodVectorSize(globals) +
            SerializedPodVectorSize(tables) +
            SerializedPodVectorSize(funcNames) +
            SerializedPodVectorSize(customSections) +
            filename.serializedSize() +
            sizeof(hash);
 }
@@ -567,32 +586,32 @@ Metadata::sizeOfExcludingThis(MallocSize
            filename.sizeOfExcludingThis(mallocSizeOf);
 }
 
 uint8_t*
 Metadata::serialize(uint8_t* cursor) const
 {
     MOZ_ASSERT(!debugEnabled && debugFuncArgTypes.empty() && debugFuncReturnTypes.empty());
     cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
-    cursor = metadata(Tier::Ion).serialize(cursor);
+    cursor = metadata(Tier::Serialized).serialize(cursor);
     cursor = SerializeVector(cursor, sigIds);
     cursor = SerializePodVector(cursor, globals);
     cursor = SerializePodVector(cursor, tables);
     cursor = SerializePodVector(cursor, funcNames);
     cursor = SerializePodVector(cursor, customSections);
     cursor = filename.serialize(cursor);
     cursor = WriteBytes(cursor, hash, sizeof(hash));
     return cursor;
 }
 
 /* static */ const uint8_t*
 Metadata::deserialize(const uint8_t* cursor)
 {
     (cursor = ReadBytes(cursor, &pod(), sizeof(pod()))) &&
-    (cursor = metadata(Tier::Ion).deserialize(cursor)) &&
+    (cursor = metadata(Tier::Serialized).deserialize(cursor)) &&
     (cursor = DeserializeVector(cursor, &sigIds)) &&
     (cursor = DeserializePodVector(cursor, &globals)) &&
     (cursor = DeserializePodVector(cursor, &tables)) &&
     (cursor = DeserializePodVector(cursor, &funcNames)) &&
     (cursor = DeserializePodVector(cursor, &customSections)) &&
     (cursor = filename.deserialize(cursor)) &&
     (cursor = ReadBytes(cursor, hash, sizeof(hash)));
     debugEnabled = false;
@@ -645,53 +664,81 @@ Metadata::getFuncName(const Bytes* maybe
     const char* funcIndexStr = NumberToCString(nullptr, &cbuf, funcIndex);
     MOZ_ASSERT(funcIndexStr);
 
     return name->append(beforeFuncIndex, strlen(beforeFuncIndex)) &&
            name->append(funcIndexStr, strlen(funcIndexStr)) &&
            name->append(afterFuncIndex, strlen(afterFuncIndex));
 }
 
-Code::Code(UniqueConstCodeSegment tier, const Metadata& metadata)
-  : tier_(Move(tier)),
+Code::Code(UniqueConstCodeSegment tier, const Metadata& metadata, UniqueJumpTable maybeJumpTable)
+  : segment1_(Move(tier)),
     metadata_(&metadata),
-    profilingLabels_(mutexid::WasmCodeProfilingLabels, CacheableCharsVector())
+    profilingLabels_(mutexid::WasmCodeProfilingLabels, CacheableCharsVector()),
+    jumpTable_(Move(maybeJumpTable))
 {
 }
 
 Code::Code()
   : profilingLabels_(mutexid::WasmCodeProfilingLabels, CacheableCharsVector())
 {
 }
 
-Tier
-Code::anyTier() const
+void
+Code::setTier2(UniqueConstCodeSegment segment) const
 {
-    return tier_->tier();
+    MOZ_RELEASE_ASSERT(segment->tier() == Tier::Ion && segment1_->tier() != Tier::Ion);
+    MOZ_RELEASE_ASSERT(!segment2_.get());
+    segment2_ = Move(segment);
 }
 
 Tiers
 Code::tiers() const
 {
-    return Tiers(tier_->tier());
+    if (hasTier2())
+        return Tiers(segment1_->tier(), segment2_->tier());
+    return Tiers(segment1_->tier());
+}
+
+bool
+Code::hasTier(Tier t) const
+{
+    if (hasTier2() && segment2_->tier() == t)
+        return true;
+    return segment1_->tier() == t;
+}
+
+Tier
+Code::stableTier() const
+{
+    return segment1_->tier();
+}
+
+Tier
+Code::bestTier() const
+{
+    if (hasTier2())
+        return segment2_->tier();
+    return segment1_->tier();
 }
 
 const CodeSegment&
 Code::segment(Tier tier) const
 {
     switch (tier) {
-      case Tier::Debug:
       case Tier::Baseline:
-        MOZ_RELEASE_ASSERT(tier_->tier() == Tier::Baseline);
-        return *tier_;
+        if (segment1_->tier() == Tier::Baseline)
+            return *segment1_;
+        MOZ_CRASH("No code segment at this tier");
       case Tier::Ion:
-        MOZ_RELEASE_ASSERT(tier_->tier() == Tier::Ion);
-        return *tier_;
-      case Tier::TBD:
-        return *tier_;
+        if (segment1_->tier() == Tier::Ion)
+            return *segment1_;
+        if (hasTier2())
+            return *segment2_;
+        MOZ_CRASH("No code segment at this tier");
       default:
         MOZ_CRASH();
     }
 }
 
 bool
 Code::containsFunctionPC(const void* pc, const CodeSegment** segmentp) const
 {
@@ -728,60 +775,47 @@ struct CallSiteRetAddrOffset
         return callSites[index].returnAddressOffset();
     }
 };
 
 size_t
 Code::serializedSize() const
 {
     return metadata().serializedSize() +
-           segment(Tier::Ion).serializedSize();
+           segment(Tier::Serialized).serializedSize();
 }
 
 uint8_t*
 Code::serialize(uint8_t* cursor, const LinkData& linkData) const
 {
     MOZ_RELEASE_ASSERT(!metadata().debugEnabled);
 
     cursor = metadata().serialize(cursor);
-    cursor = segment(Tier::Ion).serialize(cursor, linkData.linkData(Tier::Ion));
+    cursor = segment(Tier::Serialized).serialize(cursor, linkData.linkData(Tier::Serialized));
     return cursor;
 }
 
 const uint8_t*
 Code::deserialize(const uint8_t* cursor, const SharedBytes& bytecode, const LinkData& linkData,
-                  Metadata* maybeMetadata)
+                  Metadata& metadata)
 {
-    MutableMetadata metadata;
-    if (maybeMetadata) {
-        metadata = maybeMetadata;
-    } else {
-        auto tier = js::MakeUnique<MetadataTier>(Tier::Ion);
-        if (!tier)
-            return nullptr;
-
-        metadata = js_new<Metadata>(Move(tier));
-        if (!metadata)
-            return nullptr;
-    }
-
-    cursor = metadata->deserialize(cursor);
+    cursor = metadata.deserialize(cursor);
     if (!cursor)
         return nullptr;
 
     UniqueCodeSegment codeSegment = js::MakeUnique<CodeSegment>();
     if (!codeSegment)
         return nullptr;
 
-    cursor = codeSegment->deserialize(cursor, *bytecode, linkData.linkData(Tier::Ion), *metadata);
+    cursor = codeSegment->deserialize(cursor, *bytecode, linkData.linkData(Tier::Serialized), metadata);
     if (!cursor)
         return nullptr;
 
-    tier_ = UniqueConstCodeSegment(codeSegment.release());
-    metadata_ = metadata;
+    segment1_ = UniqueConstCodeSegment(codeSegment.release());
+    metadata_ = &metadata;
 
     return cursor;
 }
 
 const CallSite*
 Code::lookupCallSite(void* returnAddress, const CodeSegment** segmentp) const
 {
     for (auto t : tiers()) {
@@ -826,28 +860,27 @@ struct MemoryAccessOffset
         return accesses[index].insnOffset();
     }
 };
 
 const MemoryAccess*
 Code::lookupMemoryAccess(void* pc, const CodeSegment** segmentp) const
 {
     for (auto t : tiers()) {
-        MOZ_ASSERT(segment(t).containsFunctionPC(pc));
-
         const MemoryAccessVector& memoryAccesses = metadata(t).memoryAccesses;
 
         uint32_t target = ((uint8_t*)pc) - segment(t).base();
         size_t lowerBound = 0;
         size_t upperBound = memoryAccesses.length();
 
         size_t match;
         if (BinarySearch(MemoryAccessOffset(memoryAccesses), lowerBound, upperBound, target,
                          &match))
         {
+            MOZ_ASSERT(segment(t).containsFunctionPC(pc));
             if (segmentp)
                 *segmentp = &segment(t);
             return &memoryAccesses[match];
         }
     }
     return nullptr;
 }
 
@@ -866,17 +899,17 @@ Code::ensureProfilingLabels(const Bytes*
     }
 
     if (!labels->empty())
         return;
 
     // Any tier will do, we only need tier-invariant data that are incidentally
     // stored with the code ranges.
 
-    for (const CodeRange& codeRange : metadata(anyTier()).codeRanges) {
+    for (const CodeRange& codeRange : metadata(stableTier()).codeRanges) {
         if (!codeRange.isFunction())
             continue;
 
         ToCStringBuf cbuf;
         const char* bytecodeStr = NumberToCString(nullptr, &cbuf, codeRange.funcLineOrBytecode());
         MOZ_ASSERT(bytecodeStr);
 
         UTF8Bytes name;
--- a/js/src/wasm/WasmCode.h
+++ b/js/src/wasm/WasmCode.h
@@ -25,20 +25,20 @@
 
 namespace js {
 
 struct AsmJSMetadata;
 class WasmInstanceObject;
 
 namespace wasm {
 
-struct LinkData;
 struct LinkDataTier;
-struct Metadata;
 struct MetadataTier;
+class LinkData;
+class Metadata;
 
 // ShareableBytes is a reference-counted Vector of bytes.
 
 struct ShareableBytes : ShareableBase<ShareableBytes>
 {
     // Vector is 'final', so instead make Vector a member and add boilerplate.
     Bytes bytes;
     size_t sizeOfExcludingThis(MallocSizeOf m) const { return bytes.sizeOfExcludingThis(m); }
@@ -343,21 +343,17 @@ struct MetadataCacheablePod
         globalDataLength(0)
     {}
 };
 
 typedef uint8_t ModuleHash[8];
 
 struct MetadataTier
 {
-    explicit MetadataTier(Tier tier)
-      : tier(tier)
-    {
-        MOZ_ASSERT(tier == Tier::Baseline || tier == Tier::Ion);
-    }
+    explicit MetadataTier(Tier tier) : tier(tier) {}
 
     const Tier            tier;
 
     MemoryAccessVector    memoryAccesses;
     CodeRangeVector       codeRanges;
     CallSiteVector        callSites;
     FuncImportVector      funcImports;
     FuncExportVector      funcExports;
@@ -368,34 +364,46 @@ struct MetadataTier
 
     const FuncExport& lookupFuncExport(uint32_t funcIndex) const;
 
     WASM_DECLARE_SERIALIZABLE(MetadataTier);
 };
 
 typedef UniquePtr<MetadataTier> UniqueMetadataTier;
 
-struct Metadata : ShareableBase<Metadata>, MetadataCacheablePod
+class Metadata : public ShareableBase<Metadata>, public MetadataCacheablePod
 {
-    // `tier_` will become more complicated when tiering is implemented.
-    UniqueMetadataTier tier_;
+    UniqueMetadataTier            metadata1_;
+    mutable UniqueMetadataTier    metadata2_;     // Access only when hasTier2() is true
+    mutable mozilla::Atomic<bool> hasTier2_;
 
-    Tiers tiers() const;
-    const MetadataTier& metadata(Tier t) const;
-    MetadataTier& metadata(Tier t);
-
+  public:
     explicit Metadata(UniqueMetadataTier tier, ModuleKind kind = ModuleKind::Wasm)
       : MetadataCacheablePod(kind),
-        tier_(Move(tier))
+        metadata1_(Move(tier))
     {}
     virtual ~Metadata() {}
 
     MetadataCacheablePod& pod() { return *this; }
     const MetadataCacheablePod& pod() const { return *this; }
 
+    void commitTier2() const;
+    bool hasTier2() const { return hasTier2_; }
+    void setTier2(UniqueMetadataTier metadata) const;
+    Tiers tiers() const;
+
+    const MetadataTier& metadata(Tier t) const;
+    MetadataTier& metadata(Tier t);
+
+    UniquePtr<MetadataTier> takeMetadata(Tier tier) {
+        MOZ_ASSERT(!hasTier2());
+        MOZ_ASSERT(metadata1_->tier == tier);
+        return Move(metadata1_);
+    }
+
     SigWithIdVector       sigIds;
     GlobalDescVector      globals;
     TableDescVector       tables;
     NameInBytecodeVector  funcNames;
     CustomSectionVector   customSections;
     CacheableChars        filename;
     ModuleHash            hash;
 
@@ -431,35 +439,44 @@ struct Metadata : ShareableBase<Metadata
     virtual bool getFuncName(const Bytes* maybeBytecode, uint32_t funcIndex, UTF8Bytes* name) const;
 
     WASM_DECLARE_SERIALIZABLE_VIRTUAL(Metadata);
 };
 
 typedef RefPtr<Metadata> MutableMetadata;
 typedef RefPtr<const Metadata> SharedMetadata;
 
+typedef UniquePtr<uintptr_t, JS::FreePolicy> UniqueJumpTable;
+
 // Code objects own executable code and the metadata that describe it. A single
 // Code object is normally shared between a module and all its instances.
 //
 // profilingLabels_ is lazily initialized, but behind a lock.
 
 class Code : public ShareableBase<Code>
 {
-    // `tier_` will become more complicated when tiering is implemented.
-    UniqueConstCodeSegment              tier_;
+    UniqueConstCodeSegment              segment1_;
+    mutable UniqueConstCodeSegment      segment2_; // Access only when hasTier2() is true
     SharedMetadata                      metadata_;
     ExclusiveData<CacheableCharsVector> profilingLabels_;
+    UniqueJumpTable                     jumpTable_;
 
   public:
     Code();
+    Code(UniqueConstCodeSegment tier, const Metadata& metadata, UniqueJumpTable maybeJumpTable);
 
-    Code(UniqueConstCodeSegment tier, const Metadata& metadata);
+    uintptr_t* jumpTable() const { return jumpTable_.get(); }
 
-    Tier anyTier() const;
+    bool hasTier2() const { return metadata_->hasTier2(); }
+    void setTier2(UniqueConstCodeSegment segment) const;
     Tiers tiers() const;
+    bool hasTier(Tier t) const;
+
+    Tier stableTier() const;    // This is stable during a run
+    Tier bestTier() const;      // This may transition from Baseline -> Ion at any time
 
     const CodeSegment& segment(Tier tier) const;
     const MetadataTier& metadata(Tier tier) const { return metadata_->metadata(tier); }
     const Metadata& metadata() const { return *metadata_; }
 
     // Frame iterator support:
 
     const CallSite* lookupCallSite(void* returnAddress, const CodeSegment** segment = nullptr) const;
@@ -487,17 +504,17 @@ class Code : public ShareableBase<Code>
 
     // A Code object is serialized as the length and bytes of the machine code
     // after statically unlinking it; the Code is then later recreated from the
     // machine code and other parts.
 
     size_t serializedSize() const;
     uint8_t* serialize(uint8_t* cursor, const LinkData& linkData) const;
     const uint8_t* deserialize(const uint8_t* cursor, const SharedBytes& bytecode,
-                               const LinkData& linkData, Metadata* maybeMetadata);
+                               const LinkData& linkData, Metadata& metadata);
 };
 
 typedef RefPtr<const Code> SharedCode;
 typedef RefPtr<Code> MutableCode;
 
 } // namespace wasm
 } // namespace js
 
--- a/js/src/wasm/WasmCompartment.cpp
+++ b/js/src/wasm/WasmCompartment.cpp
@@ -22,19 +22,16 @@
 
 #include "wasm/WasmInstance.h"
 
 #include "vm/Debugger-inl.h"
 
 using namespace js;
 using namespace wasm;
 
-// With tiering, instances can have one or two code segments, and code that
-// searches the instance list will change.  Search for Tier::TBD below.
-
 Compartment::Compartment(Zone* zone)
   : mutatingInstances_(false)
 {}
 
 Compartment::~Compartment()
 {
     MOZ_ASSERT(instances_.empty());
     MOZ_ASSERT(!mutatingInstances_);
@@ -47,20 +44,26 @@ struct InstanceComparator
 
     int operator()(const Instance* instance) const {
         if (instance == &target)
             return 0;
 
         // Instances can share code, so the segments can be equal (though they
         // can't partially overlap).  If the codeBases are equal, we sort by
         // Instance address.  Thus a Code may map to many instances.
-        if (instance->codeBase(Tier::TBD) == target.codeBase(Tier::TBD))
+
+        // Compare by the first tier, always.
+
+        Tier instanceTier = instance->code().stableTier();
+        Tier targetTier = target.code().stableTier();
+
+        if (instance->codeBase(instanceTier) == target.codeBase(targetTier))
             return instance < &target ? -1 : 1;
 
-        return target.codeBase(Tier::TBD) < instance->codeBase(Tier::TBD) ? -1 : 1;
+        return target.codeBase(targetTier) < instance->codeBase(instanceTier) ? -1 : 1;
     }
 };
 
 bool
 Compartment::registerInstance(JSContext* cx, HandleWasmInstanceObject instanceObj)
 {
     Instance& instance = instanceObj->instance();
     MOZ_ASSERT(this == &instance.compartment()->wasm);
@@ -95,46 +98,42 @@ Compartment::unregisterInstance(Instance
     size_t index;
     if (!BinarySearchIf(instances_, 0, instances_.length(), InstanceComparator(instance), &index))
         return;
 
     AutoMutateInstances guard(*this);
     instances_.erase(instances_.begin() + index);
 }
 
-struct PCComparator
-{
-    const void* pc;
-    explicit PCComparator(const void* pc) : pc(pc) {}
-
-    int operator()(const Instance* instance) const {
-        if (instance->codeSegment(Tier::TBD).containsCodePC(pc))
-            return 0;
-        return pc < instance->codeBase(Tier::TBD) ? -1 : 1;
-    }
-};
-
 const Code*
 Compartment::lookupCode(const void* pc, const CodeSegment** segmentp) const
 {
     // lookupCode() can be called asynchronously from the interrupt signal
     // handler. In that case, the signal handler is just asking whether the pc
     // is in wasm code. If instances_ is being mutated then we can't be
     // executing wasm code so returning nullptr is fine.
     if (mutatingInstances_)
         return nullptr;
 
-    size_t index;
-    if (!BinarySearchIf(instances_, 0, instances_.length(), PCComparator(pc), &index))
-        return nullptr;
+    // Linear search because instances are only ordered by their first tiers,
+    // but may have two.  This code should not be hot anyway, we avoid
+    // lookupCode when we can.
+    for (auto i : instances_) {
+        const Code& code = i->code();
+        for (auto t : code.tiers()) {
+            const CodeSegment& segment = code.segment(t);
+            if (segment.containsCodePC(pc)) {
+                if (segmentp)
+                    *segmentp = &segment;
+                return &code;
+            }
+        }
+    }
 
-    const Code& code = instances_[index]->code();
-    if (segmentp)
-        *segmentp = &code.segment(Tier::TBD);
-    return &code;
+    return nullptr;
 }
 
 void
 Compartment::ensureProfilingLabels(bool profilingEnabled)
 {
     for (Instance* instance : instances_)
         instance->ensureProfilingLabels(profilingEnabled);
 }
--- a/js/src/wasm/WasmCompile.cpp
+++ b/js/src/wasm/WasmCompile.cpp
@@ -13,18 +13,22 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "wasm/WasmCompile.h"
 
+#include "mozilla/Maybe.h"
+#include "mozilla/Unused.h"
+
 #include "jsprf.h"
 
+#include "wasm/WasmBaselineCompile.h"
 #include "wasm/WasmBinaryIterator.h"
 #include "wasm/WasmGenerator.h"
 #include "wasm/WasmSignalHandlers.h"
 #include "wasm/WasmValidate.h"
 
 using namespace js;
 using namespace js::jit;
 using namespace js::wasm;
@@ -88,48 +92,213 @@ DecodeCodeSection(Decoder& d, ModuleGene
         return false;
 
     return mg.finishFuncDefs();
 }
 
 bool
 CompileArgs::initFromContext(JSContext* cx, ScriptedCaller&& scriptedCaller)
 {
-    alwaysBaseline = cx->options().wasmAlwaysBaseline();
+    baselineEnabled = cx->options().wasmBaseline();
+
+    // For sanity's sake, just use Ion if both compilers are disabled.
+    ionEnabled = cx->options().wasmIon() || !cx->options().wasmBaseline();
 
     // Debug information such as source view or debug traps will require
     // additional memory and permanently stay in baseline code, so we try to
     // only enable it when a developer actually cares: when the debugger tab
     // is open.
     debugEnabled = cx->compartment()->debuggerObservesAsmJS();
 
     this->scriptedCaller = Move(scriptedCaller);
     return assumptions.initBuildIdFromContext(cx);
 }
 
+static void
+CompilerAvailability(ModuleKind kind, const CompileArgs& args, bool* baselineEnabled,
+                     bool* debugEnabled, bool* ionEnabled)
+{
+    bool baselinePossible = kind == ModuleKind::Wasm && BaselineCanCompile();
+    *baselineEnabled = baselinePossible && args.baselineEnabled;
+    *debugEnabled = baselinePossible && args.debugEnabled;
+    *ionEnabled = args.ionEnabled;
+
+    // Default to Ion if necessary: We will never get to this point on platforms
+    // that don't have Ion at all, so this can happen if the user has disabled
+    // both compilers or if she has disabled Ion but baseline can't compile the
+    // code.
+
+    if (!(*baselineEnabled || *ionEnabled))
+        *ionEnabled = true;
+}
+
+static bool
+BackgroundWorkPossible()
+{
+    return CanUseExtraThreads() && HelperThreadState().cpuCount > 1;
+}
+
+bool
+wasm::GetDebugEnabled(const CompileArgs& args, ModuleKind kind)
+{
+    bool baselineEnabled, debugEnabled, ionEnabled;
+    CompilerAvailability(kind, args, &baselineEnabled, &debugEnabled, &ionEnabled);
+
+    return debugEnabled;
+}
+
+wasm::CompileMode
+wasm::GetInitialCompileMode(const CompileArgs& args, ModuleKind kind)
+{
+    bool baselineEnabled, debugEnabled, ionEnabled;
+    CompilerAvailability(kind, args, &baselineEnabled, &debugEnabled, &ionEnabled);
+
+    return BackgroundWorkPossible() && baselineEnabled && ionEnabled && !debugEnabled
+           ? CompileMode::Tier1
+           : CompileMode::Once;
+}
+
+wasm::Tier
+wasm::GetTier(const CompileArgs& args, CompileMode compileMode, ModuleKind kind)
+{
+    bool baselineEnabled, debugEnabled, ionEnabled;
+    CompilerAvailability(kind, args, &baselineEnabled, &debugEnabled, &ionEnabled);
+
+    switch (compileMode) {
+      case CompileMode::Tier1:
+        MOZ_ASSERT(baselineEnabled);
+        return Tier::Baseline;
+
+      case CompileMode::Tier2:
+        MOZ_ASSERT(ionEnabled);
+        return Tier::Ion;
+
+      case CompileMode::Once:
+        return (debugEnabled || !ionEnabled) ? Tier::Baseline : Tier::Ion;
+
+      default:
+        MOZ_CRASH("Bad mode");
+    }
+}
+
+namespace js {
+namespace wasm {
+
+struct Tier2GeneratorTask
+{
+    // The module that wants the results of the compilation.
+    SharedModule            module;
+
+    // The arguments for the compilation.
+    SharedCompileArgs       compileArgs;
+
+    // A flag that is set by the cancellation code and checked by any running
+    // module generator to short-circuit compilation.
+    mozilla::Atomic<bool>   cancelled;
+
+    Tier2GeneratorTask(Module& module, const CompileArgs& compileArgs)
+      : module(&module),
+        compileArgs(&compileArgs),
+        cancelled(false)
+    {}
+};
+
+}
+}
+
+static bool
+Compile(ModuleGenerator& mg, const ShareableBytes& bytecode, const CompileArgs& args,
+        UniqueChars* error, CompileMode compileMode)
+{
+    auto env = js::MakeUnique<ModuleEnvironment>();
+    if (!env)
+        return false;
+
+    Decoder d(bytecode.bytes, error);
+    if (!DecodeModuleEnvironment(d, env.get()))
+        return false;
+
+    if (!mg.init(Move(env), args, compileMode))
+        return false;
+
+    if (!DecodeCodeSection(d, mg))
+        return false;
+
+    if (!DecodeModuleTail(d, &mg.mutableEnv()))
+        return false;
+
+    return true;
+}
+
+
 SharedModule
 wasm::Compile(const ShareableBytes& bytecode, const CompileArgs& args, UniqueChars* error)
 {
     MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
 
-    Decoder d(bytecode.bytes, error);
-
-    auto env = js::MakeUnique<ModuleEnvironment>();
-    if (!env)
-        return nullptr;
-
-    if (!DecodeModuleEnvironment(d, env.get()))
-        return nullptr;
+    ModuleGenerator mg(error, nullptr);
 
-    ModuleGenerator mg(error);
-    if (!mg.init(Move(env), args))
-        return nullptr;
-
-    if (!DecodeCodeSection(d, mg))
-        return nullptr;
-
-    if (!DecodeModuleTail(d, &mg.mutableEnv()))
+    CompileMode mode = GetInitialCompileMode(args);
+    if (!::Compile(mg, bytecode, args, error, mode))
         return nullptr;
 
     MOZ_ASSERT(!*error, "unreported error in decoding");
 
-    return mg.finish(bytecode);
+    SharedModule module = mg.finishModule(bytecode);
+    if (!module)
+        return nullptr;
+
+    if (mode == CompileMode::Tier1) {
+        MOZ_ASSERT(BackgroundWorkPossible());
+
+        auto task = js::MakeUnique<Tier2GeneratorTask>(*module, args);
+        if (!task) {
+            module->unblockOnTier2GeneratorFinished(CompileMode::Once);
+            return nullptr;
+        }
+
+        if (!StartOffThreadWasmTier2Generator(&*task)) {
+            module->unblockOnTier2GeneratorFinished(CompileMode::Once);
+            return nullptr;
+        }
+
+        mozilla::Unused << task.release();
+    }
+
+    return module;
 }
+
+// This runs on a helper thread.
+bool
+wasm::GenerateTier2(Tier2GeneratorTask* task)
+{
+    UniqueChars     error;
+    ModuleGenerator mg(&error, &task->cancelled);
+
+    bool res =
+        ::Compile(mg, task->module->bytecode(), *task->compileArgs, &error, CompileMode::Tier2) &&
+        mg.finishTier2(task->module->bytecode(), task->module);
+
+    // If the task was cancelled then res will be false.
+    task->module->unblockOnTier2GeneratorFinished(res ? CompileMode::Tier2 : CompileMode::Once);
+
+    return res;
+}
+
+// This runs on the main thread.  The task will be deleted in the HelperThread
+// system.
+void
+wasm::CancelTier2GeneratorTask(Tier2GeneratorTask* task)
+{
+    task->cancelled = true;
+
+    // GenerateTier2 will also unblock and set the mode to Once, after the
+    // compilation fails, if the compilation gets to run at all.  Do it here in
+    // any case - there's no reason to wait, and we won't be depending on
+    // anything else happening.
+    task->module->unblockOnTier2GeneratorFinished(CompileMode::Once);
+}
+
+void
+wasm::DeleteTier2GeneratorTask(Tier2GeneratorTask* task)
+{
+    js_delete(task);
+}
--- a/js/src/wasm/WasmCompile.h
+++ b/js/src/wasm/WasmCompile.h
@@ -30,41 +30,71 @@ struct ScriptedCaller
 {
     UniqueChars filename;
     unsigned line;
     unsigned column;
 };
 
 // Describes all the parameters that control wasm compilation.
 
-struct CompileArgs
+struct CompileArgs : ShareableBase<CompileArgs>
 {
     Assumptions assumptions;
     ScriptedCaller scriptedCaller;
-    bool alwaysBaseline;
+    bool baselineEnabled;
     bool debugEnabled;
+    bool ionEnabled;
 
     CompileArgs(Assumptions&& assumptions, ScriptedCaller&& scriptedCaller)
       : assumptions(Move(assumptions)),
         scriptedCaller(Move(scriptedCaller)),
-        alwaysBaseline(false),
-        debugEnabled(false)
+        baselineEnabled(false),
+        debugEnabled(false),
+        ionEnabled(false)
     {}
 
     // If CompileArgs is constructed without arguments, initFromContext() must
     // be called to complete initialization.
     CompileArgs() = default;
     bool initFromContext(JSContext* cx, ScriptedCaller&& scriptedCaller);
 };
 
+typedef RefPtr<CompileArgs> MutableCompileArgs;
+typedef RefPtr<const CompileArgs> SharedCompileArgs;
+
 // Compile the given WebAssembly bytecode with the given arguments into a
 // wasm::Module. On success, the Module is returned. On failure, the returned
 // SharedModule pointer is null and either:
 //  - *error points to a string description of the error
 //  - *error is null and the caller should report out-of-memory.
 
 SharedModule
 Compile(const ShareableBytes& bytecode, const CompileArgs& args, UniqueChars* error);
 
+// Select whether debugging is available based on the available compilers, the
+// configuration options, and the nature of the module.  Note debugging can be
+// unavailable even if selected, if Rabaldr is unavailable or the module is not
+// compilable by Rabaldr.
+
+bool
+GetDebugEnabled(const CompileArgs& args, ModuleKind kind = ModuleKind::Wasm);
+
+// Select the mode for the initial compilation of a module.  The mode is "Tier1"
+// precisely if both compilers are available, we're not debugging, and it is
+// possible to compile in the background, and in that case, we'll compile twice,
+// with the mode set to "Tier2" during the second (background) compilation.
+// Otherwise, the tier is "Once" and we'll compile once, with the appropriate
+// compiler.
+
+CompileMode
+GetInitialCompileMode(const CompileArgs& args, ModuleKind kind = ModuleKind::Wasm);
+
+// Select the tier for a compilation.  The tier is Tier::Baseline if we're
+// debugging, if Baldr is not available, or if both compilers are are available
+// and the compileMode is Tier1; otherwise the tier is Tier::Ion.
+
+Tier
+GetTier(const CompileArgs& args, CompileMode compileMode, ModuleKind kind = ModuleKind::Wasm);
+
 }  // namespace wasm
 }  // namespace js
 
 #endif // namespace wasm_compile_h
--- a/js/src/wasm/WasmDebug.h
+++ b/js/src/wasm/WasmDebug.h
@@ -28,20 +28,20 @@ namespace js {
 class Debugger;
 class WasmActivation;
 class WasmBreakpoint;
 class WasmBreakpointSite;
 class WasmInstanceObject;
 
 namespace wasm {
 
-struct LinkData;
 struct LinkDataTier;
 struct MetadataTier;
 class FrameIterator;
+class LinkData;
 
 // The generated source location for the AST node/expression. The offset field refers
 // an offset in an binary format file.
 
 struct ExprLoc
 {
     uint32_t lineno;
     uint32_t column;
--- a/js/src/wasm/WasmFrameIter.cpp
+++ b/js/src/wasm/WasmFrameIter.cpp
@@ -55,19 +55,18 @@ WasmFrameIter::WasmFrameIter(WasmActivat
 
     // When asynchronously interrupted, exitFP is set to the interrupted frame
     // itself and so we do not want to skip it. Instead, we can recover the
     // Code and CodeRange from the WasmActivation, which are set when control
     // flow was interrupted. There is no CallSite (b/c the interrupt was async),
     // but this is fine because CallSite is only used for line number for which
     // we can use the beginning of the function from the CodeRange instead.
 
-    code_ = activation_->compartment()->wasm.lookupCode(activation->unwindPC());
-    MOZ_ASSERT(code_);
-    MOZ_ASSERT(&fp_->tls->instance->code() == code_);
+    code_ = &fp_->tls->instance->code();
+    MOZ_ASSERT(code_ == activation->compartment()->wasm.lookupCode(activation->unwindPC()));
 
     codeRange_ = code_->lookupRange(activation->unwindPC());
     MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
 
     MOZ_ASSERT(!done());
 }
 
 bool
@@ -119,18 +118,18 @@ WasmFrameIter::popFrame()
         }
 
         MOZ_ASSERT(done());
         return;
     }
 
     void* returnAddress = prevFP->returnAddress;
 
-    code_ = activation_->compartment()->wasm.lookupCode(returnAddress);
-    MOZ_ASSERT(code_);
+    code_ = &fp_->tls->instance->code();
+    MOZ_ASSERT(code_ == activation_->compartment()->wasm.lookupCode(returnAddress));
 
     codeRange_ = code_->lookupRange(returnAddress);
     MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
 
     callsite_ = code_->lookupCallSite(returnAddress);
     MOZ_ASSERT(callsite_);
 
     MOZ_ASSERT(!done());
@@ -313,17 +312,17 @@ LoadActivation(MacroAssembler& masm, Reg
     masm.loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, addressOfContext)), dest);
     masm.loadPtr(Address(dest, 0), dest);
     masm.loadPtr(Address(dest, JSContext::offsetOfActivation()), dest);
     masm.loadPtr(Address(dest, Activation::offsetOfPrev()), dest);
 }
 
 static void
 GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
-                         uint32_t* entry)
+                         uint32_t* entry, uint32_t* tierEntry, CompileMode mode, uint32_t funcIndex)
 {
     // ProfilingFrameIterator needs to know the offsets of several key
     // instructions from entry. To save space, we make these offsets static
     // constants and assert that they match the actual codegen below. On ARM,
     // this requires AutoForbidPools to prevent a constant pool from being
     // randomly inserted between two instructions.
     {
 #if defined(JS_CODEGEN_ARM)
@@ -338,16 +337,40 @@ GenerateCallablePrologue(MacroAssembler&
         masm.push(Imm32(reason.encode()));
         MOZ_ASSERT_IF(!masm.oom(), PushedExitReason == masm.currentOffset() - *entry);
         masm.push(FramePointer);
         MOZ_ASSERT_IF(!masm.oom(), PushedFP == masm.currentOffset() - *entry);
         masm.moveStackPtrTo(FramePointer);
         MOZ_ASSERT_IF(!masm.oom(), SetFP == masm.currentOffset() - *entry);
     }
 
+    // Tiering works as follows.  The Code owns a jumpTable, which has one
+    // pointer-sized element for each function up to the largest funcIndex in
+    // the module.  Each table element is an address into the Tier-1 or the
+    // Tier-2 function at that index; the elements are updated when Tier-2 code
+    // becomes available.  The Tier-1 function will unconditionally jump to this
+    // address.  The table elements are written racily but without tearing when
+    // Tier-2 compilation is finished.
+    //
+    // The address in the table is either to the instruction following the jump
+    // in Tier-1 code, or into the function prologue after the standard setup in
+    // Tier-2 code.  Effectively, Tier-1 code performs standard frame setup on
+    // behalf of whatever code it jumps to, and the target code allocates its
+    // own frame in whatever way it wants.
+
+    if (reason.isNone()) {
+        if (mode == CompileMode::Tier1) {
+            Register scratch = ABINonArgReg0;
+            masm.loadPtr(Address(WasmTlsReg, offsetof(TlsData, jumpTable)), scratch);
+            masm.jump(Address(scratch, funcIndex*sizeof(uintptr_t)));
+        }
+        if (tierEntry)
+            *tierEntry = masm.currentOffset();
+    }
+
     if (!reason.isNone()) {
         Register act = ABINonArgReg0;
 
         // Native callers expect the native ABI, which assume that non-saved
         // registers are preserved. Explicitly preserve the act register
         // in that case.
         if (reason.isNative() && !act.volatile_())
             masm.Push(act);
@@ -423,17 +446,17 @@ GenerateCallableEpilogue(MacroAssembler&
     masm.ret();
 
     MOZ_ASSERT_IF(!masm.oom(), PoppedFP == *ret - poppedFP);
     MOZ_ASSERT_IF(!masm.oom(), PoppedExitReason == *ret - poppedExitReason);
 }
 
 void
 wasm::GenerateFunctionPrologue(MacroAssembler& masm, unsigned framePushed, const SigIdDesc& sigId,
-                               FuncOffsets* offsets)
+                               FuncOffsets* offsets, CompileMode mode, uint32_t funcIndex)
 {
     // Flush pending pools so they do not get dumped between the 'begin' and
     // 'normalEntry' offsets since the difference must be less than UINT8_MAX
     // to be stored in CodeRange::funcBeginToNormalEntry_.
     masm.flushBuffer();
     masm.haltingAlign(CodeAlignment);
 
     // Generate table entry:
@@ -456,17 +479,18 @@ wasm::GenerateFunctionPrologue(MacroAsse
     }
 
     // The table entry might have generated a small constant pool in case of
     // immediate comparison.
     masm.flushBuffer();
 
     // Generate normal entry:
     masm.nopAlign(CodeAlignment);
-    GenerateCallablePrologue(masm, framePushed, ExitReason::None(), &offsets->normalEntry);
+    GenerateCallablePrologue(masm, framePushed, ExitReason::None(), &offsets->normalEntry,
+                             &offsets->tierEntry, mode, funcIndex);
 
     masm.setFramePushed(framePushed);
 }
 
 void
 wasm::GenerateFunctionEpilogue(MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets)
 {
     MOZ_ASSERT(masm.framePushed() == framePushed);
@@ -474,17 +498,18 @@ wasm::GenerateFunctionEpilogue(MacroAsse
     masm.setFramePushed(0);
 }
 
 void
 wasm::GenerateExitPrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
                            CallableOffsets* offsets)
 {
     masm.haltingAlign(CodeAlignment);
-    GenerateCallablePrologue(masm, framePushed, reason, &offsets->begin);
+    GenerateCallablePrologue(masm, framePushed, reason, &offsets->begin, nullptr,
+                             CompileMode::Once, 0);
     masm.setFramePushed(framePushed);
 }
 
 void
 wasm::GenerateExitEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
                            CallableOffsets* offsets)
 {
     // Inverse of GenerateExitPrologue:
@@ -795,40 +820,46 @@ ProfilingFrameIterator::operator++()
 
     if (!callerPC_) {
         MOZ_ASSERT(!callerFP_);
         codeRange_ = nullptr;
         MOZ_ASSERT(done());
         return;
     }
 
-    code_ = activation_->compartment()->wasm.lookupCode(callerPC_);
-    MOZ_ASSERT(code_);
+    if (!callerFP_) {
+        codeRange_ = code_->lookupRange(callerPC_);
+        MOZ_ASSERT(codeRange_->kind() == CodeRange::Entry);
+        callerPC_ = nullptr;
+        MOZ_ASSERT(!done());
+        return;
+    }
+
+    code_ = &callerFP_->tls->instance->code();
+    MOZ_ASSERT(code_ == activation_->compartment()->wasm.lookupCode(callerPC_));
 
     codeRange_ = code_->lookupRange(callerPC_);
     MOZ_ASSERT(codeRange_);
 
     switch (codeRange_->kind()) {
-      case CodeRange::Entry:
-        MOZ_ASSERT(callerFP_ == nullptr);
-        callerPC_ = nullptr;
-        break;
       case CodeRange::Function:
       case CodeRange::ImportJitExit:
       case CodeRange::ImportInterpExit:
       case CodeRange::BuiltinThunk:
       case CodeRange::TrapExit:
       case CodeRange::DebugTrap:
       case CodeRange::Inline:
       case CodeRange::FarJumpIsland:
         stackAddress_ = callerFP_;
         callerPC_ = callerFP_->returnAddress;
         AssertMatchesCallSite(*activation_, callerPC_, callerFP_->callerFP);
         callerFP_ = callerFP_->callerFP;
         break;
+      case CodeRange::Entry:
+        MOZ_CRASH("should have had null caller fp");
       case CodeRange::Interrupt:
       case CodeRange::Throw:
         MOZ_CRASH("code range doesn't have frame");
     }
 
     MOZ_ASSERT(!done());
 }
 
@@ -988,41 +1019,37 @@ ProfilingFrameIterator::label() const
       case CodeRange::Throw:             MOZ_FALLTHROUGH;
       case CodeRange::Interrupt:         MOZ_CRASH("does not have a frame");
     }
 
     MOZ_CRASH("bad code range kind");
 }
 
 Instance*
-wasm::LookupFaultingInstance(WasmActivation* activation, void* pc, void* fp)
+wasm::LookupFaultingInstance(const Code& code, void* pc, void* fp)
 {
     // Assume bug-caused faults can be raised at any PC and apply the logic of
     // ProfilingFrameIterator to reject any pc outside the (post-prologue,
     // pre-epilogue) body of a wasm function. This is exhaustively tested by the
     // simulators which call this function at every load/store before even
     // knowing whether there is a fault.
 
-    const Code* code = activation->compartment()->wasm.lookupCode(pc);
-    if (!code)
-        return nullptr;
-
     const CodeSegment* codeSegment;
-    const CodeRange* codeRange = code->lookupRange(pc, &codeSegment);
+    const CodeRange* codeRange = code.lookupRange(pc, &codeSegment);
     if (!codeRange || !codeRange->isFunction())
         return nullptr;
 
     size_t offsetInModule = ((uint8_t*)pc) - codeSegment->base();
     if (offsetInModule < codeRange->funcNormalEntry() + SetFP)
         return nullptr;
     if (offsetInModule >= codeRange->ret() - PoppedFP)
         return nullptr;
 
     Instance* instance = reinterpret_cast<Frame*>(fp)->tls->instance;
-    MOZ_RELEASE_ASSERT(&instance->code() == code);
+    MOZ_RELEASE_ASSERT(&instance->code() == &code);
     return instance;
 }
 
 WasmActivation*
 wasm::ActivationIfInnermost(JSContext* cx)
 {
     // WasmCall pushes both an outer WasmActivation and an inner JitActivation
     // that only becomes active when calling JIT code.
--- a/js/src/wasm/WasmFrameIter.h
+++ b/js/src/wasm/WasmFrameIter.h
@@ -15,16 +15,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef wasm_frame_iter_h
 #define wasm_frame_iter_h
 
 #include "js/ProfilingFrameIterator.h"
+#include "wasm/WasmTypes.h"
 
 class JSAtom;
 
 namespace js {
 
 class WasmActivation;
 namespace jit { class MacroAssembler; }
 
@@ -180,25 +181,26 @@ class ProfilingFrameIterator
 void
 GenerateExitPrologue(jit::MacroAssembler& masm, unsigned framePushed, ExitReason reason,
                      CallableOffsets* offsets);
 void
 GenerateExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed, ExitReason reason,
                      CallableOffsets* offsets);
 void
 GenerateFunctionPrologue(jit::MacroAssembler& masm, unsigned framePushed, const SigIdDesc& sigId,
-                         FuncOffsets* offsets);
+                         FuncOffsets* offsets, CompileMode mode = CompileMode::Once,
+                         uint32_t funcIndex = 0);
 void
 GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets);
 
 // Given a fault at pc with register fp, return the faulting instance if there
 // is such a plausible instance, and otherwise null.
 
 Instance*
-LookupFaultingInstance(WasmActivation* activation, void* pc, void* fp);
+LookupFaultingInstance(const Code& code, void* pc, void* fp);
 
 // If the innermost (active) Activation is a WasmActivation, return it.
 
 WasmActivation*
 ActivationIfInnermost(JSContext* cx);
 
 // Return whether the given PC is in wasm code.
 
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -40,19 +40,21 @@ using mozilla::MakeEnumeratedRange;
 
 // ****************************************************************************
 // ModuleGenerator
 
 static const unsigned GENERATOR_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
 static const unsigned COMPILATION_LIFO_DEFAULT_CHUNK_SIZE = 64 * 1024;
 static const uint32_t BAD_CODE_RANGE = UINT32_MAX;
 
-ModuleGenerator::ModuleGenerator(UniqueChars* error)
+ModuleGenerator::ModuleGenerator(UniqueChars* error, mozilla::Atomic<bool>* cancelled)
   : tier_(Tier(-1)),
+    compileMode_(CompileMode::Once),
     error_(error),
+    cancelled_(cancelled),
     linkDataTier_(nullptr),
     metadataTier_(nullptr),
     numSigs_(0),
     numTables_(0),
     lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
     masmAlloc_(&lifo_),
     masm_(MacroAssembler::WasmToken(), masmAlloc_),
     lastPatchedCallsite_(0),
@@ -71,52 +73,52 @@ ModuleGenerator::ModuleGenerator(UniqueC
 
 ModuleGenerator::~ModuleGenerator()
 {
     if (parallel_) {
         // Wait for any outstanding jobs to fail or complete.
         if (outstanding_) {
             AutoLockHelperThreadState lock;
             while (true) {
-                CompileTaskPtrVector& worklist = HelperThreadState().wasmWorklist(lock);
+                CompileTaskPtrVector& worklist = HelperThreadState().wasmWorklist(lock, compileMode_);
                 MOZ_ASSERT(outstanding_ >= worklist.length());
                 outstanding_ -= worklist.length();
                 worklist.clear();
 
-                CompileTaskPtrVector& finished = HelperThreadState().wasmFinishedList(lock);
+                CompileTaskPtrVector& finished = HelperThreadState().wasmFinishedList(lock, compileMode_);
                 MOZ_ASSERT(outstanding_ >= finished.length());
                 outstanding_ -= finished.length();
                 finished.clear();
 
-                uint32_t numFailed = HelperThreadState().harvestFailedWasmJobs(lock);
+                uint32_t numFailed = HelperThreadState().harvestFailedWasmJobs(lock, compileMode_);
                 MOZ_ASSERT(outstanding_ >= numFailed);
                 outstanding_ -= numFailed;
 
                 if (!outstanding_)
                     break;
 
                 HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
             }
         }
 
-        MOZ_ASSERT(HelperThreadState().wasmCompilationInProgress);
-        HelperThreadState().wasmCompilationInProgress = false;
+        MOZ_ASSERT(HelperThreadState().wasmCompilationInProgress(compileMode_));
+        HelperThreadState().wasmCompilationInProgress(compileMode_) = false;
     } else {
         MOZ_ASSERT(!outstanding_);
     }
     MOZ_ASSERT_IF(finishedFuncDefs_, !batchedBytecode_);
     MOZ_ASSERT_IF(finishedFuncDefs_, !currentTask_);
 }
 
 bool
 ModuleGenerator::initAsmJS(Metadata* asmJSMetadata)
 {
     MOZ_ASSERT(env_->isAsmJS());
 
-    if (!linkData_.initTier(Tier::Ion))
+    if (!linkData_.initTier1(Tier::Ion, *asmJSMetadata))
         return false;
     linkDataTier_ = &linkData_.linkData(Tier::Ion);
 
     metadataTier_ = &asmJSMetadata->metadata(Tier::Ion);
     metadata_ = asmJSMetadata;
     MOZ_ASSERT(isAsmJS());
 
     // Enabling debugging requires baseline and baseline is only enabled for
@@ -136,39 +138,35 @@ ModuleGenerator::initAsmJS(Metadata* asm
     return true;
 }
 
 bool
 ModuleGenerator::initWasm(const CompileArgs& args)
 {
     MOZ_ASSERT(!env_->isAsmJS());
 
-    bool canBaseline = BaselineCanCompile();
-    bool debugEnabled = args.debugEnabled && canBaseline;
-    tier_ = ((args.alwaysBaseline || debugEnabled) && canBaseline)
-            ? Tier::Baseline
-            : Tier::Ion;
-
-    if (!linkData_.initTier(tier_))
-        return false;
-    linkDataTier_ = &linkData_.linkData(tier_);
+    tier_ = GetTier(args, compileMode_);
 
     auto metadataTier = js::MakeUnique<MetadataTier>(tier_);
     if (!metadataTier)
         return false;
 
     metadata_ = js_new<Metadata>(Move(metadataTier));
     if (!metadata_)
         return false;
 
     metadataTier_ = &metadata_->metadata(tier_);
 
+    if (!linkData_.initTier1(tier_, *metadata_))
+        return false;
+    linkDataTier_ = &linkData_.linkData(tier_);
+
     MOZ_ASSERT(!isAsmJS());
 
-    metadata_->debugEnabled = debugEnabled;
+    metadata_->debugEnabled = GetDebugEnabled(args);
 
     // For wasm, the Vectors are correctly-sized and already initialized.
 
     numSigs_ = env_->sigs.length();
     numTables_ = env_->tables.length();
 
     for (size_t i = 0; i < env_->funcImportGlobalDataOffsets.length(); i++) {
         env_->funcImportGlobalDataOffsets[i] = metadata_->globalDataLength;
@@ -234,19 +232,20 @@ ModuleGenerator::initWasm(const CompileA
         }
     }
 
     return true;
 }
 
 bool
 ModuleGenerator::init(UniqueModuleEnvironment env, const CompileArgs& args,
-                      Metadata* maybeAsmJSMetadata)
+                      CompileMode compileMode, Metadata* maybeAsmJSMetadata)
 {
     env_ = Move(env);
+    compileMode_ = compileMode;
 
     if (!funcToCodeRange_.appendN(BAD_CODE_RANGE, env_->funcSigs.length()))
         return false;
 
     if (!assumptions_.clone(args.assumptions))
         return false;
 
     if (!exportedFuncs_.init())
@@ -278,27 +277,27 @@ ModuleGenerator::finishOutstandingTask()
     MOZ_ASSERT(parallel_);
 
     CompileTask* task = nullptr;
     {
         AutoLockHelperThreadState lock;
         while (true) {
             MOZ_ASSERT(outstanding_ > 0);
 
-            if (HelperThreadState().wasmFailed(lock)) {
+            if (HelperThreadState().wasmFailed(lock, compileMode_)) {
                 if (error_) {
                     MOZ_ASSERT(!*error_, "Should have stopped earlier");
-                    *error_ = Move(HelperThreadState().harvestWasmError(lock));
+                    *error_ = Move(HelperThreadState().harvestWasmError(lock, compileMode_));
                 }
                 return false;
             }
 
-            if (!HelperThreadState().wasmFinishedList(lock).empty()) {
+            if (!HelperThreadState().wasmFinishedList(lock, compileMode_).empty()) {
                 outstanding_--;
-                task = HelperThreadState().wasmFinishedList(lock).popCopy();
+                task = HelperThreadState().wasmFinishedList(lock, compileMode_).popCopy();
                 break;
             }
 
             HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
         }
     }
 
     return finishTask(task);
@@ -883,36 +882,40 @@ ModuleGenerator::startFuncDefs()
     // blocking.
 
     GlobalHelperThreadState& threads = HelperThreadState();
     MOZ_ASSERT(threads.threadCount > 1);
 
     uint32_t numTasks;
     if (CanUseExtraThreads() &&
         threads.cpuCount > 1 &&
-        threads.wasmCompilationInProgress.compareExchange(false, true))
+        threads.wasmCompilationInProgress(compileMode_).compareExchange(false, true))
     {
 #ifdef DEBUG
         {
             AutoLockHelperThreadState lock;
-            MOZ_ASSERT(!HelperThreadState().wasmFailed(lock));
-            MOZ_ASSERT(HelperThreadState().wasmWorklist(lock).empty());
-            MOZ_ASSERT(HelperThreadState().wasmFinishedList(lock).empty());
+            MOZ_ASSERT(!HelperThreadState().wasmFailed(lock, compileMode_));
+            MOZ_ASSERT(HelperThreadState().wasmWorklist(lock, compileMode_).empty());
+            MOZ_ASSERT(HelperThreadState().wasmFinishedList(lock, compileMode_).empty());
         }
 #endif
         parallel_ = true;
         numTasks = 2 * threads.maxWasmCompilationThreads();
     } else {
         numTasks = 1;
     }
 
     if (!tasks_.initCapacity(numTasks))
         return false;
-    for (size_t i = 0; i < numTasks; i++)
-        tasks_.infallibleEmplaceBack(*env_, tier_, COMPILATION_LIFO_DEFAULT_CHUNK_SIZE);
+    for (size_t i = 0; i < numTasks; i++) {
+        tasks_.infallibleEmplaceBack(*env_,
+                                     tier_,
+                                     compileMode_,
+                                     COMPILATION_LIFO_DEFAULT_CHUNK_SIZE);
+    }
 
     if (!freeTasks_.reserve(numTasks))
         return false;
     for (size_t i = 0; i < numTasks; i++)
         freeTasks_.infallibleAppend(&tasks_[i]);
 
     startedFuncDefs_ = true;
     MOZ_ASSERT(!finishedFuncDefs_);
@@ -947,23 +950,26 @@ ModuleGenerator::startFuncDef(uint32_t l
     return true;
 }
 
 bool
 ModuleGenerator::launchBatchCompile()
 {
     MOZ_ASSERT(currentTask_);
 
+    if (cancelled_ && *cancelled_)
+        return false;
+
     currentTask_->setDebugEnabled(metadata_->debugEnabled);
 
     size_t numBatchedFuncs = currentTask_->units().length();
     MOZ_ASSERT(numBatchedFuncs);
 
     if (parallel_) {
-        if (!StartOffThreadWasmCompile(currentTask_))
+        if (!StartOffThreadWasmCompile(currentTask_, compileMode_))
             return false;
         outstanding_++;
     } else {
         if (!CompileFunction(currentTask_, error_))
             return false;