Merge mozilla-inbound to mozilla-central. a=merge
authorCosmin Sabou <csabou@mozilla.com>
Tue, 13 Nov 2018 06:23:01 +0200
changeset 445981 f6df375b86987b2772067a61873ebfe3a98c353a
parent 445927 d056f0ff51c05e69ab26e690a42238b53a52d1a8 (current diff)
parent 445980 17243a560006c6db1f9e4cc0fea57a8ae29b1dbc (diff)
child 445985 0557cad00db4733570bbf912c0fe9fc8641ac004
child 446017 c3fe7a80a8e84e859b76a16bb49395911fef5f17
push id35030
push usercsabou@mozilla.com
push dateTue, 13 Nov 2018 04:24:01 +0000
treeherdermozilla-central@f6df375b8698 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone65.0a1
first release with
nightly linux32
f6df375b8698 / 65.0a1 / 20181113100051 / files
nightly linux64
f6df375b8698 / 65.0a1 / 20181113100051 / files
nightly mac
f6df375b8698 / 65.0a1 / 20181113100051 / files
nightly win32
f6df375b8698 / 65.0a1 / 20181113100051 / files
nightly win64
f6df375b8698 / 65.0a1 / 20181113100051 / 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 mozilla-inbound to mozilla-central. a=merge
layout/style/ServoCSSPropList.mako.py
layout/style/test/property_database.js
--- a/browser/base/content/test/static/browser_parsable_css.js
+++ b/browser/base/content/test/static/browser_parsable_css.js
@@ -43,16 +43,20 @@ let whitelist = [
    errorMessage: /Unknown property.*overflow-clip-box/i,
    isFromDevTools: false},
   // The '-moz-menulist-button' value is only supported in chrome and UA sheets
   // but forms.css is loaded as a document sheet by this test.
   // Maybe bug 1261237 will fix this?
   {sourceName: /(?:res|gre-resources)\/forms\.css$/i,
    errorMessage: /Error in parsing value for \u2018-moz-appearance\u2019/iu,
    isFromDevTools: false},
+  // -moz-user-select: -moz-text is only enabled to user-agent stylesheets.
+  {sourceName: /contenteditable.css$/i,
+   errorMessage: /Error in parsing value for \u2018-moz-user-select\u2019/iu,
+   isFromDevTools: false},
   // These variables are declared somewhere else, and error when we load the
   // files directly. They're all marked intermittent because their appearance
   // in the error console seems to not be consistent.
   {sourceName: /jsonview\/css\/general\.css$/i,
    intermittent: true,
    errorMessage: /Property contained reference to invalid variable.*color/i,
    isFromDevTools: true},
   {sourceName: /webide\/skin\/logs\.css$/i,
--- a/browser/config/mozconfigs/win32/mingwclang
+++ b/browser/config/mozconfigs/win32/mingwclang
@@ -20,16 +20,18 @@ unset MAKECAB
 #  build/mozconfig.automation
 #    MOZ_AUTOMATION_ flags
 #  build/mozconfig.rust
 #    TOOLTOOL_DIR
 #    RUSTC
 #    CARGO
 . "$topsrcdir/browser/config/mozconfigs/common"
 
+export MOZ_PACKAGE_JSSHELL=1
+
 # MinGW Stuff
 ac_add_options --target=i686-w64-mingw32
 ac_add_options --with-toolchain-prefix=i686-w64-mingw32-
 
 ac_add_options --disable-warnings-as-errors
 MOZ_COPY_PDBS=1
 
 # Temporary config settings until we get these working on mingw
--- a/browser/config/mozconfigs/win64/mingwclang
+++ b/browser/config/mozconfigs/win64/mingwclang
@@ -20,16 +20,18 @@ unset MAKECAB
 #  build/mozconfig.automation
 #    MOZ_AUTOMATION_ flags
 #  build/mozconfig.rust
 #    TOOLTOOL_DIR
 #    RUSTC
 #    CARGO
 . "$topsrcdir/browser/config/mozconfigs/common"
 
+export MOZ_PACKAGE_JSSHELL=1
+
 # MinGW Stuff
 ac_add_options --target=x86_64-w64-mingw32
 ac_add_options --with-toolchain-prefix=x86_64-w64-mingw32-
 
 ac_add_options --disable-warnings-as-errors
 MOZ_COPY_PDBS=1
 
 # Temporary config settings until we get these working on mingw
--- 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: 2.1.42
+Current extension version is: 2.1.52
 
-Taken from upstream commit: 2194aef0
+Taken from upstream commit: 4724ebbc
--- a/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
+++ b/browser/extensions/pdfjs/content/PdfStreamConverter.jsm
@@ -780,21 +780,19 @@ class RequestListener {
  */
 class FindEventManager {
   constructor(contentWindow) {
     this.contentWindow = contentWindow;
     this.winmm = contentWindow.docShell.messageManager;
   }
 
   bind() {
-    var unload = (evt) => {
+    this.contentWindow.addEventListener("unload", (evt) => {
       this.unbind();
-      this.contentWindow.removeEventListener(evt.type, unload);
-    };
-    this.contentWindow.addEventListener("unload", unload);
+    }, {once: true});
 
     // We cannot directly attach listeners to for the find events
     // since the FindBar is in the parent process. Instead we're
     // asking the PdfjsChromeUtils to do it for us and forward
     // all the find events to us.
     this.winmm.sendAsyncMessage("PDFJS:Parent:addEventListener");
     this.winmm.addMessageListener("PDFJS:Child:handleEvent", this);
   }
@@ -807,16 +805,17 @@ class FindEventManager {
     detail = Cu.cloneInto(detail, contentWindow);
     var forward = contentWindow.document.createEvent("CustomEvent");
     forward.initCustomEvent(type, true, true, detail);
     contentWindow.dispatchEvent(forward);
   }
 
   unbind() {
     this.winmm.sendAsyncMessage("PDFJS:Parent:removeEventListener");
+    this.winmm.removeMessageListener("PDFJS:Child:handleEvent", this);
   }
 }
 
 function PdfStreamConverter() {
 }
 
 PdfStreamConverter.prototype = {
   QueryInterface: ChromeUtils.generateQI([Ci.nsIStreamConverter, Ci.nsIStreamListener, Ci.nsIRequestObserver]),
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.1.42';
-var pdfjsBuild = '2194aef0';
+var pdfjsVersion = '2.1.52';
+var pdfjsBuild = '4724ebbc';
 var pdfjsSharedUtil = __w_pdfjs_require__(1);
 var pdfjsDisplayAPI = __w_pdfjs_require__(7);
 var pdfjsDisplayTextLayer = __w_pdfjs_require__(19);
 var pdfjsDisplayAnnotationLayer = __w_pdfjs_require__(20);
 var pdfjsDisplayDOMUtils = __w_pdfjs_require__(8);
 var pdfjsDisplaySVG = __w_pdfjs_require__(21);
 let pdfjsDisplayWorkerOptions = __w_pdfjs_require__(13);
 let pdfjsDisplayAPICompatibility = __w_pdfjs_require__(10);
@@ -4221,17 +4221,17 @@ function _fetchDocument(worker, source, 
     return Promise.reject(new Error('Worker was destroyed'));
   }
   if (pdfDataRangeTransport) {
     source.length = pdfDataRangeTransport.length;
     source.initialData = pdfDataRangeTransport.initialData;
   }
   return worker.messageHandler.sendWithPromise('GetDocRequest', {
     docId,
-    apiVersion: '2.1.42',
+    apiVersion: '2.1.52',
     source: {
       data: source.data,
       url: source.url,
       password: source.password,
       disableAutoFetch: source.disableAutoFetch,
       rangeChunkSize: source.rangeChunkSize,
       length: source.length
     },
@@ -5535,18 +5535,18 @@ var InternalRenderTask = function Intern
         }
       });
     }
   };
   return InternalRenderTask;
 }();
 var version, build;
 {
-  exports.version = version = '2.1.42';
-  exports.build = build = '2194aef0';
+  exports.version = version = '2.1.52';
+  exports.build = build = '4724ebbc';
 }
 exports.getDocument = getDocument;
 exports.LoopbackPort = LoopbackPort;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFWorker = PDFWorker;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 exports.setPDFNetworkStreamFactory = setPDFNetworkStreamFactory;
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -118,18 +118,18 @@ return /******/ (function(modules) { // 
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
 
 
-var pdfjsVersion = '2.1.42';
-var pdfjsBuild = '2194aef0';
+var pdfjsVersion = '2.1.52';
+var pdfjsBuild = '4724ebbc';
 var pdfjsCoreWorker = __w_pdfjs_require__(1);
 exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
 
 /***/ }),
 /* 1 */
 /***/ (function(module, exports, __w_pdfjs_require__) {
 
 "use strict";
@@ -321,17 +321,17 @@ var WorkerMessageHandler = {
     });
   },
   createDocumentHandler(docParams, port) {
     var pdfManager;
     var terminated = false;
     var cancelXHRs = null;
     var WorkerTasks = [];
     let apiVersion = docParams.apiVersion;
-    let workerVersion = '2.1.42';
+    let workerVersion = '2.1.52';
     if (apiVersion !== workerVersion) {
       throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
     }
     var docId = docParams.docId;
     var docBaseUrl = docParams.docBaseUrl;
     var workerHandlerName = docParams.docId + '_worker';
     var handler = new _message_handler.MessageHandler(workerHandlerName, docId, port);
     handler.postMessageTransfers = docParams.postMessageTransfers;
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -4040,29 +4040,31 @@ exports.PDFFindBar = PDFFindBar;
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.PDFFindController = exports.FindState = undefined;
 
+var _ui_utils = __webpack_require__(2);
+
 var _pdfjsLib = __webpack_require__(3);
 
 var _pdf_find_utils = __webpack_require__(16);
 
-var _ui_utils = __webpack_require__(2);
-
 const FindState = {
   FOUND: 0,
   NOT_FOUND: 1,
   WRAPPED: 2,
   PENDING: 3
 };
 const FIND_TIMEOUT = 250;
+const MATCH_SCROLL_OFFSET_TOP = -50;
+const MATCH_SCROLL_OFFSET_LEFT = -400;
 const CHARACTERS_TO_NORMALIZE = {
   '\u2018': '\'',
   '\u2019': '\'',
   '\u201A': '\'',
   '\u201B': '\'',
   '\u201C': '"',
   '\u201D': '"',
   '\u201E': '"',
@@ -4109,51 +4111,80 @@ class PDFFindController {
     }
     if (!pdfDocument) {
       return;
     }
     this._pdfDocument = pdfDocument;
     this._firstPageCapability.resolve();
   }
   executeCommand(cmd, state) {
+    if (!state) {
+      return;
+    }
     const pdfDocument = this._pdfDocument;
-    if (this._state === null || this._shouldDirtyMatch(cmd)) {
+    if (this._state === null || this._shouldDirtyMatch(cmd, state)) {
       this._dirtyMatch = true;
     }
     this._state = state;
-    this._updateUIState(FindState.PENDING);
+    if (cmd !== 'findhighlightallchange') {
+      this._updateUIState(FindState.PENDING);
+    }
     this._firstPageCapability.promise.then(() => {
       if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) {
         return;
       }
       this._extractText();
       const findbarClosed = !this._highlightMatches;
+      const pendingTimeout = !!this._findTimeout;
       if (this._findTimeout) {
         clearTimeout(this._findTimeout);
         this._findTimeout = null;
       }
       if (cmd === 'find') {
         this._findTimeout = setTimeout(() => {
           this._nextMatch();
           this._findTimeout = null;
         }, FIND_TIMEOUT);
       } else if (this._dirtyMatch) {
         this._nextMatch();
       } else if (cmd === 'findagain') {
         this._nextMatch();
         if (findbarClosed && this._state.highlightAll) {
           this._updateAllPages();
         }
+      } else if (cmd === 'findhighlightallchange') {
+        if (pendingTimeout) {
+          this._nextMatch();
+        } else {
+          this._highlightMatches = true;
+        }
+        this._updateAllPages();
       } else {
         this._nextMatch();
       }
     });
   }
+  scrollMatchIntoView({ element = null, pageIndex = -1, matchIndex = -1 }) {
+    if (!this._scrollMatches || !element) {
+      return;
+    } else if (matchIndex === -1 || matchIndex !== this._selected.matchIdx) {
+      return;
+    } else if (pageIndex === -1 || pageIndex !== this._selected.pageIdx) {
+      return;
+    }
+    this._scrollMatches = false;
+    const spot = {
+      top: MATCH_SCROLL_OFFSET_TOP,
+      left: MATCH_SCROLL_OFFSET_LEFT
+    };
+    (0, _ui_utils.scrollIntoView)(element, spot, true);
+  }
   _reset() {
     this._highlightMatches = false;
+    this._scrollMatches = false;
     this._pdfDocument = null;
     this._pageMatches = [];
     this._pageMatchesLength = [];
     this._state = null;
     this._selected = {
       pageIdx: -1,
       matchIdx: -1
     };
@@ -4175,25 +4206,30 @@ class PDFFindController {
   }
   get _query() {
     if (this._state.query !== this._rawQuery) {
       this._rawQuery = this._state.query;
       this._normalizedQuery = normalize(this._state.query);
     }
     return this._normalizedQuery;
   }
-  _shouldDirtyMatch(cmd) {
+  _shouldDirtyMatch(cmd, state) {
+    if (state.query !== this._state.query) {
+      return true;
+    }
     switch (cmd) {
       case 'findagain':
         const pageNumber = this._selected.pageIdx + 1;
         const linkService = this._linkService;
         if (pageNumber >= 1 && pageNumber <= linkService.pagesCount && linkService.page !== pageNumber && linkService.isPageVisible && !linkService.isPageVisible(pageNumber)) {
           break;
         }
         return false;
+      case 'findhighlightallchange':
+        return false;
     }
     return true;
   }
   _prepareMatches(matchesWithLength, matches, matchesLength) {
     function isSubTerm(matchesWithLength, currentIndex) {
       const currentElem = matchesWithLength[currentIndex];
       const nextElem = matchesWithLength[currentIndex + 1];
       if (currentIndex < matchesWithLength.length - 1 && currentElem.match === nextElem.match) {
@@ -4338,17 +4374,17 @@ class PDFFindController {
           console.error(`Unable to get text content for page ${i + 1}`, reason);
           this._pageContents[i] = '';
           extractTextCapability.resolve(i);
         });
       });
     }
   }
   _updatePage(index) {
-    if (this._selected.pageIdx === index) {
+    if (this._scrollMatches && this._selected.pageIdx === index) {
       this._linkService.page = index + 1;
     }
     this._eventBus.dispatch('updatetextlayermatches', {
       source: this,
       pageIndex: index
     });
   }
   _updateAllPages() {
@@ -4458,16 +4494,17 @@ class PDFFindController {
       this._selected.matchIdx = this._offset.matchIdx;
       state = wrapped ? FindState.WRAPPED : FindState.FOUND;
       if (previousPage !== -1 && previousPage !== this._selected.pageIdx) {
         this._updatePage(previousPage);
       }
     }
     this._updateUIState(state, this._state.findPrevious);
     if (this._selected.pageIdx !== -1) {
+      this._scrollMatches = true;
       this._updatePage(this._selected.pageIdx);
     }
   }
   _onFindBarClose(evt) {
     const pdfDocument = this._pdfDocument;
     this._firstPageCapability.promise.then(() => {
       if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) {
         return;
@@ -6917,91 +6954,88 @@ class BaseViewer {
   }
   _resetCurrentPageView() {
     if (this.isInPresentationMode) {
       this._setScale(this._currentScaleValue, true);
     }
     let pageView = this._pages[this._currentPageNumber - 1];
     this._scrollIntoView({ pageDiv: pageView.div });
   }
-  scrollPageIntoView(params) {
+  scrollPageIntoView({ pageNumber, destArray = null, allowNegativeOffset = false }) {
     if (!this.pdfDocument) {
       return;
     }
-    let pageNumber = params.pageNumber || 0;
-    let dest = params.destArray || null;
-    let allowNegativeOffset = params.allowNegativeOffset || false;
-    if (this.isInPresentationMode || !dest) {
-      this._setCurrentPageNumber(pageNumber, true);
-      return;
-    }
-    let pageView = this._pages[pageNumber - 1];
+    const pageView = Number.isInteger(pageNumber) && this._pages[pageNumber - 1];
     if (!pageView) {
       console.error(`${this._name}.scrollPageIntoView: Invalid "pageNumber" parameter.`);
       return;
     }
+    if (this.isInPresentationMode || !destArray) {
+      this._setCurrentPageNumber(pageNumber, true);
+      return;
+    }
     let x = 0,
         y = 0;
     let width = 0,
         height = 0,
         widthScale,
         heightScale;
     let changeOrientation = pageView.rotation % 180 === 0 ? false : true;
     let pageWidth = (changeOrientation ? pageView.height : pageView.width) / pageView.scale / _ui_utils.CSS_UNITS;
     let pageHeight = (changeOrientation ? pageView.width : pageView.height) / pageView.scale / _ui_utils.CSS_UNITS;
     let scale = 0;
-    switch (dest[1].name) {
+    switch (destArray[1].name) {
       case 'XYZ':
-        x = dest[2];
-        y = dest[3];
-        scale = dest[4];
+        x = destArray[2];
+        y = destArray[3];
+        scale = destArray[4];
         x = x !== null ? x : 0;
         y = y !== null ? y : pageHeight;
         break;
       case 'Fit':
       case 'FitB':
         scale = 'page-fit';
         break;
       case 'FitH':
       case 'FitBH':
-        y = dest[2];
+        y = destArray[2];
         scale = 'page-width';
         if (y === null && this._location) {
           x = this._location.left;
           y = this._location.top;
         }
         break;
       case 'FitV':
       case 'FitBV':
-        x = dest[2];
+        x = destArray[2];
         width = pageWidth;
         height = pageHeight;
         scale = 'page-height';
         break;
       case 'FitR':
-        x = dest[2];
-        y = dest[3];
-        width = dest[4] - x;
-        height = dest[5] - y;
+        x = destArray[2];
+        y = destArray[3];
+        width = destArray[4] - x;
+        height = destArray[5] - y;
         let hPadding = this.removePageBorders ? 0 : _ui_utils.SCROLLBAR_PADDING;
         let vPadding = this.removePageBorders ? 0 : _ui_utils.VERTICAL_PADDING;
         widthScale = (this.container.clientWidth - hPadding) / width / _ui_utils.CSS_UNITS;
         heightScale = (this.container.clientHeight - vPadding) / height / _ui_utils.CSS_UNITS;
         scale = Math.min(Math.abs(widthScale), Math.abs(heightScale));
         break;
       default:
-        console.error(`${this._name}.scrollPageIntoView: "${dest[1].name}" ` + 'is not a valid destination type.');
+        console.error(`${this._name}.scrollPageIntoView: ` + `"${destArray[1].name}" is not a valid destination type.`);
         return;
     }
     if (scale && scale !== this._currentScale) {
       this.currentScaleValue = scale;
     } else if (this._currentScale === _ui_utils.UNKNOWN_SCALE) {
       this.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE;
     }
-    if (scale === 'page-fit' && !dest[4]) {
+    if (scale === 'page-fit' && !destArray[4]) {
       this._scrollIntoView({
         pageDiv: pageView.div,
         pageNumber
       });
       return;
     }
     let boundingRect = [pageView.viewport.convertToViewportPoint(x, y), pageView.viewport.convertToViewportPoint(x + width, y + height)];
     let left = Math.min(boundingRect[0][0], boundingRect[1][0]);
@@ -7227,17 +7261,17 @@ class BaseViewer {
     viewer.classList.toggle('scrollHorizontal', scrollMode === ScrollMode.HORIZONTAL);
     viewer.classList.toggle('scrollWrapped', scrollMode === ScrollMode.WRAPPED);
     if (!this.pdfDocument || !pageNumber) {
       return;
     }
     if (this._currentScaleValue && isNaN(this._currentScaleValue)) {
       this._setScale(this._currentScaleValue, true);
     }
-    this.scrollPageIntoView({ pageNumber });
+    this._setCurrentPageNumber(pageNumber, true);
     this.update();
   }
   get spreadMode() {
     return this._spreadMode;
   }
   set spreadMode(mode) {
     if (this._spreadMode === mode) {
       return;
@@ -7276,17 +7310,17 @@ class BaseViewer {
           viewer.appendChild(spread);
         }
         spread.appendChild(pages[i].div);
       }
     }
     if (!pageNumber) {
       return;
     }
-    this.scrollPageIntoView({ pageNumber });
+    this._setCurrentPageNumber(pageNumber, true);
     this.update();
   }
 }
 exports.BaseViewer = BaseViewer;
 exports.ScrollMode = ScrollMode;
 exports.SpreadMode = SpreadMode;
 
 /***/ }),
@@ -7849,18 +7883,16 @@ Object.defineProperty(exports, "__esModu
 });
 exports.DefaultTextLayerFactory = exports.TextLayerBuilder = undefined;
 
 var _ui_utils = __webpack_require__(2);
 
 var _pdfjsLib = __webpack_require__(3);
 
 const EXPAND_DIVS_TIMEOUT = 300;
-const MATCH_SCROLL_OFFSET_TOP = -50;
-const MATCH_SCROLL_OFFSET_LEFT = -400;
 class TextLayerBuilder {
   constructor({ textLayerDiv, eventBus, pageIndex, viewport, findController = null, enhanceTextSelection = false }) {
     this.textLayerDiv = textLayerDiv;
     this.eventBus = eventBus || (0, _ui_utils.getGlobalEventBus)();
     this.textContent = null;
     this.textContentItemsStr = [];
     this.textContentStream = null;
     this.renderingDone = false;
@@ -8008,23 +8040,21 @@ class TextLayerBuilder {
       return;
     }
     for (let i = i0; i < i1; i++) {
       let match = matches[i];
       let begin = match.begin;
       let end = match.end;
       let isSelected = isSelectedPage && i === selectedMatchIdx;
       let highlightSuffix = isSelected ? ' selected' : '';
-      if (findController.selected.matchIdx === i && findController.selected.pageIdx === pageIdx) {
-        const spot = {
-          top: MATCH_SCROLL_OFFSET_TOP,
-          left: MATCH_SCROLL_OFFSET_LEFT
-        };
-        (0, _ui_utils.scrollIntoView)(textDivs[begin.divIdx], spot, true);
-      }
+      findController.scrollMatchIntoView({
+        element: textDivs[begin.divIdx],
+        pageIndex: pageIdx,
+        matchIndex: i
+      });
       if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
         if (prevEnd !== null) {
           appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
         }
         beginText(begin);
       } else {
         appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset);
       }
--- a/browser/extensions/pdfjs/moz.yaml
+++ b/browser/extensions/pdfjs/moz.yaml
@@ -15,15 +15,15 @@ origin:
   description: Portable Document Format (PDF) viewer that is built with HTML5
 
   # Full URL for the package's homepage/etc
   # Usually different from repository url
   url: https://github.com/mozilla/pdf.js
 
   # Human-readable identifier for this version/release
   # Generally "version NNN", "tag SSS", "bookmark SSS"
-  release: version 2.1.42
+  release: version 2.1.52
 
   # The package's license, where possible using the mnemonic from
   # https://spdx.org/licenses/
   # Multiple licenses can be specified (as a YAML list)
   # A "LICENSE" file must exist containing the full license text
   license: Apache-2.0
--- a/browser/installer/windows/docs/FullConfig.rst
+++ b/browser/installer/windows/docs/FullConfig.rst
@@ -64,11 +64,9 @@ For options that accept ``true`` or ``fa
     ; Semicolons can be used to add comments
     InstallDirectoryName=Firefox Release
     DesktopShortcut=false
     StartMenuShortcuts=true
     MaintenanceService=false
     OptionalExtensions=false
 
 ``/ExtractDir=[directory]``
-  Extract the application files to the given directory and exit, without actually running the installer. Of course, this means all other options will be ignored.
-
-  This option is not available for use in .ini files.
+  Extract the application files to the given directory and exit, without actually running the installer. No other options may be supplied along with ``ExtractDir``, and ``ExtractDir`` is not available for use in .ini files.
--- a/browser/installer/windows/msi/installer.wxs
+++ b/browser/installer/windows/msi/installer.wxs
@@ -64,17 +64,17 @@
   <CustomAction Id="RunInstallDirPath" Return="check" Execute="deferred"
                 HideTarget="no" Impersonate="no" BinaryKey="WrappedExe"
                 ExeCommand="/S /InstallDirectoryPath=[INSTALL_DIRECTORY_PATH] /TaskbarShortcut=[TASKBAR_SHORTCUT] /DesktopShortcut=[DESKTOP_SHORTCUT] /StartMenuShortcut=[START_MENU_SHORTCUT] /MaintenanceService=[INSTALL_MAINTENANCE_SERVICE] /RemoveDistributionDir=[REMOTE_DISTRIBUTION_DIR] /PreventRebootRequired=[PREVENT_REBOOT_REQUIRED] /OptionalExtensions=[OPTIONAL_EXTENSIONS] /LaunchedFromMSI" />
   <CustomAction Id="RunInstallDirName" Return="check" Execute="deferred"
                 HideTarget="no" Impersonate="no" BinaryKey="WrappedExe"
                 ExeCommand="/S /InstallDirectoryName=[INSTALL_DIRECTORY_NAME] /TaskbarShortcut=[TASKBAR_SHORTCUT] /DesktopShortcut=[DESKTOP_SHORTCUT] /StartMenuShortcut=[START_MENU_SHORTCUT] /MaintenanceService=[INSTALL_MAINTENANCE_SERVICE] /RemoveDistributionDir=[REMOTE_DISTRIBUTION_DIR] /PreventRebootRequired=[PREVENT_REBOOT_REQUIRED] /OptionalExtensions=[OPTIONAL_EXTENSIONS] /LaunchedFromMSI" />
   <CustomAction Id="RunExtractOnly" Return="check" Execute="deferred"
                 HideTarget="no" Impersonate="no" BinaryKey="WrappedExe"
-                ExeCommand="/S /ExtractDir=[EXTRACT_DIR]" />
+                ExeCommand="/ExtractDir=[EXTRACT_DIR]" />
 
   <!-- When we run the custom actions is kind of arbitrary; this sequencing gets
        us the least confusing message showing in the MSI progress dialog while
        the installer runs. Our actions don't need to be sequenced relative
 	   to one another because only one will ever run. -->
   <InstallExecuteSequence>
     <Custom Action="RunInstallNoDir" After="ProcessComponents">
     <![CDATA[
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -1351,29 +1351,24 @@ exports.CSS_PROPERTIES = {
   },
   "-moz-user-select": {
     "isInherited": false,
     "subproperties": [
       "-moz-user-select"
     ],
     "supports": [],
     "values": [
-      "-moz-all",
       "-moz-none",
       "-moz-text",
       "all",
       "auto",
-      "element",
-      "elements",
       "inherit",
       "initial",
       "none",
       "text",
-      "toggle",
-      "tri-state",
       "unset"
     ]
   },
   "-moz-window-dragging": {
     "isInherited": false,
     "subproperties": [
       "-moz-window-dragging"
     ],
@@ -2747,29 +2742,24 @@ exports.CSS_PROPERTIES = {
   },
   "-webkit-user-select": {
     "isInherited": false,
     "subproperties": [
       "-moz-user-select"
     ],
     "supports": [],
     "values": [
-      "-moz-all",
       "-moz-none",
       "-moz-text",
       "all",
       "auto",
-      "element",
-      "elements",
       "inherit",
       "initial",
       "none",
       "text",
-      "toggle",
-      "tri-state",
       "unset"
     ]
   },
   "align-content": {
     "isInherited": false,
     "subproperties": [
       "align-content"
     ],
--- a/dom/fetch/FetchStreamReader.cpp
+++ b/dom/fetch/FetchStreamReader.cpp
@@ -61,20 +61,24 @@ FetchStreamReader::Create(JSContext* aCx
   }
 
   if (!NS_IsMainThread()) {
     WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
     MOZ_ASSERT(workerPrivate);
 
     RefPtr<WeakWorkerRef> workerRef =
       WeakWorkerRef::Create(workerPrivate, [streamReader]() {
-        // The WorkerPrivate does have a context available, and we could pass
-        // it here to trigger cancellation of the reader, but the author of
-        // this comment chickened out.
-        streamReader->CloseAndRelease(nullptr, NS_ERROR_DOM_INVALID_STATE_ERR);
+        MOZ_ASSERT(streamReader);
+        MOZ_ASSERT(streamReader->mWorkerRef);
+
+        WorkerPrivate* workerPrivate = streamReader->mWorkerRef->GetPrivate();
+        MOZ_ASSERT(workerPrivate);
+
+        streamReader->CloseAndRelease(workerPrivate->GetJSContext(),
+                                      NS_ERROR_DOM_INVALID_STATE_ERR);
       });
 
     if (NS_WARN_IF(!workerRef)) {
       streamReader->mPipeOut->CloseWithStatus(NS_ERROR_DOM_INVALID_STATE_ERR);
       return NS_ERROR_DOM_INVALID_STATE_ERR;
     }
 
     // These 2 objects create a ref-cycle here that is broken when the stream is
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -1570,41 +1570,37 @@ IDBObjectStore::GetAddInfo(JSContext* aC
 
   // Return DATA_ERR if no key was specified this isn't an autoIncrement
   // objectStore.
   if (aKey.IsUnset() && !isAutoIncrement) {
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
   // Figure out indexes and the index values to update here.
-  const nsTArray<IndexMetadata>& indexes = mSpec->indexes();
-
-  uint32_t idxCount = indexes.Length();
-
-  if (idxCount) {
-    if (!aValueWrapper.Clone(aCx)) {
-      return NS_ERROR_DOM_DATA_CLONE_ERR;
-    }
-
-    // Update idxCount, the structured clone process may trigger content code
-    // via getters/other which can potentially call CreateIndex/DeleteIndex.
-    idxCount = indexes.Length();
+
+  if (mSpec->indexes().Length() && !aValueWrapper.Clone(aCx)) {
+    return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
-  aUpdateInfoArray.SetCapacity(idxCount); // Pretty good estimate
-
-  for (uint32_t idxIndex = 0; idxIndex < idxCount; idxIndex++) {
-    const IndexMetadata& metadata = indexes[idxIndex];
-
-    rv = AppendIndexUpdateInfo(metadata.id(), metadata.keyPath(),
-                               metadata.unique(), metadata.multiEntry(),
-                               metadata.locale(), aCx, aValueWrapper.Value(),
-                               aUpdateInfoArray);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+  {
+    const nsTArray<IndexMetadata>& indexes = mSpec->indexes();
+    uint32_t idxCount = indexes.Length();
+
+    aUpdateInfoArray.SetCapacity(idxCount); // Pretty good estimate
+
+    for (uint32_t idxIndex = 0; idxIndex < idxCount; idxIndex++) {
+      const IndexMetadata& metadata = indexes[idxIndex];
+
+      rv = AppendIndexUpdateInfo(metadata.id(), metadata.keyPath(),
+                                 metadata.unique(), metadata.multiEntry(),
+                                 metadata.locale(), aCx, aValueWrapper.Value(),
+                                 aUpdateInfoArray);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
     }
   }
 
 
   if (isAutoIncrement && HasValidKeyPath()) {
     if (!aValueWrapper.Clone(aCx)) {
       return NS_ERROR_DOM_DATA_CLONE_ERR;
     }
@@ -1659,16 +1655,21 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
   StructuredCloneWriteInfo cloneWriteInfo(mTransaction->Database());
   nsTArray<IndexUpdateInfo> updateInfo;
 
   aRv = GetAddInfo(aCx, aValueWrapper, aKey, cloneWriteInfo, key, updateInfo);
   if (aRv.Failed()) {
     return nullptr;
   }
 
+  if (!mTransaction->IsOpen()) {
+    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
+    return nullptr;
+  }
+
   // Check the size limit of the serialized message which mainly consists of
   // a StructuredCloneBuffer, an encoded object key, and the encoded index keys.
   // kMaxIDBMsgOverhead covers the minor stuff not included in this calculation
   // because the precise calculation would slow down this AddOrPut operation.
   static const size_t kMaxIDBMsgOverhead = 1024 * 1024; // 1MB
   const uint32_t maximalSizeFromPref =
     IndexedDatabaseManager::MaxSerializedMsgSize();
   MOZ_ASSERT(maximalSizeFromPref > kMaxIDBMsgOverhead);
--- a/dom/workers/test/chrome.ini
+++ b/dom/workers/test/chrome.ini
@@ -78,8 +78,9 @@ skip-if = (os == 'linux') # Bug 1244409
 [test_fileReaderSync.xul]
 [test_fileReaderSyncErrors.xul]
 [test_fileSlice.xul]
 [test_fileSubWorker.xul]
 [test_bug1062920.xul]
 [test_sharedWorker_privateBrowsing.html]
 [test_shutdownCheck.xul]
 support-files = worker_shutdownCheck.js
+[test_readableStream_when_closing.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_readableStream_when_closing.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for ReadableStream+fetch when the worker is closing</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+</head>
+<body>
+  <script>
+
+function workerCode() {
+  onmessage = () => {
+    const BIG_BUFFER_SIZE = 1000000;
+    const fibStream = new ReadableStream({
+        start(controller) {},
+
+        pull(controller) {
+          const buffer = new Uint8Array(BIG_BUFFER_SIZE);
+          buffer.fill(42);
+          controller.enqueue(buffer);
+        }
+    });
+
+    const r = new Response(fibStream);
+
+    const p = r.blob();
+    self.postMessage("reading");
+
+    p.then(() => {
+      // really?
+    });
+  }
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [
+  ["javascript.options.streams", true],
+]}).then(() => {
+  const b = new Blob([workerCode+'workerCode();']);
+  const url = URL.createObjectURL(b);
+  const w = new Worker(url);
+  w.onmessage = function(e) {
+    ok(true, 'Worker is reading');
+
+    const wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"].
+                getService(Ci.nsIWorkerDebuggerManager);
+    wdm.addListener({
+      onUnregister: function (dbg) {
+        if (dbg.url == url) {
+          ok(true, "Debugger with url " + url + " should be unregistered.");
+          wdm.removeListener(this);
+          SimpleTest.finish();
+        }
+      }
+    });
+
+    w.terminate();
+  }
+  w.postMessage("start");
+});
+
+  </script>
+</body>
+</html>
+
--- a/gfx/2d/Rect.h
+++ b/gfx/2d/Rect.h
@@ -291,17 +291,19 @@ IntRectTyped<units> RoundedToInt(const R
                              int32_t(copy.Width()),
                              int32_t(copy.Height()));
 }
 
 template<class units>
 bool RectIsInt32Safe(const RectTyped<units>& aRect) {
   float min = (float)std::numeric_limits<std::int32_t>::min();
   float max = (float)std::numeric_limits<std::int32_t>::max();
-  return aRect.x > min && aRect.y > min && aRect.XMost() < max && aRect.YMost() < max;
+  return aRect.x > min && aRect.y > min &&
+         aRect.width < max && aRect.height < max &&
+         aRect.XMost() < max && aRect.YMost() < max;
 }
 
 template<class units>
 IntRectTyped<units> RoundedIn(const RectTyped<units>& aRect)
 {
   return IntRectTyped<units>::RoundIn(aRect);
 }
 
new file mode 100644
--- /dev/null
+++ b/gfx/tests/crashtests/1490704-1.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <style class="">
+    * {
+      transform: scalex(10) !important;
+      block-size: calc(-25958*-8px + -23%);
+    }
+
+    @page :left {
+      @page :left {
+        *:link {}
+      }
+    }
+
+    * {
+      box-shadow: green calc(42em - 43357px) 45px, blue -3841px 125px, currentColor 21px 50268px, 168px 2px 50817px 253px orange;
+      -moz-columns: 2 auto ! important;
+    }
+  </style>
+</head>
+
+<body class="" style="inline-size:-moz-min-content!important">
+  <p class=""><canvas class="" width="1024">
+</body>
+</html>
\ No newline at end of file
--- a/gfx/tests/crashtests/crashtests.list
+++ b/gfx/tests/crashtests/crashtests.list
@@ -164,10 +164,11 @@ load 1325159-1.html
 load 1331683.html
 skip-if(Android) pref(dom.disable_open_during_load,false) load 1343666.html
 load 1408078-1.html
 load 1464243.html
 load 1467847-1.html
 load 1468020.html
 load 1470440.html
 load 1478035.html
+load 1490704-1.html
 load 1501518.html
 load 1503986-1.html
--- a/js/public/CompilationAndEvaluation.h
+++ b/js/public/CompilationAndEvaluation.h
@@ -117,114 +117,89 @@ Evaluate(JSContext* cx, const ReadOnlyCo
 extern JS_PUBLIC_API(bool)
 Evaluate(JSContext* cx, AutoVector<JSObject*>& envChain, const ReadOnlyCompileOptions& options,
          SourceBufferHolder& srcBuf, MutableHandle<Value> rval);
 
 /**
  * Evaluate the provided UTF-8 data in the scope of the current global of |cx|,
  * and return the completion value in |rval|.  If the data contains invalid
  * UTF-8, an error is reported.
- *
- * The |options.utf8| flag is asserted to be true.  At a future time this flag
- * will be removed and UTF-8-ness of source bytes will be entirely determined
- * by which compilation function is called.
  */
 extern JS_PUBLIC_API(bool)
 EvaluateUtf8(JSContext* cx, const ReadOnlyCompileOptions& options,
              const char* bytes, size_t length, MutableHandle<Value> rval);
 
 /**
  * Evaluate the provided Latin-1 data (i.e. each byte directly corresponds to
  * the same Unicode code point) in the scope of the current global of |cx|, and
  * return the completion value in |rval|.
  *
- * The |options.utf8| flag is asserted to be false.  At a future time this flag
- * will be removed and UTF-8-ness of source bytes will be entirely determined
- * by which compilation function is called.
- *
  * This function may eventually be removed, such that *only* bytes containing
  * UTF-8 source text may be directly compiled.  Avoid using it if you can.
  */
 extern JS_PUBLIC_API(bool)
 EvaluateLatin1(JSContext* cx, const ReadOnlyCompileOptions& options,
                const char* bytes, size_t length, MutableHandle<Value> rval);
 
 /**
  * Evaluate the UTF-8 contents of the file at the given path, and return the
  * completion value in |rval|.  (The path itself is in the system encoding, not
  * [necessarily] UTF-8.)  If the contents contain any malformed UTF-8, an error
  * is reported.
- *
- * The |options.utf8| flag is asserted to be true.  At a future time this flag
- * will be removed.
  */
 extern JS_PUBLIC_API(bool)
 EvaluateUtf8Path(JSContext* cx, const ReadOnlyCompileOptions& options,
                  const char* filename, MutableHandle<Value> rval);
 
 /**
  * |script| will always be set. On failure, it will be set to nullptr.
  */
 extern JS_PUBLIC_API(bool)
 Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
         SourceBufferHolder& srcBuf, MutableHandle<JSScript*> script);
 
 /**
  * Compile the provided UTF-8 data into a script.  If the data contains invalid
  * UTF-8, an error is reported.
  *
- * The |options.utf8| flag is asserted to be true.  At a future time this flag
- * will be removed and UTF-8-ness of source bytes will be entirely determined
- * by which compilation function is called.
- *
  * |script| is always set to the compiled script or to null in case of error.
  */
 extern JS_PUBLIC_API(bool)
 CompileUtf8(JSContext* cx, const ReadOnlyCompileOptions& options,
             const char* bytes, size_t length, MutableHandle<JSScript*> script);
 
 /**
  * Compile the provided Latin-1 data (i.e. each byte directly corresponds to
  * the same Unicode code point) into a script.
  *
- * The |options.utf8| flag is asserted to be false.  At a future time this flag
- * will be removed and UTF-8-ness of source bytes will be entirely determined
- * by which compilation function is called.
- *
  * This function may eventually be removed, such that *only* bytes containing
  * UTF-8 source text may be directly compiled.  Avoid using it if you can.
  *
  * |script| is always set to the compiled script or to null in case of error.
  */
 extern JS_PUBLIC_API(bool)
 CompileLatin1(JSContext* cx, const ReadOnlyCompileOptions& options,
               const char* bytes, size_t length, MutableHandle<JSScript*> script);
 
 /**
  * Compile the UTF-8 contents of the given file into a script.  If the contents
  * contain any malformed UTF-8, an error is reported.
  *
  * |script| is always set to the compiled script or to null in case of error.
- *
- * The |options.utf8| flag is asserted to be true.  At a future time this flag
- * will be removed.
  */
 extern JS_PUBLIC_API(bool)
 CompileUtf8File(JSContext* cx, const ReadOnlyCompileOptions& options,
                 FILE* file, MutableHandle<JSScript*> script);
 
 /**
  * Compile the UTF-8 contents of the file at the given path into a script.
  * (The path itself is in the system encoding, not [necessarily] UTF-8.)  If
  * the contents contain any malformed UTF-8, an error is reported.
  *
  * |script| is always set to the compiled script or to null in case of error.
- *
- * The |options.utf8| flag is asserted to be true.  At a future time this flag
- * will be removed.
  */
 extern JS_PUBLIC_API(bool)
 CompileUtf8Path(JSContext* cx, const ReadOnlyCompileOptions& options,
                 const char* filename, MutableHandle<JSScript*> script);
 
 extern JS_PUBLIC_API(bool)
 CompileForNonSyntacticScope(JSContext* cx, const ReadOnlyCompileOptions& options,
                             SourceBufferHolder& srcBuf, MutableHandle<JSScript*> script);
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -37,71 +37,107 @@ using mozilla::Nothing;
 using JS::CompileOptions;
 using JS::ReadOnlyCompileOptions;
 using JS::SourceBufferHolder;
 
 // The BytecodeCompiler class contains resources common to compiling scripts and
 // function bodies.
 class MOZ_STACK_CLASS BytecodeCompiler
 {
-  public:
-    // Construct an object passing mandatory arguments.
-    BytecodeCompiler(JSContext* cx,
-                     const ReadOnlyCompileOptions& options,
-                     SourceBufferHolder& sourceBuffer,
-                     HandleScope enclosingScope);
-
-    JSScript* compileGlobalScript(ScopeKind scopeKind);
-    JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
-    ModuleObject* compileModule();
-    bool compileStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
-                                   FunctionAsyncKind asyncKind,
-                                   const Maybe<uint32_t>& parameterListEnd);
-
-    ScriptSourceObject* sourceObjectPtr() const;
-
-  private:
-    JSScript* compileScript(HandleObject environment, SharedContext* sc);
-    bool checkLength();
-    bool createScriptSource(const Maybe<uint32_t>& parameterListEnd);
-    bool canLazilyParse();
-    bool createParser(ParseGoal goal);
-    bool createSourceAndParser(ParseGoal goal,
-                               const Maybe<uint32_t>& parameterListEnd = Nothing());
-
-    // If toString{Start,End} are not explicitly passed, assume the script's
-    // offsets in the source used to parse it are the same as what should be
-    // used to compute its Function.prototype.toString() value.
-    bool createScript();
-    bool createScript(uint32_t toStringStart, uint32_t toStringEnd);
-
-    using TokenStreamPosition = frontend::TokenStreamPosition<char16_t>;
-
-    bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
-    bool handleParseFailure(const Directives& newDirectives, TokenStreamPosition& startPosition);
-    bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
-
+  protected:
     AutoKeepAtoms keepAtoms;
 
     JSContext* cx;
     const ReadOnlyCompileOptions& options;
     SourceBufferHolder& sourceBuffer;
 
-    RootedScope enclosingScope;
-
     RootedScriptSourceObject sourceObject;
     ScriptSource* scriptSource;
 
     Maybe<UsedNameTracker> usedNames;
     Maybe<Parser<SyntaxParseHandler, char16_t>> syntaxParser;
     Maybe<Parser<FullParseHandler, char16_t>> parser;
 
     Directives directives;
 
     RootedScript script;
+
+  public:
+    // Construct an object passing mandatory arguments.
+    BytecodeCompiler(JSContext* cx,
+                     const ReadOnlyCompileOptions& options,
+                     SourceBufferHolder& sourceBuffer);
+
+    ScriptSourceObject* sourceObjectPtr() const {
+        return sourceObject.get();
+    }
+
+    // Call this before calling compile{Global,Eval}Script.
+    MOZ_MUST_USE bool prepareScriptParse() {
+        return createSourceAndParser(ParseGoal::Script) && createCompleteScript();
+    }
+
+    JSScript* compileGlobalScript(ScopeKind scopeKind);
+    JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
+
+    // Call this before calling compileModule.
+    MOZ_MUST_USE bool prepareModuleParse() {
+        return createSourceAndParser(ParseGoal::Module) && createCompleteScript();
+    }
+
+    ModuleObject* compileModule(HandleScope enclosingScope);
+
+    // Call this before calling parseStandaloneFunction.
+    MOZ_MUST_USE bool prepareStandaloneFunctionParse(const Maybe<uint32_t>& parameterListEnd) {
+        return createSourceAndParser(ParseGoal::Script, parameterListEnd);
+    }
+
+    // Call this before calling compileStandaloneFunction.
+    CodeNode* parseStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
+                                      FunctionAsyncKind asyncKind,
+                                      const Maybe<uint32_t>& parameterListEnd,
+                                      HandleScope enclosingScope);
+
+    bool compileStandaloneFunction(CodeNode* parsedFunction, MutableHandleFunction fun);
+
+  private:
+    void assertSourceAndParserCreated() const {
+        MOZ_ASSERT(sourceObject != nullptr);
+        MOZ_ASSERT(scriptSource != nullptr);
+        MOZ_ASSERT(usedNames.isSome());
+        MOZ_ASSERT(parser.isSome());
+    }
+
+    void assertSourceParserAndScriptCreated() const {
+        assertSourceAndParserCreated();
+        MOZ_ASSERT(script != nullptr);
+    }
+
+    JSScript* compileScript(HandleObject environment, SharedContext* sc);
+    bool checkLength();
+    bool createScriptSource(const Maybe<uint32_t>& parameterListEnd);
+    bool canLazilyParse();
+    bool createParser(ParseGoal goal);
+    bool createSourceAndParser(ParseGoal goal,
+                               const Maybe<uint32_t>& parameterListEnd = Nothing());
+
+    // This assumes the created script's offsets in the source used to parse it
+    // are the same as are used to compute its Function.prototype.toString()
+    // value.
+    bool createCompleteScript();
+
+    // This uses explicitly-provided toString offsets as the created script's
+    // offsets in the source.
+    bool createScript(uint32_t toStringStart, uint32_t toStringEnd);
+
+    using TokenStreamPosition = frontend::TokenStreamPosition<char16_t>;
+
+    bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
+    bool handleParseFailure(const Directives& newDirectives, TokenStreamPosition& startPosition);
+    bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
 };
 
 AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx, const TraceLoggerTextId id,
                                            const ErrorReporter& errorReporter)
 #ifdef JS_TRACE_LOGGING
   : logger_(TraceLoggerForCurrentThread(cx))
 {
     // If the tokenizer hasn't yet gotten any tokens, use the line and column
@@ -148,23 +184,21 @@ AutoFrontendTraceLog::AutoFrontendTraceL
     typeLog_.emplace(logger_, id);
 }
 #else
 { }
 #endif
 
 BytecodeCompiler::BytecodeCompiler(JSContext* cx,
                                    const ReadOnlyCompileOptions& options,
-                                   SourceBufferHolder& sourceBuffer,
-                                   HandleScope enclosingScope)
+                                   SourceBufferHolder& sourceBuffer)
   : keepAtoms(cx),
     cx(cx),
     options(options),
     sourceBuffer(sourceBuffer),
-    enclosingScope(cx, enclosingScope),
     sourceObject(cx),
     scriptSource(nullptr),
     directives(options.strictOption),
     script(cx)
 {
     MOZ_ASSERT(sourceBuffer.get());
 }
 
@@ -224,19 +258,20 @@ BytecodeCompiler::canLazilyParse()
 }
 
 bool
 BytecodeCompiler::createParser(ParseGoal goal)
 {
     usedNames.emplace(cx);
 
     if (canLazilyParse()) {
-        syntaxParser.emplace(cx, cx->tempLifoAlloc(), options, sourceBuffer.get(),
-                             sourceBuffer.length(), /* foldConstants = */ false,
-                             *usedNames, nullptr, nullptr, sourceObject, goal);
+        syntaxParser.emplace(cx, cx->tempLifoAlloc(), options,
+                             sourceBuffer.get(), sourceBuffer.length(),
+                             /* foldConstants = */ false, *usedNames, nullptr, nullptr,
+                             sourceObject, goal);
         if (!syntaxParser->checkOptions()) {
             return false;
         }
     }
 
     parser.emplace(cx, cx->tempLifoAlloc(), options, sourceBuffer.get(), sourceBuffer.length(),
                    /* foldConstants = */ true, *usedNames, syntaxParser.ptrOr(nullptr), nullptr,
                    sourceObject, goal);
@@ -248,17 +283,17 @@ bool
 BytecodeCompiler::createSourceAndParser(ParseGoal goal,
                                         const Maybe<uint32_t>& parameterListEnd /* = Nothing() */)
 {
     return createScriptSource(parameterListEnd) &&
            createParser(goal);
 }
 
 bool
-BytecodeCompiler::createScript()
+BytecodeCompiler::createCompleteScript()
 {
     return createScript(0, sourceBuffer.length());
 }
 
 bool
 BytecodeCompiler::createScript(uint32_t toStringStart, uint32_t toStringEnd)
 {
     script = JSScript::Create(cx, options,
@@ -320,26 +355,20 @@ BytecodeCompiler::deoptimizeArgumentsInE
     }
 
     return true;
 }
 
 JSScript*
 BytecodeCompiler::compileScript(HandleObject environment, SharedContext* sc)
 {
-    if (!createSourceAndParser(ParseGoal::Script)) {
-        return nullptr;
-    }
+    assertSourceParserAndScriptCreated();
 
     TokenStreamPosition startPosition(keepAtoms, parser->tokenStream);
 
-    if (!createScript()) {
-        return nullptr;
-    }
-
     Maybe<BytecodeEmitter> emitter;
     if (!emplaceEmitter(emitter, sc)) {
         return nullptr;
     }
 
     for (;;) {
         ParseNode* pn;
         {
@@ -391,43 +420,47 @@ BytecodeCompiler::compileScript(HandleOb
 
     return script;
 }
 
 JSScript*
 BytecodeCompiler::compileGlobalScript(ScopeKind scopeKind)
 {
     GlobalSharedContext globalsc(cx, scopeKind, directives, options.extraWarningsOption);
+
+    if (!prepareScriptParse()) {
+        return nullptr;
+    }
+
     return compileScript(nullptr, &globalsc);
 }
 
 JSScript*
 BytecodeCompiler::compileEvalScript(HandleObject environment, HandleScope enclosingScope)
 {
     EvalSharedContext evalsc(cx, environment, enclosingScope,
                              directives, options.extraWarningsOption);
+
+    if (!prepareScriptParse()) {
+        return nullptr;
+    }
+
     return compileScript(environment, &evalsc);
 }
 
 ModuleObject*
-BytecodeCompiler::compileModule()
+BytecodeCompiler::compileModule(HandleScope enclosingScope)
 {
-    if (!createSourceAndParser(ParseGoal::Module)) {
-        return nullptr;
-    }
+    assertSourceParserAndScriptCreated();
 
     Rooted<ModuleObject*> module(cx, ModuleObject::create(cx));
     if (!module) {
         return nullptr;
     }
 
-    if (!createScript()) {
-        return nullptr;
-    }
-
     module->init(script);
 
     ModuleBuilder builder(cx, module, parser->anyChars);
 
     ModuleSharedContext modulesc(cx, module, enclosingScope, builder);
     ParseNode* pn = parser->moduleBody(&modulesc);
     if (!pn) {
         return nullptr;
@@ -456,83 +489,77 @@ BytecodeCompiler::compileModule()
     if (!scriptSource->tryCompressOffThread(cx)) {
         return nullptr;
     }
 
     MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
     return module;
 }
 
-// Compile a standalone JS function, which might appear as the value of an
+// Parse a standalone JS function, which might appear as the value of an
 // event handler attribute in an HTML <INPUT> tag, or in a Function()
 // constructor.
-bool
-BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
-                                            GeneratorKind generatorKind,
-                                            FunctionAsyncKind asyncKind,
-                                            const Maybe<uint32_t>& parameterListEnd)
+CodeNode*
+BytecodeCompiler::parseStandaloneFunction(MutableHandleFunction fun,
+                                          GeneratorKind generatorKind,
+                                          FunctionAsyncKind asyncKind,
+                                          const Maybe<uint32_t>& parameterListEnd,
+                                          HandleScope enclosingScope)
 {
     MOZ_ASSERT(fun);
     MOZ_ASSERT(fun->isTenured());
 
-    if (!createSourceAndParser(ParseGoal::Script, parameterListEnd)) {
-        return false;
-    }
+    assertSourceAndParserCreated();
 
     TokenStreamPosition startPosition(keepAtoms, parser->tokenStream);
 
     // Speculatively parse using the default directives implied by the context.
     // If a directive is encountered (e.g., "use strict") that changes how the
     // function should have been parsed, we backup and reparse with the new set
     // of directives.
 
     ParseNode* fn;
     do {
         Directives newDirectives = directives;
         fn = parser->standaloneFunction(fun, enclosingScope, parameterListEnd, generatorKind,
                                         asyncKind, directives, &newDirectives);
         if (!fn && !handleParseFailure(newDirectives, startPosition)) {
-            return false;
+            return nullptr;
         }
     } while (!fn);
 
-    FunctionBox* funbox = fn->as<CodeNode>().funbox();
+    return &fn->as<CodeNode>();
+}
+
+// Compile a standalone JS function.
+bool
+BytecodeCompiler::compileStandaloneFunction(CodeNode* parsedFunction, MutableHandleFunction fun)
+{
+    FunctionBox* funbox = parsedFunction->funbox();
     if (funbox->function()->isInterpreted()) {
         MOZ_ASSERT(fun == funbox->function());
 
         if (!createScript(funbox->toStringStart, funbox->toStringEnd)) {
             return false;
         }
 
         Maybe<BytecodeEmitter> emitter;
         if (!emplaceEmitter(emitter, funbox)) {
             return false;
         }
-        if (!emitter->emitFunctionScript(&fn->as<CodeNode>(),
-                                         BytecodeEmitter::TopLevelFunction::Yes))
-        {
+        if (!emitter->emitFunctionScript(parsedFunction, BytecodeEmitter::TopLevelFunction::Yes)) {
             return false;
         }
     } else {
         fun.set(funbox->function());
         MOZ_ASSERT(IsAsmJSModule(fun));
     }
 
     // Enqueue an off-thread source compression task after finishing parsing.
-    if (!scriptSource->tryCompressOffThread(cx)) {
-        return false;
-    }
-
-    return true;
-}
-
-ScriptSourceObject*
-BytecodeCompiler::sourceObjectPtr() const
-{
-    return sourceObject.get();
+    return scriptSource->tryCompressOffThread(cx);
 }
 
 ScriptSourceObject*
 frontend::CreateScriptSourceObject(JSContext* cx, const ReadOnlyCompileOptions& options,
                                    const Maybe<uint32_t>& parameterListEnd /* = Nothing() */)
 {
     ScriptSource* ss = cx->new_<ScriptSource>();
     if (!ss) {
@@ -641,17 +668,17 @@ class MOZ_RAII AutoAssertReportedExcepti
 JSScript*
 frontend::CompileGlobalScript(JSContext* cx, ScopeKind scopeKind,
                               const ReadOnlyCompileOptions& options,
                               SourceBufferHolder& srcBuf,
                               ScriptSourceObject** sourceObjectOut)
 {
     MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
     AutoAssertReportedException assertException(cx);
-    BytecodeCompiler compiler(cx, options, srcBuf, /* enclosingScope = */ nullptr);
+    BytecodeCompiler compiler(cx, options, srcBuf);
     AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
     JSScript* script = compiler.compileGlobalScript(scopeKind);
     if (!script) {
         return nullptr;
     }
     assertException.reset();
     return script;
 }
@@ -722,17 +749,17 @@ frontend::CompileGlobalBinASTScript(JSCo
 JSScript*
 frontend::CompileEvalScript(JSContext* cx, HandleObject environment,
                             HandleScope enclosingScope,
                             const ReadOnlyCompileOptions& options,
                             SourceBufferHolder& srcBuf,
                             ScriptSourceObject** sourceObjectOut)
 {
     AutoAssertReportedException assertException(cx);
-    BytecodeCompiler compiler(cx, options, srcBuf, enclosingScope);
+    BytecodeCompiler compiler(cx, options, srcBuf);
     AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
     JSScript* script = compiler.compileEvalScript(environment, enclosingScope);
     if (!script) {
         return nullptr;
     }
     assertException.reset();
     return script;
 
@@ -748,20 +775,25 @@ frontend::CompileModule(JSContext* cx, c
 
     AutoAssertReportedException assertException(cx);
 
     CompileOptions options(cx, optionsInput);
     options.maybeMakeStrictMode(true); // ES6 10.2.1 Module code is always strict mode code.
     options.setIsRunOnce(true);
     options.allowHTMLComments = false;
 
+    BytecodeCompiler compiler(cx, options, srcBuf);
+    AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
+
+    if (!compiler.prepareModuleParse()) {
+        return nullptr;
+    }
+
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
-    BytecodeCompiler compiler(cx, options, srcBuf, emptyGlobalScope);
-    AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
-    ModuleObject* module = compiler.compileModule();
+    ModuleObject* module = compiler.compileModule(emptyGlobalScope);
     if (!module) {
         return nullptr;
     }
 
     assertException.reset();
     return module;
 }
 
@@ -996,90 +1028,106 @@ bool
 frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
                                     const JS::ReadOnlyCompileOptions& options,
                                     JS::SourceBufferHolder& srcBuf,
                                     const Maybe<uint32_t>& parameterListEnd,
                                     HandleScope enclosingScope /* = nullptr */)
 {
     AutoAssertReportedException assertException(cx);
 
+    BytecodeCompiler compiler(cx, options, srcBuf);
+    if (!compiler.prepareStandaloneFunctionParse(parameterListEnd)) {
+        return false;
+    }
+
     RootedScope scope(cx, enclosingScope);
     if (!scope) {
         scope = &cx->global()->emptyGlobalScope();
     }
 
-    BytecodeCompiler compiler(cx, options, srcBuf, scope);
-    if (!compiler.compileStandaloneFunction(fun, GeneratorKind::NotGenerator,
-                                            FunctionAsyncKind::SyncFunction,
-                                            parameterListEnd))
-    {
+    CodeNode* parsedFunction = compiler.parseStandaloneFunction(fun, GeneratorKind::NotGenerator,
+                                                                FunctionAsyncKind::SyncFunction,
+                                                                parameterListEnd, scope);
+    if (!parsedFunction || !compiler.compileStandaloneFunction(parsedFunction, fun)) {
         return false;
     }
 
     assertException.reset();
     return true;
 }
 
 bool
 frontend::CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
                                      const JS::ReadOnlyCompileOptions& options,
                                      JS::SourceBufferHolder& srcBuf,
                                      const Maybe<uint32_t>& parameterListEnd)
 {
     AutoAssertReportedException assertException(cx);
 
-    RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
+    BytecodeCompiler compiler(cx, options, srcBuf);
+    if (!compiler.prepareStandaloneFunctionParse(parameterListEnd)) {
+        return false;
+    }
 
-    BytecodeCompiler compiler(cx, options, srcBuf, emptyGlobalScope);
-    if (!compiler.compileStandaloneFunction(fun, GeneratorKind::Generator,
-                                            FunctionAsyncKind::SyncFunction,
-                                            parameterListEnd))
-    {
+    RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
+    CodeNode* parsedFunction = compiler.parseStandaloneFunction(fun, GeneratorKind::Generator,
+                                                                FunctionAsyncKind::SyncFunction,
+                                                                parameterListEnd,
+                                                                emptyGlobalScope);
+    if (!parsedFunction || !compiler.compileStandaloneFunction(parsedFunction, fun)) {
         return false;
     }
 
     assertException.reset();
     return true;
 }
 
 bool
 frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
                                          const ReadOnlyCompileOptions& options,
                                          JS::SourceBufferHolder& srcBuf,
                                          const Maybe<uint32_t>& parameterListEnd)
 {
     AutoAssertReportedException assertException(cx);
 
-    RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
+    BytecodeCompiler compiler(cx, options, srcBuf);
+    if (!compiler.prepareStandaloneFunctionParse(parameterListEnd)) {
+        return false;
+    }
 
-    BytecodeCompiler compiler(cx, options, srcBuf, emptyGlobalScope);
-    if (!compiler.compileStandaloneFunction(fun, GeneratorKind::NotGenerator,
-                                            FunctionAsyncKind::AsyncFunction,
-                                            parameterListEnd))
-    {
+    RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
+    CodeNode* parsedFunction = compiler.parseStandaloneFunction(fun, GeneratorKind::NotGenerator,
+                                                                FunctionAsyncKind::AsyncFunction,
+                                                                parameterListEnd,
+                                                                emptyGlobalScope);
+    if (!parsedFunction || !compiler.compileStandaloneFunction(parsedFunction, fun)) {
         return false;
     }
 
     assertException.reset();
     return true;
 }
 
 bool
 frontend::CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
                                           const ReadOnlyCompileOptions& options,
                                           JS::SourceBufferHolder& srcBuf,
                                           const Maybe<uint32_t>& parameterListEnd)
 {
     AutoAssertReportedException assertException(cx);
 
-    RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
+    BytecodeCompiler compiler(cx, options, srcBuf);
+    if (!compiler.prepareStandaloneFunctionParse(parameterListEnd)) {
+        return false;
+    }
 
-    BytecodeCompiler compiler(cx, options, srcBuf, emptyGlobalScope);
-    if (!compiler.compileStandaloneFunction(fun, GeneratorKind::Generator,
-                                            FunctionAsyncKind::AsyncFunction,
-                                            parameterListEnd))
-    {
+    RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
+    CodeNode* parsedFunction = compiler.parseStandaloneFunction(fun, GeneratorKind::Generator,
+                                                                FunctionAsyncKind::AsyncFunction,
+                                                                parameterListEnd,
+                                                                emptyGlobalScope);
+    if (!parsedFunction || !compiler.compileStandaloneFunction(parsedFunction, fun)) {
         return false;
     }
 
     assertException.reset();
     return true;
 }
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -675,18 +675,18 @@ SourceUnits<Utf8Unit>::assertNextCodePoi
     } else if (c < 0x800) {
         expectedUnits[0] = 0b1100'0000 | (c >> 6);
         expectedUnits[1] = 0b1000'0000 | (c & 0b11'1111);
     } else if (c < 0x10000) {
         expectedUnits[0] = 0b1110'0000 | (c >> 12);
         expectedUnits[1] = 0b1000'0000 | ((c >> 6) & 0b11'1111);
         expectedUnits[2] = 0b1000'0000 | (c & 0b11'1111);
     } else {
-        expectedUnits[0] = 0b1110'0000 | (c >> 18);
-        expectedUnits[2] = 0b1000'0000 | ((c >> 12) & 0b11'1111);
+        expectedUnits[0] = 0b1111'0000 | (c >> 18);
+        expectedUnits[1] = 0b1000'0000 | ((c >> 12) & 0b11'1111);
         expectedUnits[2] = 0b1000'0000 | ((c >> 6) & 0b11'1111);
         expectedUnits[3] = 0b1000'0000 | (c & 0b11'1111);
     }
 
     MOZ_ASSERT(peeked.lengthInUnits() <= 4);
     for (uint8_t i = 0; i < peeked.lengthInUnits(); i++) {
         MOZ_ASSERT(expectedUnits[i] == ptr[i].toUint8());
     }
@@ -789,24 +789,27 @@ TokenStreamChars<Utf8Unit, AnyCharsAcces
     char leadByteStr[5];
     byteToTerminatedString(leadValue, leadByteStr);
 
     // |toHexChar| produces the desired decimal numbers for values < 4.
     const char expectedStr[] = { toHexChar(required - 1), '\0' };
     const char actualStr[] = { toHexChar(remaining - 1), '\0' };
 
     internalEncodingError(remaining, JSMSG_NOT_ENOUGH_CODE_UNITS,
-                          leadByteStr, expectedStr, actualStr, remaining == 2 ? " was" : "s were");
+                          leadByteStr,
+                          expectedStr, required == 2 ? "" : "s",
+                          actualStr, remaining == 2 ? " was" : "s were");
 }
 
 template<class AnyCharsAccess>
 MOZ_COLD void
-TokenStreamChars<Utf8Unit, AnyCharsAccess>::badTrailingUnit(Utf8Unit badUnit,
-                                                            uint8_t unitsObserved)
+TokenStreamChars<Utf8Unit, AnyCharsAccess>::badTrailingUnit(uint8_t unitsObserved)
 {
+    Utf8Unit badUnit = this->sourceUnits.addressOfNextCodeUnit()[unitsObserved - 1];
+
     char badByteStr[5];
     byteToTerminatedString(badUnit.toUint8(), badByteStr);
 
     internalEncodingError(unitsObserved, JSMSG_BAD_TRAILING_UTF8_UNIT, badByteStr);
 }
 
 template<class AnyCharsAccess>
 MOZ_COLD void
@@ -824,22 +827,23 @@ TokenStreamChars<Utf8Unit, AnyCharsAcces
     // 0x1F'FFFF is the maximum value that can fit in 3+6+6+6 unconstrained
     // bits in a four-byte UTF-8 code unit sequence.
     constexpr size_t MaxHexSize = sizeof("0x1F" "FFFF"); // including '\0'
     char codePointCharsArray[MaxHexSize];
 
     char* codePointStr = codePointCharsArray + ArrayLength(codePointCharsArray);
     *--codePointStr = '\0';
 
-    uint32_t copy = codePoint;
-    while (copy) {
+    // Note that by do-while looping here rather than while-looping, this
+    // writes a '0' when |codePoint == 0|.
+    do {
         MOZ_ASSERT(codePointCharsArray < codePointStr);
-        *--codePointStr = toHexChar(copy & 0xF);
-        copy >>= 4;
-    }
+        *--codePointStr = toHexChar(codePoint & 0xF);
+        codePoint >>= 4;
+    } while (codePoint);
 
     MOZ_ASSERT(codePointCharsArray + 2 <= codePointStr);
     *--codePointStr = 'x';
     *--codePointStr = '0';
 
     internalEncodingError(codePointLength, JSMSG_FORBIDDEN_UTF8_CODE_POINT, codePointStr, reason);
 }
 
@@ -851,18 +855,18 @@ TokenStreamChars<Utf8Unit, AnyCharsAcces
     auto onBadLeadUnit = [this, &lead]() {
         this->badLeadUnit(lead);
     };
 
     auto onNotEnoughUnits = [this, &lead](uint8_t remaining, uint8_t required) {
         this->notEnoughUnits(lead, remaining, required);
     };
 
-    auto onBadTrailingUnit = [this, &lead](uint8_t unitsObserved) {
-        this->badTrailingUnit(lead, unitsObserved);
+    auto onBadTrailingUnit = [this](uint8_t unitsObserved) {
+        this->badTrailingUnit(unitsObserved);
     };
 
     auto onBadCodePoint = [this](char32_t badCodePoint, uint8_t unitsObserved) {
         this->badCodePoint(badCodePoint, unitsObserved);
     };
 
     auto onNotShortestForm = [this](char32_t badCodePoint, uint8_t unitsObserved) {
         this->notShortestForm(badCodePoint, unitsObserved);
@@ -972,18 +976,18 @@ TokenStreamChars<Utf8Unit, AnyCharsAcces
     auto onBadLeadUnit = [this, &lead]() {
         this->badLeadUnit(lead);
     };
 
     auto onNotEnoughUnits = [this, &lead](uint_fast8_t remaining, uint_fast8_t required) {
         this->notEnoughUnits(lead, remaining, required);
     };
 
-    auto onBadTrailingUnit = [this, &lead](uint_fast8_t unitsObserved) {
-        this->badTrailingUnit(lead, unitsObserved);
+    auto onBadTrailingUnit = [this](uint_fast8_t unitsObserved) {
+        this->badTrailingUnit(unitsObserved);
     };
 
     auto onBadCodePoint = [this](char32_t badCodePoint, uint_fast8_t unitsObserved) {
         this->badCodePoint(badCodePoint, unitsObserved);
     };
 
     auto onNotShortestForm = [this](char32_t badCodePoint, uint_fast8_t unitsObserved) {
         this->notShortestForm(badCodePoint, unitsObserved);
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -2189,17 +2189,17 @@ class TokenStreamChars<mozilla::Utf8Unit
      */
     MOZ_COLD void notEnoughUnits(mozilla::Utf8Unit lead, uint8_t remaining, uint8_t required);
 
     /**
      * Report an error for a bad trailing UTF-8 code unit, where the bad
      * trailing unit was the last of |unitsObserved| units examined from the
      * current offset.
      */
-    MOZ_COLD void badTrailingUnit(mozilla::Utf8Unit badUnit, uint8_t unitsObserved);
+    MOZ_COLD void badTrailingUnit(uint8_t unitsObserved);
 
     // Helper used for both |badCodePoint| and |notShortestForm| for code units
     // that have all the requisite high bits set/unset in a manner that *could*
     // encode a valid code point, but the remaining bits encoding its actual
     // value do not define a permitted value.
     MOZ_COLD void badStructurallyValidCodePoint(uint32_t codePoint, uint8_t codePointLength,
                                                 const char* reason);
 
--- a/js/src/jit-test/tests/wasm/passive-segs-nonboundary.js
+++ b/js/src/jit-test/tests/wasm/passive-segs-nonboundary.js
@@ -365,16 +365,17 @@ function checkMiscPrefixed(opcode, expec
     }
 }
 
 //-----------------------------------------------------------
 // Verification cases for memory.copy/fill opcode encodings
 
 checkMiscPrefixed([0x0a, 0x00], false); // memory.copy, flags=0
 checkMiscPrefixed([0x0b, 0x00], false); // memory.fill, flags=0
+checkMiscPrefixed([0x0b, 0x80, 0x00], false); // memory.fill, flags=0 (long encoding)
 checkMiscPrefixed([0x0f], true);        // table.copy+1, which is currently unassigned
 
 //-----------------------------------------------------------
 // Verification cases for memory.copy/fill arguments
 
 // Invalid argument types
 {
     const tys = ['i32', 'f32', 'i64', 'f64'];
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -356,17 +356,17 @@ MSG_DEF(JSMSG_COMPUTED_NAME_IN_PATTERN,0
 MSG_DEF(JSMSG_DEFAULT_IN_PATTERN,      0, JSEXN_SYNTAXERR, "destructuring defaults aren't supported in this destructuring declaration")
 MSG_DEF(JSMSG_BAD_NEWTARGET,           0, JSEXN_SYNTAXERR, "new.target only allowed within functions")
 MSG_DEF(JSMSG_ESCAPED_KEYWORD,         0, JSEXN_SYNTAXERR, "keywords must be written literally, without embedded escapes")
 MSG_DEF(JSMSG_MISSING_SEMI_FIELD,      0, JSEXN_SYNTAXERR, "missing ; after field definition")
 MSG_DEF(JSMSG_FIELDS_NOT_SUPPORTED,    0, JSEXN_SYNTAXERR, "fields are not currently supported")
 
 // UTF-8 source text encoding errors
 MSG_DEF(JSMSG_BAD_LEADING_UTF8_UNIT,   1, JSEXN_SYNTAXERR, "{0} byte doesn't begin a valid UTF-8 code point")
-MSG_DEF(JSMSG_NOT_ENOUGH_CODE_UNITS,   4, JSEXN_SYNTAXERR, "{0} byte in UTF-8 must be followed by {1} bytes, but {2} byte{3} present")
+MSG_DEF(JSMSG_NOT_ENOUGH_CODE_UNITS,   5, JSEXN_SYNTAXERR, "{0} byte in UTF-8 must be followed by {1} byte{2}, but {3} byte{4} present")
 MSG_DEF(JSMSG_BAD_TRAILING_UTF8_UNIT,  1, JSEXN_SYNTAXERR, "bad trailing UTF-8 byte {0} doesn't match the pattern 0b10xxxxxx")
 MSG_DEF(JSMSG_FORBIDDEN_UTF8_CODE_POINT,2,JSEXN_SYNTAXERR, "{0} isn't a valid code point because {1}")
 MSG_DEF(JSMSG_BAD_CODE_UNITS,          1, JSEXN_NOTE, "the code units comprising this invalid code point were: {0}")
 
 // asm.js
 MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL,       1, JSEXN_TYPEERR, "asm.js type error: {0}")
 MSG_DEF(JSMSG_USE_ASM_LINK_FAIL,       1, JSEXN_TYPEERR, "asm.js link error: {0}")
 MSG_DEF(JSMSG_USE_ASM_TYPE_OK,         1, JSEXN_WARN,    "Successfully compiled asm.js code ({0})")
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -881,17 +881,17 @@ CreateBuffer(JSContext* cx, uint32_t ini
     return true;
 }
 
 bool
 js::CreateWasmBuffer(JSContext* cx, const wasm::Limits& memory,
                      MutableHandleArrayBufferObjectMaybeShared buffer)
 {
     MOZ_ASSERT(memory.initial % wasm::PageSize == 0);
-    MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
+    MOZ_RELEASE_ASSERT(cx->wasmHaveSignalHandlers);
     MOZ_RELEASE_ASSERT((memory.initial / wasm::PageSize) <= wasm::MaxMemoryInitialPages);
 
     // Prevent applications specifying a large max (like UINT32_MAX) from
     // unintentially OOMing the browser on 32-bit: they just want "a lot of
     // memory". Maintain the invariant that initialSize <= maxSize.
 
     Maybe<uint32_t> maxSize = memory.maximum;
     if (sizeof(void*) == 4 && maxSize) {
@@ -927,17 +927,18 @@ js::CreateWasmBuffer(JSContext* cx, cons
 // Note this function can return false with or without an exception pending. The
 // asm.js caller checks cx->isExceptionPending before propagating failure.
 // Returning false without throwing means that asm.js linking will fail which
 // will recompile as non-asm.js.
 /* static */ bool
 ArrayBufferObject::prepareForAsmJS(JSContext* cx, Handle<ArrayBufferObject*> buffer)
 {
     MOZ_ASSERT(buffer->byteLength() % wasm::PageSize == 0);
-    MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
+    // Don't assert cx->wasmHaveSignalHandlers because (1) they aren't needed
+    // for asm.js, (2) they are only installed for WebAssembly, not asm.js.
 
     if (buffer->forInlineTypedObject()) {
         return false;
     }
 
     if (!buffer->isWasm() && buffer->isPreparedForAsmJS()) {
         return true;
     }
--- a/js/src/vm/JSContext.cpp
+++ b/js/src/vm/JSContext.cpp
@@ -119,19 +119,16 @@ JSContext::init(ContextKind kind)
 
 #ifdef JS_SIMULATOR
         simulator_ = jit::Simulator::Create();
         if (!simulator_) {
             return false;
         }
 #endif
 
-        if (!wasm::EnsureSignalHandlers(this)) {
-            return false;
-        }
     } else {
         atomsZoneFreeLists_ = js_new<gc::FreeLists>();
         if (!atomsZoneFreeLists_) {
             return false;
         }
     }
 
     // Set the ContextKind last, so that ProtectedData checks will allow us to
@@ -1338,16 +1335,18 @@ JSContext::JSContext(JSRuntime* runtime,
 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
     runningOOMTest(false),
 #endif
     enableAccessValidation(false),
     inUnsafeRegion(0),
     generationalDisabled(0),
     compactingDisabledCount(0),
     suppressProfilerSampling(false),
+    wasmTriedToInstallSignalHandlers(false),
+    wasmHaveSignalHandlers(false),
     tempLifoAlloc_((size_t)TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
     debuggerMutations(0),
     ionPcScriptCache(nullptr),
     throwing(false),
     overRecursed_(false),
     propagatingForcedReturn_(false),
     liveVolatileJitFrameIter_(nullptr),
     reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
--- a/js/src/vm/JSContext.h
+++ b/js/src/vm/JSContext.h
@@ -618,19 +618,20 @@ struct JSContext : public JS::RootingCon
     }
     void disableProfilerSampling() {
         suppressProfilerSampling = true;
     }
     void enableProfilerSampling() {
         suppressProfilerSampling = false;
     }
 
-#if defined(XP_DARWIN)
-    js::wasm::MachExceptionHandler wasmMachExceptionHandler;
-#endif
+    // Used by wasm::EnsureThreadSignalHandlers(cx) to install thread signal
+    // handlers once per JSContext/thread.
+    bool wasmTriedToInstallSignalHandlers;
+    bool wasmHaveSignalHandlers;
 
     /* Temporary arena pool used while compiling and decompiling. */
     static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
   private:
     js::ThreadData<js::LifoAlloc> tempLifoAlloc_;
   public:
     js::LifoAlloc& tempLifoAlloc() { return tempLifoAlloc_.ref(); }
     const js::LifoAlloc& tempLifoAlloc() const { return tempLifoAlloc_.ref(); }
--- a/js/src/vm/MutexIDs.h
+++ b/js/src/vm/MutexIDs.h
@@ -50,16 +50,17 @@
   _(RuntimeScriptData,           500) \
   _(WasmFuncTypeIdSet,           500) \
   _(WasmCodeProfilingLabels,     500) \
   _(WasmCompileTaskState,        500) \
   _(WasmCodeBytesEnd,            500) \
   _(WasmStreamEnd,               500) \
   _(WasmStreamStatus,            500) \
   _(WasmRuntimeInstances,        500) \
+  _(WasmSignalInstallState,      500) \
                                       \
   _(IcuTimeZoneStateMutex,       600) \
   _(ThreadId,                    600) \
   _(WasmCodeSegmentMap,          600) \
   _(WasmDeferredValidation,      600) \
   _(TraceLoggerGraphState,       600) \
   _(VTuneLock,                   600)
 
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -43,16 +43,17 @@
 #include "util/Windows.h"
 #include "vm/DateTime.h"
 #include "vm/Debugger.h"
 #include "vm/JSAtom.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/TraceLogging.h"
 #include "vm/TraceLoggingGraph.h"
+#include "wasm/WasmSignalHandlers.h"
 
 #include "gc/GC-inl.h"
 #include "vm/JSContext-inl.h"
 
 using namespace js;
 
 using mozilla::Atomic;
 using mozilla::DebugOnly;
@@ -176,16 +177,19 @@ JSRuntime::JSRuntime(JSRuntime* parentRu
                                : js::StackFormat::SpiderMonkey),
     wasmInstances(mutexid::WasmRuntimeInstances),
     moduleResolveHook(),
     moduleMetadataHook(),
     moduleDynamicImportHook()
 {
     JS_COUNT_CTOR(JSRuntime);
     liveRuntimesCount++;
+
+    // See function comment for why we call this now, not in JS_Init().
+    wasm::EnsureEagerProcessSignalHandlers();
 }
 
 JSRuntime::~JSRuntime()
 {
     JS_COUNT_DTOR(JSRuntime);
     MOZ_ASSERT(!initialized_);
 
     DebugOnly<size_t> oldCount = liveRuntimesCount--;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -24,18 +24,16 @@
 #include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/UniquePtr.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/JSFunction.h"
 #include "vm/JSScript.h"
 #include "vm/SavedFrame.h"
 #include "wasm/WasmFrameIter.h"
-#include "wasm/WasmSignalHandlers.h"
-#include "wasm/WasmTypes.h"
 
 namespace JS {
 namespace dbg {
 #ifdef JS_BROKEN_GCC_ATTRIBUTE_WARNING
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wattributes"
 #endif // JS_BROKEN_GCC_ATTRIBUTE_WARNING
 
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -11086,20 +11086,16 @@ BaseCompiler::finish()
 }
 
 } // wasm
 } // js
 
 bool
 js::wasm::BaselineCanCompile()
 {
-    // On all platforms we require signals for Wasm.
-    // If we made it this far we must have signals.
-    MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
-
 #if defined(JS_CODEGEN_ARM)
     // Simplifying assumption: require SDIV and UDIV.
     //
     // I have no good data on ARM populations allowing me to say that
     // X% of devices in the market implement SDIV and UDIV.  However,
     // they are definitely implemented on the Cortex-A7 and Cortex-A15
     // and on all ARMv8 systems.
     if (!HasIDIV()) {
--- a/js/src/wasm/WasmCompile.cpp
+++ b/js/src/wasm/WasmCompile.cpp
@@ -527,18 +527,16 @@ DecodeCodeSection(const ModuleEnvironmen
 
     return mg.finishFuncDefs();
 }
 
 SharedModule
 wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, UniqueChars* error,
                     UniqueCharsVector* warnings, UniqueLinkData* maybeLinkData)
 {
-    MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
-
     Decoder d(bytecode.bytes, 0, error, warnings);
 
     CompilerEnvironment compilerEnv(args);
     ModuleEnvironment env(args.gcTypesConfigured,
                           &compilerEnv,
                           args.sharedMemoryEnabled ? Shareable::True : Shareable::False);
     if (!DecodeModuleEnvironment(d, &env)) {
         return nullptr;
@@ -571,18 +569,16 @@ wasm::CompileBuffer(const CompileArgs& a
 
     return mg.finishModule(bytecode, nullptr, maybeLinkData);
 }
 
 void
 wasm::CompileTier2(const CompileArgs& args, const Bytes& bytecode, const Module& module,
                    Atomic<bool>* cancelled)
 {
-    MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
-
     UniqueChars error;
     Decoder d(bytecode, 0, &error);
 
     HasGcTypes gcTypesConfigured = HasGcTypes::False; // No optimized backend support yet
     OptimizedBackend optimizedBackend = args.forceCranelift
                                       ? OptimizedBackend::Cranelift
                                       : OptimizedBackend::Ion;
 
@@ -709,18 +705,16 @@ wasm::CompileStreaming(const CompileArgs
                        const Bytes& envBytes,
                        const Bytes& codeBytes,
                        const ExclusiveBytesPtr& codeBytesEnd,
                        const ExclusiveStreamEndData& exclusiveStreamEnd,
                        const Atomic<bool>& cancelled,
                        UniqueChars* error,
                        UniqueCharsVector* warnings)
 {
-    MOZ_ASSERT(wasm::HaveSignalHandlers());
-
     CompilerEnvironment compilerEnv(args);
     Maybe<ModuleEnvironment> env;
 
     {
         Decoder d(envBytes, 0, error, warnings);
 
         env.emplace(args.gcTypesConfigured,
                     &compilerEnv,
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -66,17 +66,17 @@ wasm::HasCompilerSupport(JSContext* cx)
     if (!cx->jitSupportsFloatingPoint()) {
         return false;
     }
 
     if (!cx->jitSupportsUnalignedAccesses()) {
         return false;
     }
 
-    if (!wasm::HaveSignalHandlers()) {
+    if (!wasm::EnsureFullSignalHandlers(cx)) {
         return false;
     }
 
 #if !MOZ_LITTLE_ENDIAN
     return false;
 #endif
 
 #ifdef ENABLE_WASM_THREAD_OPS
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -1248,16 +1248,18 @@ Module::instantiate(JSContext* cx,
                     Handle<FunctionVector> funcImports,
                     HandleWasmTableObject tableImport,
                     HandleWasmMemoryObject memoryImport,
                     HandleValVector globalImportValues,
                     WasmGlobalObjectVector& globalObjs,
                     HandleObject instanceProto,
                     MutableHandleWasmInstanceObject instance) const
 {
+    MOZ_RELEASE_ASSERT(metadata().isAsmJS() || cx->wasmHaveSignalHandlers);
+
     if (!instantiateFunctions(cx, funcImports)) {
         return false;
     }
 
     RootedWasmMemoryObject memory(cx, memoryImport);
     if (!instantiateMemory(cx, &memory)) {
         return false;
     }
--- a/js/src/wasm/WasmOpIter.h
+++ b/js/src/wasm/WasmOpIter.h
@@ -2050,18 +2050,18 @@ OpIter<Policy>::readMemOrTableCopy(bool 
             return fail("can't touch memory without memory");
         }
     } else {
         if (env_.tables.length() == 0) {
             return fail("can't table.copy without a table");
         }
     }
 
-    uint8_t memOrTableFlags;
-    if (!readFixedU8(&memOrTableFlags)) {
+    uint32_t memOrTableFlags;
+    if (!readVarU32(&memOrTableFlags)) {
         return fail(isMem ? "unable to read memory flags" : "unable to read table flags");
     }
     if (memOrTableFlags != 0) {
         return fail(isMem ? "memory flags must be zero" : "table flags must be zero");
     }
 
     if (!popWithType(ValType::I32, len)) {
         return false;
@@ -2117,18 +2117,18 @@ inline bool
 OpIter<Policy>::readMemFill(Value* start, Value* val, Value* len)
 {
     MOZ_ASSERT(Classify(op_) == OpKind::MemFill);
 
     if (!env_.usesMemory()) {
         return fail("can't touch memory without memory");
     }
 
-    uint8_t memoryFlags;
-    if (!readFixedU8(&memoryFlags)) {
+    uint32_t memoryFlags;
+    if (!readVarU32(&memoryFlags)) {
         return fail("unable to read memory flags");
     }
     if (memoryFlags != 0) {
         return fail("memory flags must be zero");
     }
 
     if (!popWithType(ValType::I32, len)) {
         return false;
@@ -2169,18 +2169,18 @@ OpIter<Policy>::readMemOrTableInit(bool 
     if (!popWithType(ValType::I32, src)) {
         return false;
     }
 
     if (!popWithType(ValType::I32, dst)) {
         return false;
     }
 
-    uint8_t memOrTableFlags;
-    if (!readFixedU8(&memOrTableFlags)) {
+    uint32_t memOrTableFlags;
+    if (!readVarU32(&memOrTableFlags)) {
         return fail(isMem ? "unable to read memory flags" : "unable to read table flags");
     }
     if (memOrTableFlags != 0) {
         return fail(isMem ? "memory flags must be zero" : "table flags must be zero");
     }
 
     if (!readVarU32(segIndex)) {
         return false;
--- a/js/src/wasm/WasmSignalHandlers.cpp
+++ b/js/src/wasm/WasmSignalHandlers.cpp
@@ -17,37 +17,40 @@
  */
 
 #include "wasm/WasmSignalHandlers.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/ThreadLocal.h"
 
+#include "threading/Thread.h"
 #include "vm/Runtime.h"
 #include "wasm/WasmInstance.h"
 
+#if defined(XP_WIN)
+# include "util/Windows.h"
+#elif defined(XP_DARWIN)
+# include <mach/exc.h>
+# include <mach/mach.h>
+#else
+# include <signal.h>
+#endif
+
 using namespace js;
 using namespace js::wasm;
 
 using mozilla::DebugOnly;
 
 // =============================================================================
 // This following pile of macros and includes defines the ToRegisterState() and
 // the ContextTo{PC,FP,SP,LR}() functions from the (highly) platform-specific
 // CONTEXT struct which is provided to the signal handler.
 // =============================================================================
 
-#if defined(XP_WIN)
-# include "util/Windows.h"
-#else
-# include <signal.h>
-# include <sys/mman.h>
-#endif
-
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 # include <sys/ucontext.h> // for ucontext_t, mcontext_t
 #endif
 
 #if defined(__x86_64__)
 # if defined(__DragonFly__)
 #  include <machine/npx.h> // for union savefpu
 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
@@ -338,21 +341,31 @@ struct macos_arm_context {
 # define SP_sig(p) RSP_sig(p)
 # define LR_sig(p) R31_sig(p)
 #elif defined(__ppc64__) ||  defined (__PPC64__) || defined(__ppc64le__) || defined (__PPC64LE__)
 # define PC_sig(p) R32_sig(p)
 # define SP_sig(p) R01_sig(p)
 # define FP_sig(p) R01_sig(p)
 #endif
 
-static uint8_t**
+static void
+SetContextPC(CONTEXT* context, uint8_t* pc)
+{
+#ifdef PC_sig
+    *reinterpret_cast<uint8_t**>(&PC_sig(context)) = pc;
+#else
+    MOZ_CRASH();
+#endif
+}
+
+static uint8_t*
 ContextToPC(CONTEXT* context)
 {
 #ifdef PC_sig
-    return reinterpret_cast<uint8_t**>(&PC_sig(context));
+    return reinterpret_cast<uint8_t*>(PC_sig(context));
 #else
     MOZ_CRASH();
 #endif
 }
 
 static uint8_t*
 ContextToFP(CONTEXT* context)
 {
@@ -385,17 +398,17 @@ ContextToLR(CONTEXT* context)
 }
 #endif
 
 static JS::ProfilingFrameIterator::RegisterState
 ToRegisterState(CONTEXT* context)
 {
     JS::ProfilingFrameIterator::RegisterState state;
     state.fp = ContextToFP(context);
-    state.pc = *ContextToPC(context);
+    state.pc = ContextToPC(context);
     state.sp = ContextToSP(context);
 #if defined(__arm__) || defined(__aarch64__) || defined(__mips__)
     state.lr = ContextToLR(context);
 #else
     state.lr = (void*)UINTPTR_MAX;
 #endif
     return state;
 }
@@ -429,47 +442,56 @@ struct AutoHandlingTrap
 
     ~AutoHandlingTrap() {
         MOZ_ASSERT(sAlreadyHandlingTrap.get());
         sAlreadyHandlingTrap.set(false);
     }
 };
 
 static MOZ_MUST_USE bool
-HandleTrap(CONTEXT* context, JSContext* cx)
+HandleTrap(CONTEXT* context, JSContext* assertCx = nullptr)
 {
     MOZ_ASSERT(sAlreadyHandlingTrap.get());
 
-    uint8_t* pc = *ContextToPC(context);
+    uint8_t* pc = ContextToPC(context);
     const CodeSegment* codeSegment = LookupCodeSegment(pc);
     if (!codeSegment || !codeSegment->isModule()) {
         return false;
     }
 
     const ModuleSegment& segment = *codeSegment->asModule();
 
     Trap trap;
     BytecodeOffset bytecode;
     if (!segment.code().lookupTrap(pc, &trap, &bytecode)) {
         return false;
     }
 
-    // We have a safe, expected wasm trap. Call startWasmTrap() to store enough
-    // register state at the point of the trap to allow stack unwinding or
-    // resumption, both of which will call finishWasmTrap().
+    // We have a safe, expected wasm trap, so fp is well-defined to be a Frame*.
+    // For the first sanity check, the Trap::IndirectCallBadSig special case is
+    // due to this trap occurring in the indirect call prologue, while fp points
+    // to the caller's Frame which can be in a different Module. In any case,
+    // though, the containing JSContext is the same.
+    Instance* instance = ((Frame*)ContextToFP(context))->tls->instance;
+    MOZ_RELEASE_ASSERT(&instance->code() == &segment.code() || trap == Trap::IndirectCallBadSig);
+    JSContext* cx = instance->realm()->runtimeFromAnyThread()->mainContextFromAnyThread();
+    MOZ_RELEASE_ASSERT(!assertCx || cx == assertCx);
+
+    // JitActivation::startWasmTrap() stores enough register state from the
+    // point of the trap to allow stack unwinding or resumption, both of which
+    // will call finishWasmTrap().
     jit::JitActivation* activation = cx->activation()->asJit();
     activation->startWasmTrap(trap, bytecode.offset(), ToRegisterState(context));
-    *ContextToPC(context) = segment.trapCode();
+    SetContextPC(context, segment.trapCode());
     return true;
 }
 
 // =============================================================================
-// The following platform specific signal/exception handlers are installed by
-// wasm::EnsureSignalHandlers() and funnel all potential wasm traps into
-// HandleTrap() above.
+// The following platform-specific handlers funnel all signals/exceptions into
+// the shared HandleTrap() above.
 // =============================================================================
 
 #if defined(XP_WIN)
 
 static LONG WINAPI
 WasmTrapHandler(LPEXCEPTION_POINTERS exception)
 {
     if (sAlreadyHandlingTrap.get()) {
@@ -487,17 +509,19 @@ WasmTrapHandler(LPEXCEPTION_POINTERS exc
     if (!HandleTrap(exception->ContextRecord, TlsContext.get())) {
         return EXCEPTION_CONTINUE_SEARCH;
     }
 
     return EXCEPTION_CONTINUE_EXECUTION;
 }
 
 #elif defined(XP_DARWIN)
-# include <mach/exc.h>
+// On OSX we are forced to use the lower-level Mach exception mechanism instead
+// of Unix signals because breakpad uses Mach exceptions and would otherwise
+// report a crash before wasm gets a chance to handle the exception.
 
 // This definition was generated by mig (the Mach Interface Generator) for the
 // routine 'exception_raise' (exc.defs).
 #pragma pack(4)
 typedef struct {
     mach_msg_header_t Head;
     /* start of the kernel processed data */
     mach_msg_body_t msgh_body;
@@ -514,17 +538,17 @@ typedef struct {
 // The full Mach message also includes a trailer.
 struct ExceptionRequest
 {
     Request__mach_exception_raise_t body;
     mach_msg_trailer_t trailer;
 };
 
 static bool
-HandleMachException(JSContext* cx, const ExceptionRequest& request)
+HandleMachException(const ExceptionRequest& request)
 {
     // Get the port of the JSContext's thread from the message.
     mach_port_t cxThread = request.body.thread.name;
 
     // Read out the JSRuntime thread's register state.
     CONTEXT context;
 # if defined(__x86_64__)
     unsigned int thread_state_count = x86_THREAD_STATE64_COUNT;
@@ -560,17 +584,17 @@ HandleMachException(JSContext* cx, const
         request.body.exception != EXC_BAD_INSTRUCTION)
     {
         return false;
     }
 
     {
         AutoNoteSingleThreadedRegion anstr;
         AutoHandlingTrap aht;
-        if (!HandleTrap(&context, cx)) {
+        if (!HandleTrap(&context)) {
             return false;
         }
     }
 
     // Update the thread state with the new pc and register values.
     kret = thread_set_state(cxThread, float_state, (thread_state_t)&context.float_, float_state_count);
     if (kret != KERN_SUCCESS) {
         return false;
@@ -578,58 +602,48 @@ HandleMachException(JSContext* cx, const
     kret = thread_set_state(cxThread, thread_state, (thread_state_t)&context.thread, thread_state_count);
     if (kret != KERN_SUCCESS) {
         return false;
     }
 
     return true;
 }
 
-// Taken from mach_exc in /usr/include/mach/mach_exc.defs.
-static const mach_msg_id_t sExceptionId = 2405;
-
-// The choice of id here is arbitrary, the only constraint is that sQuitId != sExceptionId.
-static const mach_msg_id_t sQuitId = 42;
+static mach_port_t sMachDebugPort = MACH_PORT_NULL;
 
 static void
-MachExceptionHandlerThread(JSContext* cx)
+MachExceptionHandlerThread()
 {
-    mach_port_t port = cx->wasmMachExceptionHandler.port();
-    kern_return_t kret;
+    // Taken from mach_exc in /usr/include/mach/mach_exc.defs.
+    static const unsigned EXCEPTION_MSG_ID = 2405;
 
-    while(true) {
+    while (true) {
         ExceptionRequest request;
-        kret = mach_msg(&request.body.Head, MACH_RCV_MSG, 0, sizeof(request),
-                        port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+        kern_return_t kret = mach_msg(&request.body.Head, MACH_RCV_MSG, 0, sizeof(request),
+                                      sMachDebugPort, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
 
         // If we fail even receiving the message, we can't even send a reply!
         // Rather than hanging the faulting thread (hanging the browser), crash.
         if (kret != KERN_SUCCESS) {
             fprintf(stderr, "MachExceptionHandlerThread: mach_msg failed with %d\n", (int)kret);
             MOZ_CRASH();
         }
 
-        // There are only two messages we should be receiving: an exception
-        // message that occurs when the runtime's thread faults and the quit
-        // message sent when the runtime is shutting down.
-        if (request.body.Head.msgh_id == sQuitId) {
-            break;
-        }
-        if (request.body.Head.msgh_id != sExceptionId) {
+        if (request.body.Head.msgh_id != EXCEPTION_MSG_ID) {
             fprintf(stderr, "Unexpected msg header id %d\n", (int)request.body.Head.msgh_bits);
             MOZ_CRASH();
         }
 
         // Some thread just commited an EXC_BAD_ACCESS and has been suspended by
         // the kernel. The kernel is waiting for us to reply with instructions.
         // Our default is the "not handled" reply (by setting the RetCode field
         // of the reply to KERN_FAILURE) which tells the kernel to continue
         // searching at the process and system level. If this is an asm.js
         // expected exception, we handle it and return KERN_SUCCESS.
-        bool handled = HandleMachException(cx, request);
+        bool handled = HandleMachException(request);
         kern_return_t replyCode = handled ? KERN_SUCCESS : KERN_FAILURE;
 
         // This magic incantation to send a reply back to the kernel was derived
         // from the exc_server generated by 'mig -v /usr/include/mach/mach_exc.defs'.
         __Reply__exception_raise_t reply;
         reply.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request.body.Head.msgh_bits), 0);
         reply.Head.msgh_size = sizeof(reply);
         reply.Head.msgh_remote_port = request.body.Head.msgh_remote_port;
@@ -637,111 +651,16 @@ MachExceptionHandlerThread(JSContext* cx
         reply.Head.msgh_id = request.body.Head.msgh_id + 100;
         reply.NDR = NDR_record;
         reply.RetCode = replyCode;
         mach_msg(&reply.Head, MACH_SEND_MSG, sizeof(reply), 0, MACH_PORT_NULL,
                  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
     }
 }
 
-MachExceptionHandler::MachExceptionHandler()
-  : installed_(false),
-    thread_(),
-    port_(MACH_PORT_NULL)
-{}
-
-void
-MachExceptionHandler::uninstall()
-{
-    if (installed_) {
-        thread_port_t thread = mach_thread_self();
-        kern_return_t kret = thread_set_exception_ports(thread,
-                                                        EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION,
-                                                        MACH_PORT_NULL,
-                                                        EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
-                                                        THREAD_STATE_NONE);
-        mach_port_deallocate(mach_task_self(), thread);
-        if (kret != KERN_SUCCESS) {
-            MOZ_CRASH();
-        }
-        installed_ = false;
-    }
-    if (thread_.joinable()) {
-        // Break the handler thread out of the mach_msg loop.
-        mach_msg_header_t msg;
-        msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
-        msg.msgh_size = sizeof(msg);
-        msg.msgh_remote_port = port_;
-        msg.msgh_local_port = MACH_PORT_NULL;
-        msg.msgh_reserved = 0;
-        msg.msgh_id = sQuitId;
-        kern_return_t kret = mach_msg(&msg, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL,
-                                      MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
-        if (kret != KERN_SUCCESS) {
-            fprintf(stderr, "MachExceptionHandler: failed to send quit message: %d\n", (int)kret);
-            MOZ_CRASH();
-        }
-
-        // Wait for the handler thread to complete before deallocating the port.
-        thread_.join();
-    }
-    if (port_ != MACH_PORT_NULL) {
-        DebugOnly<kern_return_t> kret = mach_port_destroy(mach_task_self(), port_);
-        MOZ_ASSERT(kret == KERN_SUCCESS);
-        port_ = MACH_PORT_NULL;
-    }
-}
-
-bool
-MachExceptionHandler::install(JSContext* cx)
-{
-    MOZ_ASSERT(!installed());
-    kern_return_t kret;
-    mach_port_t thread;
-
-    auto onFailure = mozilla::MakeScopeExit([&] {
-        uninstall();
-    });
-
-    // Get a port which can send and receive data.
-    kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port_);
-    if (kret != KERN_SUCCESS) {
-        return false;
-    }
-    kret = mach_port_insert_right(mach_task_self(), port_, port_, MACH_MSG_TYPE_MAKE_SEND);
-    if (kret != KERN_SUCCESS) {
-        return false;
-    }
-
-    // Create a thread to block on reading port_.
-    if (!thread_.init(MachExceptionHandlerThread, cx)) {
-        return false;
-    }
-
-    // Direct exceptions on this thread to port_ (and thus our handler thread).
-    // Note: we are totally clobbering any existing *thread* exception ports and
-    // not even attempting to forward. Breakpad and gdb both use the *process*
-    // exception ports which are only called if the thread doesn't handle the
-    // exception, so we should be fine.
-    thread = mach_thread_self();
-    kret = thread_set_exception_ports(thread,
-                                      EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION,
-                                      port_,
-                                      EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
-                                      THREAD_STATE_NONE);
-    mach_port_deallocate(mach_task_self(), thread);
-    if (kret != KERN_SUCCESS) {
-        return false;
-    }
-
-    installed_ = true;
-    onFailure.release();
-    return true;
-}
-
 #else  // If not Windows or Mac, assume Unix
 
 #ifdef __mips__
 static const uint32_t kWasmTrapSignal = SIGFPE;
 #else
 static const uint32_t kWasmTrapSignal = SIGILL;
 #endif
 
@@ -789,69 +708,77 @@ WasmTrapHandler(int signum, siginfo_t* i
     }
 }
 # endif // XP_WIN || XP_DARWIN || assume unix
 
 #if defined(ANDROID) && defined(MOZ_LINKER)
 extern "C" MFBT_API bool IsSignalHandlingBroken();
 #endif
 
-static bool sTriedInstallSignalHandlers = false;
-static bool sHaveSignalHandlers = false;
-
-static bool
-ProcessHasSignalHandlers()
+struct InstallState
 {
-    // We assume that there are no races creating the first JSRuntime of the process.
-    if (sTriedInstallSignalHandlers) {
-        return sHaveSignalHandlers;
+    bool tried;
+    bool success;
+    InstallState() : tried(false), success(false) {}
+};
+
+static ExclusiveData<InstallState> sEagerInstallState(mutexid::WasmSignalInstallState);
+
+void
+wasm::EnsureEagerProcessSignalHandlers()
+{
+    auto eagerInstallState = sEagerInstallState.lock();
+    if (eagerInstallState->tried) {
+        return;
     }
-    sTriedInstallSignalHandlers = true;
+
+    eagerInstallState->tried = true;
+    MOZ_RELEASE_ASSERT(eagerInstallState->success == false);
 
 #if defined (JS_CODEGEN_NONE)
     // If there is no JIT, then there should be no Wasm signal handlers.
-    return false;
+    return;
 #endif
 
     // Signal handlers are currently disabled when recording or replaying.
     if (mozilla::recordreplay::IsRecordingOrReplaying()) {
-        return false;
+        return;
     }
 
 #if defined(ANDROID) && defined(MOZ_LINKER)
     // Signal handling is broken on some android systems.
     if (IsSignalHandlingBroken()) {
-        return false;
+        return;
     }
 #endif
 
-    // Initalize ThreadLocal flag used by WasmTrapHandler
     sAlreadyHandlingTrap.infallibleInit();
 
-    // Install a SIGSEGV handler to handle safely-out-of-bounds asm.js heap
-    // access and/or unaligned accesses.
+    // Install whatever exception/signal handler is appropriate for the OS.
 #if defined(XP_WIN)
 
 # if defined(MOZ_ASAN)
     // Under ASan we need to let the ASan runtime's ShadowExceptionHandler stay
     // in the first handler position. This requires some coordination with
     // MemoryProtectionExceptionHandler::isDisabled().
     const bool firstHandler = false;
 # else
     // Otherwise, WasmTrapHandler needs to go first, so that we can recover
     // from wasm faults and continue execution without triggering handlers
     // such as MemoryProtectionExceptionHandler that assume we are crashing.
     const bool firstHandler = true;
 # endif
     if (!AddVectoredExceptionHandler(firstHandler, WasmTrapHandler)) {
-        return false;
+        // Windows has all sorts of random security knobs for disabling things
+        // so make this a dynamic failure that disables wasm, not a MOZ_CRASH().
+        return;
     }
+
 #elif defined(XP_DARWIN)
-    // OSX handles seg faults via the Mach exception handler above, so don't
-    // install WasmTrapHandler.
+    // All the Mach setup in EnsureLazyProcessSignalHandlers.
 #else
     // SA_NODEFER allows us to reenter the signal handler if we crash while
     // handling the signal, and fall through to the Breakpad handler by testing
     // handlingSegFault.
 
     // Allow handling OOB with signals on all architectures
     struct sigaction faultHandler;
     faultHandler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
@@ -878,46 +805,107 @@ ProcessHasSignalHandlers()
     wasmTrapHandler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
     wasmTrapHandler.sa_sigaction = WasmTrapHandler;
     sigemptyset(&wasmTrapHandler.sa_mask);
     if (sigaction(kWasmTrapSignal, &wasmTrapHandler, &sPrevWasmTrapHandler)) {
         MOZ_CRASH("unable to install wasm trap handler");
     }
 #endif
 
-    sHaveSignalHandlers = true;
+    eagerInstallState->success = true;
+}
+
+static ExclusiveData<InstallState> sLazyInstallState(mutexid::WasmSignalInstallState);
+
+static bool
+EnsureLazyProcessSignalHandlers()
+{
+    auto lazyInstallState = sLazyInstallState.lock();
+    if (lazyInstallState->tried) {
+        return lazyInstallState->success;
+    }
+
+    lazyInstallState->tried = true;
+    MOZ_RELEASE_ASSERT(lazyInstallState->success == false);
+
+#ifdef XP_DARWIN
+    // Create the port that all JSContext threads will redirect their traps to.
+    kern_return_t kret;
+    kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &sMachDebugPort);
+    if (kret != KERN_SUCCESS) {
+        return false;
+    }
+    kret = mach_port_insert_right(mach_task_self(), sMachDebugPort, sMachDebugPort,
+                                  MACH_MSG_TYPE_MAKE_SEND);
+    if (kret != KERN_SUCCESS) {
+        return false;
+    }
+
+    // Create the thread that will wait on and service sMachDebugPort.
+    // It's not useful to destroy this thread on process shutdown so
+    // immediately detach on successful start.
+    Thread handlerThread;
+    if (!handlerThread.init(MachExceptionHandlerThread)) {
+        return false;
+    }
+    handlerThread.detach();
+#endif
+
+    lazyInstallState->success = true;
     return true;
 }
 
 bool
-wasm::EnsureSignalHandlers(JSContext* cx)
+wasm::EnsureFullSignalHandlers(JSContext* cx)
 {
-    // Nothing to do if the platform doesn't support it.
-    if (!ProcessHasSignalHandlers()) {
-        return true;
+    if (cx->wasmTriedToInstallSignalHandlers) {
+        return cx->wasmHaveSignalHandlers;
+    }
+
+    cx->wasmTriedToInstallSignalHandlers = true;
+    MOZ_RELEASE_ASSERT(!cx->wasmHaveSignalHandlers);
+
+    {
+        auto eagerInstallState = sEagerInstallState.lock();
+        MOZ_RELEASE_ASSERT(eagerInstallState->tried);
+        if (!eagerInstallState->success) {
+            return false;
+        }
     }
 
-#if defined(XP_DARWIN)
-    // On OSX, each JSContext which runs wasm gets its own handler thread.
-    if (!cx->wasmMachExceptionHandler.installed() && !cx->wasmMachExceptionHandler.install(cx)) {
+    if (!EnsureLazyProcessSignalHandlers()) {
+        return false;
+    }
+
+#ifdef XP_DARWIN
+    // In addition to the process-wide signal handler setup, OSX needs each
+    // thread configured to send its exceptions to sMachDebugPort. While there
+    // are also task-level (i.e. process-level) exception ports, those are
+    // "claimed" by breakpad and chaining Mach exceptions is dark magic that we
+    // avoid by instead intercepting exceptions at the thread level before they
+    // propagate to the process-level. This works because there are no other
+    // uses of thread-level exception ports.
+    MOZ_RELEASE_ASSERT(sMachDebugPort != MACH_PORT_NULL);
+    thread_port_t thisThread = mach_thread_self();
+    kern_return_t kret = thread_set_exception_ports(thisThread,
+                                                    EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION,
+                                                    sMachDebugPort,
+                                                    EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
+                                                    THREAD_STATE_NONE);
+    mach_port_deallocate(mach_task_self(), thisThread);
+    if (kret != KERN_SUCCESS) {
         return false;
     }
 #endif
 
+    cx->wasmHaveSignalHandlers = true;
     return true;
 }
 
 bool
-wasm::HaveSignalHandlers()
-{
-    MOZ_ASSERT(sTriedInstallSignalHandlers);
-    return sHaveSignalHandlers;
-}
-
-bool
 wasm::MemoryAccessTraps(const RegisterState& regs, uint8_t* addr, uint32_t numBytes, uint8_t** newPC)
 {
     const wasm::CodeSegment* codeSegment = wasm::LookupCodeSegment(regs.pc);
     if (!codeSegment || !codeSegment->isModule()) {
         return false;
     }
 
     const wasm::ModuleSegment& segment = *codeSegment->asModule();
--- a/js/src/wasm/WasmSignalHandlers.h
+++ b/js/src/wasm/WasmSignalHandlers.h
@@ -16,71 +16,53 @@
  * limitations under the License.
  */
 
 #ifndef wasm_signal_handlers_h
 #define wasm_signal_handlers_h
 
 #include "mozilla/Attributes.h"
 
-#if defined(XP_DARWIN)
-# include <mach/mach.h>
-#endif
-
 #include "js/ProfilingFrameIterator.h"
-#include "threading/Thread.h"
 #include "wasm/WasmProcess.h"
 
 namespace js {
 namespace wasm {
 
 typedef JS::ProfilingFrameIterator::RegisterState RegisterState;
 
-// Ensure the given JSRuntime is set up to use signals. Failure to enable signal
-// handlers indicates some catastrophic failure and creation of the runtime must
-// fail.
-MOZ_MUST_USE bool
-EnsureSignalHandlers(JSContext* cx);
+// This function performs the low-overhead signal handler initialization that we
+// want to do eagerly to ensure a more-deterministic global process state. This
+// is especially relevant for signal handlers since handler ordering depends on
+// installation order: the wasm signal handler must run *before* the other crash
+// handlers (ds/MemoryProtectionExceptionHandler.h and breakpad) and since POSIX
+// signal handlers work LIFO, this function needs to be called at the end of the
+// startup process, after the other two handlers have been installed. Currently,
+// this is achieved by having JSRuntime() call this function. There can be
+// multiple JSRuntimes per process so this function can thus be called multiple
+// times, having no effect after the first call.
+void
+EnsureEagerProcessSignalHandlers();
 
-// Return whether signals can be used in this process for asm.js/wasm
-// out-of-bounds.
+// Assuming EnsureEagerProcessSignalHandlers() has already been called,
+// this function performs the full installation of signal handlers which must
+// be performed per-thread/JSContext. This operation may incur some overhead and
+// so should be done only when needed to use wasm. Currently, this is done in
+// wasm::HasCompilerSupport() which is called when deciding whether to expose the
+// 'WebAssembly' object on the global object.
 bool
-HaveSignalHandlers();
+EnsureFullSignalHandlers(JSContext* cx);
 
 // Return whether, with the given simulator register state, a memory access to
 // 'addr' of size 'numBytes' needs to trap and, if so, where the simulator
 // should redirect pc to.
 bool
 MemoryAccessTraps(const RegisterState& regs, uint8_t* addr, uint32_t numBytes, uint8_t** newPC);
 
 // Return whether, with the given simulator register state, an illegal
 // instruction fault is expected and, if so, the value of the next PC.
 bool
 HandleIllegalInstruction(const RegisterState& regs, uint8_t** newPC);
 
-#if defined(XP_DARWIN)
-// On OSX we are forced to use the lower-level Mach exception mechanism instead
-// of Unix signals. Mach exceptions are not handled on the victim's stack but
-// rather require an extra thread. For simplicity, we create one such thread
-// per JSContext (upon the first use of wasm in the JSContext). This thread
-// and related resources are owned by AsmJSMachExceptionHandler which is owned
-// by JSContext.
-class MachExceptionHandler
-{
-    bool installed_;
-    js::Thread thread_;
-    mach_port_t port_;
-
-    void uninstall();
-
-  public:
-    MachExceptionHandler();
-    ~MachExceptionHandler() { uninstall(); }
-    mach_port_t port() const { return port_; }
-    bool installed() const { return installed_; }
-    bool install(JSContext* cx);
-};
-#endif
-
 } // namespace wasm
 } // namespace js
 
 #endif // wasm_signal_handlers_h
--- a/js/src/wasm/WasmTextToBinary.cpp
+++ b/js/src/wasm/WasmTextToBinary.cpp
@@ -6285,53 +6285,51 @@ EncodeWake(Encoder& e, AstWake& s)
 {
     return EncodeLoadStoreAddress(e, s.address()) &&
            EncodeExpr(e, s.count()) &&
            e.writeOp(ThreadOp::Wake) &&
            EncodeLoadStoreFlags(e, s.address());
 }
 
 #ifdef ENABLE_WASM_BULKMEM_OPS
-static const uint8_t DEFAULT_MEM_TABLE_FLAGS = 0;
-
 static bool
 EncodeMemOrTableCopy(Encoder& e, AstMemOrTableCopy& s)
 {
     return EncodeExpr(e, s.dest()) &&
            EncodeExpr(e, s.src()) &&
            EncodeExpr(e, s.len()) &&
            e.writeOp(s.isMem() ? MiscOp::MemCopy : MiscOp::TableCopy) &&
-           e.writeFixedU8(DEFAULT_MEM_TABLE_FLAGS);
+           e.writeVarU32(uint32_t(MemoryTableFlags::Default));
 }
 
 static bool
 EncodeMemOrTableDrop(Encoder& e, AstMemOrTableDrop& s)
 {
     return e.writeOp(s.isMem() ? MiscOp::MemDrop : MiscOp::TableDrop) &&
            e.writeVarU32(s.segIndex());
 }
 
 static bool
 EncodeMemFill(Encoder& e, AstMemFill& s)
 {
     return EncodeExpr(e, s.start()) &&
            EncodeExpr(e, s.val()) &&
            EncodeExpr(e, s.len()) &&
            e.writeOp(MiscOp::MemFill) &&
-           e.writeFixedU8(DEFAULT_MEM_TABLE_FLAGS);
+           e.writeVarU32(uint32_t(MemoryTableFlags::Default));
 }
 
 static bool
 EncodeMemOrTableInit(Encoder& e, AstMemOrTableInit& s)
 {
     return EncodeExpr(e, s.dst()) &&
            EncodeExpr(e, s.src()) &&
            EncodeExpr(e, s.len()) &&
            e.writeOp(s.isMem() ? MiscOp::MemInit : MiscOp::TableInit) &&
-           e.writeFixedU8(DEFAULT_MEM_TABLE_FLAGS) &&
+           e.writeVarU32(uint32_t(MemoryTableFlags::Default)) &&
            e.writeVarU32(s.segIndex());
 }
 #endif
 
 #ifdef ENABLE_WASM_GC
 static bool
 EncodeStructNew(Encoder& e, AstStructNew& s)
 {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4157,19 +4157,17 @@ nsIFrame::IsSelectable(StyleUserSelect* 
   //
   StyleUserSelect selectStyle  = StyleUserSelect::Auto;
   nsIFrame* frame              = const_cast<nsIFrame*>(this);
   bool containsEditable        = false;
 
   while (frame) {
     const nsStyleUIReset* userinterface = frame->StyleUIReset();
     switch (userinterface->mUserSelect) {
-      case StyleUserSelect::All:
-      case StyleUserSelect::MozAll:
-      {
+      case StyleUserSelect::All: {
         // override the previous values
         if (selectStyle != StyleUserSelect::MozText) {
           selectStyle = userinterface->mUserSelect;
         }
         nsIContent* frameContent = frame->GetContent();
         containsEditable = frameContent &&
           frameContent->EditableDescendantCount() > 0;
         break;
@@ -4183,18 +4181,16 @@ nsIFrame::IsSelectable(StyleUserSelect* 
     }
     frame = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
   }
 
   // convert internal values to standard values
   if (selectStyle == StyleUserSelect::Auto ||
       selectStyle == StyleUserSelect::MozText) {
     selectStyle = StyleUserSelect::Text;
-  } else if (selectStyle == StyleUserSelect::MozAll) {
-    selectStyle = StyleUserSelect::All;
   }
 
   // If user tries to select all of a non-editable content,
   // prevent selection if it contains editable content.
   bool allowSelection = true;
   if (selectStyle == StyleUserSelect::All) {
     allowSelection = !containsEditable;
   }
@@ -4263,18 +4259,16 @@ nsFrame::HandlePress(nsPresContext* aPre
   // check whether style allows selection
   // if not, don't tell selection the mouse event even occurred.
   StyleUserSelect selectStyle;
   // check for select: none
   if (!IsSelectable(&selectStyle)) {
     return NS_OK;
   }
 
-  // When implementing StyleUserSelect::Element, StyleUserSelect::Elements and
-  // StyleUserSelect::Toggle, need to change this logic
   bool useFrameSelection = (selectStyle == StyleUserSelect::Text);
 
   // If the mouse is dragged outside the nearest enclosing scrollable area
   // while making a selection, the area will be scrolled. To do this, capture
   // the mouse on the nearest scrollable frame. If there isn't a scrollable
   // frame, or something else is already capturing the mouse, there's no
   // reason to capture.
   if (!nsIPresShell::GetCapturingContent()) {
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -391,16 +391,17 @@ cbindgen-types = [
     { gecko = "StyleDisplayMode", servo = "gecko::media_features::DisplayMode" },
     { gecko = "StyleFillRule", servo = "values::generics::basic_shape::FillRule" },
     { gecko = "StyleFontDisplay", servo = "font_face::FontDisplay" },
     { gecko = "StyleFontFaceSourceListComponent", servo = "font_face::FontFaceSourceListComponent" },
     { gecko = "StyleFontLanguageOverride", servo = "values::computed::font::FontLanguageOverride" },
     { gecko = "StylePathCommand", servo = "values::specified::svg_path::PathCommand" },
     { gecko = "StyleUnicodeRange", servo = "cssparser::UnicodeRange" },
     { gecko = "StyleOverflowWrap", servo = "values::computed::OverflowWrap" },
+    { gecko = "StyleUserSelect", servo = "values::computed::UserSelect" },
 ]
 
 mapped-generic-types = [
     { generic = true, gecko = "mozilla::RustCell", servo = "::std::cell::Cell" },
     { generic = false, gecko = "ServoNodeData", servo = "AtomicRefCell<ElementData>" },
     { generic = false, gecko = "mozilla::ServoWritingMode", servo = "::logical_geometry::WritingMode" },
     { generic = false, gecko = "mozilla::ServoCustomPropertiesMap", servo = "Option<::servo_arc::Arc<::custom_properties::CustomPropertiesMap>>" },
     { generic = false, gecko = "mozilla::ServoRuleNode", servo = "Option<::rule_tree::StrongRuleNode>" },
--- a/layout/style/ServoCSSPropList.mako.py
+++ b/layout/style/ServoCSSPropList.mako.py
@@ -106,16 +106,17 @@ SERIALIZED_PREDEFINED_TYPES = [
     "Quotes",
     "Resize",
     "Rotate",
     "Scale",
     "TextAlign",
     "Translate",
     "TimingFunction",
     "TransformStyle",
+    "UserSelect",
     "background::BackgroundSize",
     "basic_shape::ClippingShape",
     "basic_shape::FloatAreaShape",
     "position::HorizontalPosition",
     "position::VerticalPosition",
     "url::ImageUrlOrNone",
 ]
 
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -218,30 +218,16 @@ enum class StyleUserFocus : uint8_t {
   Normal,
   SelectAll,
   SelectBefore,
   SelectAfter,
   SelectSame,
   SelectMenu,
 };
 
-// user-select
-enum class StyleUserSelect : uint8_t {
-  None,
-  Text,
-  Element,
-  Elements,
-  All,
-  Toggle,
-  TriState,
-  Auto,     // internal value - please use nsFrame::IsSelectable()
-  MozAll,   // force selection of all children, unless an ancestor has NONE set - bug 48096
-  MozText,  // Like TEXT, except that it won't get overridden by ancestors having ALL.
-};
-
 // user-input
 enum class StyleUserInput : uint8_t {
   None,
   Auto,
 };
 
 // user-modify
 enum class StyleUserModify : uint8_t {
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -2620,17 +2620,17 @@ var gCSSProperties = {
     other_values: [ "read-write", "write-only" ],
     invalid_values: []
   },
   "-moz-user-select": {
     domProp: "MozUserSelect",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "auto" ],
-    other_values: [ "none", "text", "element", "elements", "all", "toggle", "tri-state", "-moz-all", "-moz-none" ],
+    other_values: [ "none", "text", "all", "-moz-none" ],
     invalid_values: []
   },
   "background": {
     domProp: "background",
     inherited: false,
     type: CSS_TYPE_TRUE_SHORTHAND,
     subproperties: [ "background-attachment", "background-color", "background-image", "background-position-x", "background-position-y", "background-repeat", "background-clip", "background-origin", "background-size" ],
     initial_values: [ "transparent", "none", "repeat", "scroll", "0% 0%", "top left", "left top", "0% 0% / auto", "top left / auto", "left top / auto", "0% 0% / auto auto",
--- a/layout/style/test/test_non_content_accessible_values.html
+++ b/layout/style/test/test_non_content_accessible_values.html
@@ -105,16 +105,19 @@ const NON_CONTENT_ACCESSIBLE_VALUES = {
     "-moz-mac-disclosure-button-open",
     "-moz-mac-source-list",
     "-moz-mac-source-list-selection",
     "-moz-mac-vibrancy-dark",
     "-moz-mac-vibrancy-light",
     "-moz-mac-vibrant-titlebar-dark",
     "-moz-mac-vibrant-titlebar-light",
   ],
+  "-moz-user-select": [
+    "-moz-text",
+  ],
 };
 
 if (!SpecialPowers.getBoolPref("layout.css.xul-box-display-values.content.enabled")) {
   NON_CONTENT_ACCESSIBLE_VALUES.display.push("-moz-box", "-moz-inline-box");
 }
 
 const sheet = document.getElementById("sheet");
 const div = document.querySelector("div");
--- a/servo/components/style/cbindgen.toml
+++ b/servo/components/style/cbindgen.toml
@@ -48,10 +48,11 @@ include = [
   "FillRule",
   "FontDisplay",
   "FontFaceSourceListComponent",
   "FontLanguageOverride",
   "OverflowWrap",
   "TimingFunction",
   "PathCommand",
   "UnicodeRange",
+  "UserSelect",
 ]
 item_types = ["enums", "structs", "typedefs"]
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -331,16 +331,17 @@ class Longhand(object):
                 "SVGOpacity",
                 "SVGPaintOrder",
                 "ScrollSnapType",
                 "TextAlign",
                 "TextDecorationLine",
                 "TextEmphasisPosition",
                 "TouchAction",
                 "TransformStyle",
+                "UserSelect",
                 "XSpan",
                 "XTextZoom",
                 "ZIndex",
             }
         if self.name == "overflow-y":
             return True
         return bool(self.keyword)
 
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -1424,16 +1424,17 @@ impl Clone for ${style_struct.gecko_stru
         "Position": impl_position,
         "RGBAColor": impl_rgba_color,
         "SVGLength": impl_svg_length,
         "SVGOpacity": impl_svg_opacity,
         "SVGPaint": impl_svg_paint,
         "SVGWidth": impl_svg_length,
         "Transform": impl_transform,
         "TransformOrigin": impl_transform_origin,
+        "UserSelect": impl_simple,
         "url::UrlOrNone": impl_css_url,
     }
 
     def longhand_method(longhand):
         args = dict(ident=longhand.ident, gecko_ffi_name=longhand.gecko_ffi_name)
 
         # get the method and pass additional keyword or type-specific arguments
         if longhand.logical:
--- a/servo/components/style/properties/longhands/ui.mako.rs
+++ b/servo/components/style/properties/longhands/ui.mako.rs
@@ -26,25 +26,23 @@
     products="gecko",
     gecko_enum_prefix="StyleScrollbarWidth",
     animation_value_type="discrete",
     gecko_pref="layout.css.scrollbar-width.enabled",
     enabled_in="chrome",
     spec="https://drafts.csswg.org/css-scrollbars-1/#scrollbar-width"
 )}
 
-${helpers.single_keyword(
+${helpers.predefined_type(
     "-moz-user-select",
-    "auto text none all element elements toggle tri-state -moz-all -moz-text",
+    "UserSelect",
+    "computed::UserSelect::Auto",
     products="gecko",
+    gecko_ffi_name="mUserSelect",
     alias="-webkit-user-select",
-    gecko_ffi_name="mUserSelect",
-    gecko_enum_prefix="StyleUserSelect",
-    gecko_strip_moz_prefix=False,
-    aliases="-moz-none=none",
     animation_value_type="discrete",
     spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select",
 )}
 
 // TODO(emilio): This probably should be hidden from content.
 ${helpers.single_keyword(
     "-moz-window-dragging",
     "default drag no-drag",
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -79,17 +79,17 @@ pub use self::table::XSpan;
 pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize};
 pub use self::text::{OverflowWrap, TextOverflow, WordSpacing};
 pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};
 pub use self::time::Time;
 pub use self::transform::{Rotate, Scale, Transform, TransformOperation};
 pub use self::transform::{TransformOrigin, TransformStyle, Translate};
 #[cfg(feature = "gecko")]
 pub use self::ui::CursorImage;
-pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon};
+pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon, UserSelect};
 pub use super::specified::{BorderStyle, TextDecorationLine};
 pub use super::{Auto, Either, None_};
 pub use app_units::Au;
 
 #[cfg(feature = "gecko")]
 pub mod align;
 pub mod angle;
 pub mod background;
--- a/servo/components/style/values/computed/ui.rs
+++ b/servo/components/style/values/computed/ui.rs
@@ -5,17 +5,17 @@
 //! Computed values for UI properties
 
 use crate::values::computed::color::Color;
 use crate::values::computed::url::ComputedImageUrl;
 use crate::values::computed::Number;
 use crate::values::generics::ui as generics;
 use crate::values::{Auto, Either};
 
-pub use crate::values::specified::ui::MozForceBrokenImageIcon;
+pub use crate::values::specified::ui::{MozForceBrokenImageIcon, UserSelect};
 
 /// auto | <color>
 pub type ColorOrAuto = Either<Color, Auto>;
 
 /// A computed value for the `cursor` property.
 pub type Cursor = generics::Cursor<CursorImage>;
 
 /// A computed value for item of `image cursors`.
--- a/servo/components/style/values/specified/box.rs
+++ b/servo/components/style/values/specified/box.rs
@@ -47,19 +47,16 @@ fn moz_box_display_values_enabled(contex
 /// <https://drafts.csswg.org/css-display/#propdef-display>
 ///
 ///
 /// NOTE(emilio): Order is important in Gecko!
 ///
 /// If you change it, make sure to take a look at the
 /// FrameConstructionDataByDisplay stuff (both the XUL and non-XUL version), and
 /// ensure it's still correct!
-///
-/// Also, when you change this from Gecko you may need to regenerate the
-/// C++-side bindings (see components/style/cbindgen.toml).
 #[allow(missing_docs)]
 #[derive(
     Clone,
     Copy,
     Debug,
     Eq,
     FromPrimitive,
     Hash,
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -77,17 +77,17 @@ pub use self::table::XSpan;
 pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize, TextAlign};
 pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle};
 pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
 pub use self::time::Time;
 pub use self::transform::{Rotate, Scale, Transform};
 pub use self::transform::{TransformOrigin, TransformStyle, Translate};
 #[cfg(feature = "gecko")]
 pub use self::ui::CursorImage;
-pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon};
+pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon, UserSelect};
 pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
 
 #[cfg(feature = "gecko")]
 pub mod align;
 pub mod angle;
 pub mod background;
 pub mod basic_shape;
 pub mod border;
--- a/servo/components/style/values/specified/ui.rs
+++ b/servo/components/style/values/specified/ui.rs
@@ -135,8 +135,48 @@ impl Parse for ScrollbarColor {
             return Ok(generics::ScrollbarColor::Auto);
         }
         Ok(generics::ScrollbarColor::Colors {
             thumb: Color::parse(context, input)?,
             track: Color::parse(context, input)?,
         })
     }
 }
+
+fn in_ua_sheet(context: &ParserContext) -> bool {
+    use crate::stylesheets::Origin;
+    context.stylesheet_origin == Origin::UserAgent
+}
+
+/// The specified value for the `user-select` property.
+///
+/// https://drafts.csswg.org/css-ui-4/#propdef-user-select
+#[allow(missing_docs)]
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    Eq,
+    MallocSizeOf,
+    Parse,
+    PartialEq,
+    SpecifiedValueInfo,
+    ToComputedValue,
+    ToCss,
+)]
+#[repr(u8)]
+pub enum UserSelect {
+    Auto,
+    Text,
+    #[parse(aliases = "-moz-none")]
+    None,
+    /// Force selection of all children, unless an ancestor has `none` set.
+    All,
+    /// Like `text`, except that it won't get overridden by ancestors having
+    /// `all`.
+    ///
+    /// FIXME(emilio): This only has one use in contenteditable.css, can we find
+    /// a better way to do this?
+    ///
+    /// See bug 1181130.
+    #[parse(condition = "in_ua_sheet")]
+    MozText,
+}
--- a/taskcluster/ci/toolchain/linux.yml
+++ b/taskcluster/ci/toolchain/linux.yml
@@ -570,17 +570,17 @@ linux64-rust-nightly-macos:
     worker:
         max-run-time: 7200
         env:
             UPLOAD_DIR: artifacts
     run:
         using: toolchain-script
         script: repack_rust.py
         arguments: [
-            '--channel', 'nightly-2018-09-16',
+            '--channel', 'nightly-2018-10-05',
             '--host', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-apple-darwin',
         ]
         toolchain-artifact: public/build/rustc.tar.xz
 
 linux64-rust-android-1.30:
     description: "rust repack with android-cross support"
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/IndexedDB/key_valid.html.ini
@@ -0,0 +1,3 @@
+[key_valid.html]
+  disabled:
+    if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): https://bugzilla.mozilla.org/show_bug.cgi?id=1506417
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/wasm/jsapi/constructor/compile.any.js.ini
@@ -0,0 +1,13 @@
+[compile.any.worker.html]
+  [Invalid code]
+    expected: FAIL
+
+
+[compile.any.html]
+  [Invalid code]
+    expected: FAIL
+
+
+[compile.any.js]
+  [Invalid code]
+    expected: FAIL
--- a/testing/web-platform/tests/wasm/jsapi/constructor/compile.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/constructor/compile.any.js
@@ -57,16 +57,21 @@ test(() => {
   const promise = WebAssembly.compile(emptyModuleBinary);
   assert_equals(Object.getPrototypeOf(promise), Promise.prototype, "prototype");
   assert_true(Object.isExtensible(promise), "extensibility");
 }, "Promise type");
 
 promise_test(t => {
   const buffer = new Uint8Array();
   return promise_rejects(t, new WebAssembly.CompileError(), WebAssembly.compile(buffer));
+}, "Empty buffer");
+
+test(() => {
+  const buffer = new Uint8Array(Array.from(emptyModuleBinary).concat([0, 0]));
+  assert_throws(new WebAssembly.CompileError(), () => WebAssembly.compile(buffer));
 }, "Invalid code");
 
 promise_test(() => {
   return WebAssembly.compile(emptyModuleBinary).then(assert_Module);
 }, "Result type");
 
 promise_test(() => {
   return WebAssembly.compile(emptyModuleBinary, {}).then(assert_Module);
--- a/testing/web-platform/tests/wasm/jsapi/constructor/instantiate.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/constructor/instantiate.any.js
@@ -74,16 +74,21 @@ for (const [name, fn] of instanceTestFac
       verify(instance);
     });
   }, `${name}: Module argument`);
 }
 
 promise_test(t => {
   const buffer = new Uint8Array();
   return promise_rejects(t, new WebAssembly.CompileError(), WebAssembly.instantiate(buffer));
+}, "Empty buffer");
+
+promise_test(t => {
+  const buffer = new Uint8Array(Array.from(emptyModuleBinary).concat([0, 0]));
+  return promise_rejects(t, new WebAssembly.CompileError(), WebAssembly.instantiate(buffer));
 }, "Invalid code");
 
 promise_test(() => {
   const buffer = new Uint8Array(new WasmModuleBuilder().toBuffer());
   assert_equals(buffer[0], 0);
   const promise = WebAssembly.instantiate(buffer);
   buffer[0] = 1;
   return promise.then(assert_WebAssemblyInstantiatedSource);
--- a/testing/web-platform/tests/wasm/jsapi/module/constructor.any.js
+++ b/testing/web-platform/tests/wasm/jsapi/module/constructor.any.js
@@ -45,16 +45,21 @@ test(() => {
 }, "Invalid arguments");
 
 test(() => {
   const buffer = new Uint8Array();
   assert_throws(new WebAssembly.CompileError(), () => new WebAssembly.Module(buffer));
 }, "Empty buffer");
 
 test(() => {
+  const buffer = new Uint8Array(Array.from(emptyModuleBinary).concat([0, 0]));
+  assert_throws(new WebAssembly.CompileError(), () => new WebAssembly.Module(buffer));
+}, "Invalid code");
+
+test(() => {
   const module = new WebAssembly.Module(emptyModuleBinary);
   assert_equals(Object.getPrototypeOf(module), WebAssembly.Module.prototype);
 }, "Prototype");
 
 test(() => {
   const module = new WebAssembly.Module(emptyModuleBinary);
   assert_true(Object.isExtensible(module));
 }, "Extensibility");
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/wasm/webapi/invalid-code.any.js
@@ -0,0 +1,16 @@
+// META: global=window,worker
+// META: script=/wasm/jsapi/wasm-constants.js
+// META: script=/wasm/jsapi/wasm-module-builder.js
+
+let emptyModuleBinary;
+setup(() => {
+  emptyModuleBinary = new WasmModuleBuilder().toBuffer();
+});
+
+for (const method of ["compileStreaming", "instantiateStreaming"]) {
+  promise_test(t => {
+    const buffer = new Uint8Array(Array.from(emptyModuleBinary).concat([0, 0]));
+    const response = new Response(buffer, { headers: { "Content-Type": "application/wasm" } });
+    return promise_rejects(t, new WebAssembly.CompileError(), WebAssembly[method](response));
+  }, `Invalid code: ${method}`);
+}
--- a/toolkit/components/url-classifier/SafeBrowsing.jsm
+++ b/toolkit/components/url-classifier/SafeBrowsing.jsm
@@ -229,17 +229,18 @@ var SafeBrowsing = {
   readPrefs() {
     loggingEnabled = Services.prefs.getBoolPref(PREF_DEBUG_ENABLED);
     log("reading prefs");
 
     this.phishingEnabled = Services.prefs.getBoolPref("browser.safebrowsing.phishing.enabled");
     this.malwareEnabled = Services.prefs.getBoolPref("browser.safebrowsing.malware.enabled");
     this.downloadsEnabled = Services.prefs.getBoolPref("browser.safebrowsing.downloads.enabled");
     this.passwordsEnabled = Services.prefs.getBoolPref("browser.safebrowsing.passwords.enabled");
-    this.trackingEnabled = Services.prefs.getBoolPref("privacy.trackingprotection.enabled") ||
+    this.trackingEnabled = Services.prefs.getBoolPref("toolkit.telemetry.isGeckoViewMode", false) ||
+                           Services.prefs.getBoolPref("privacy.trackingprotection.enabled") ||
                            Services.prefs.getBoolPref("privacy.trackingprotection.pbmode.enabled");
     this.blockedEnabled = Services.prefs.getBoolPref("browser.safebrowsing.blockedURIs.enabled");
     this.trackingAnnotations = Services.prefs.getBoolPref("privacy.trackingprotection.annotate_channels");
     this.flashBlockEnabled = Services.prefs.getBoolPref("plugins.flashBlock.enabled");
     this.flashInfobarListEnabled = Services.prefs.getBoolPref("plugins.show_infobar", false);
 
     let flashAllowTable, flashAllowExceptTable, flashTable,
         flashExceptTable, flashSubDocTable,
--- a/toolkit/mozapps/extensions/content/extensions.css
+++ b/toolkit/mozapps/extensions/content/extensions.css
@@ -53,17 +53,16 @@ xhtml|link {
 }
 
 .detail-row {
   -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#detail-row");
 }
 
 .text-list {
   white-space: pre-line;
-  -moz-user-select: element;
 }
 
 row[unsupported="true"] {
   display: none;
 }
 
 #addonitem-popup > menuitem[disabled="true"] {
   display: none;
--- a/toolkit/recordreplay/ProcessRedirect.cpp
+++ b/toolkit/recordreplay/ProcessRedirect.cpp
@@ -463,18 +463,20 @@ MaybeInternalJumpTarget(uint8_t* aIpStar
     // determine the extent of a symbol's code on OSX. Use strstr to avoid
     // issues with goo in the symbol names.
     if ((strstr(startName, "CTRunGetGlyphs") &&
          !strstr(startName, "CTRunGetGlyphsPtr")) ||
         (strstr(startName, "CTRunGetPositions") &&
          !strstr(startName, "CTRunGetPositionsPtr")) ||
         (strstr(startName, "CTRunGetStringIndices") &&
          !strstr(startName, "CTRunGetStringIndicesPtr")) ||
-        strstr(startName, "CGColorSpaceCreateDeviceGray") ||
-        strstr(startName, "CGColorSpaceCreateDeviceRGB") ||
+        (strstr(startName, "CGColorSpaceCreateDeviceGray") &&
+         !strstr(startName, "CGColorSpaceCreateDeviceGray_block_invoke")) ||
+        (strstr(startName, "CGColorSpaceCreateDeviceRGB") &&
+         !strstr(startName, "CGColorSpaceCreateDeviceRGB_block_invoke")) ||
         // For these functions, there is a syscall near the beginning which
         // other system threads might be inside.
         strstr(startName, "__workq_kernreturn") ||
         strstr(startName, "kevent64")) {
       PrintRedirectSpew("Failed [%p]: Vetoed by annotation\n", aIpEnd - 1);
       return aIpEnd - 1;
     }
   }
--- a/toolkit/recordreplay/ProcessRedirectDarwin.cpp
+++ b/toolkit/recordreplay/ProcessRedirectDarwin.cpp
@@ -194,16 +194,17 @@ namespace recordreplay {
         nullptr, Preamble_PassThrough)                           \
   MACRO(mach_msg, RR_Compose<RR_ScalarRval, RR_WriteBuffer<0, 3>>, \
         nullptr, nullptr, Preamble_WaitForever)                  \
   MACRO(mach_timebase_info,                                      \
         RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<0, sizeof(mach_timebase_info_data_t)>>) \
   MACRO(mach_vm_allocate, nullptr, Preamble_mach_vm_allocate)    \
   MACRO(mach_vm_deallocate, nullptr, Preamble_mach_vm_deallocate) \
   MACRO(mach_vm_protect, nullptr, Preamble_mach_vm_protect)      \
+  MACRO(rand, RR_ScalarRval)                                     \
   MACRO(realpath,                                                \
         RR_SaveRvalHadErrorZero<RR_Compose<RR_CStringRval,       \
                                            RR_WriteOptionalBufferFixedSize<1, PATH_MAX>>>) \
   MACRO(realpath$DARWIN_EXTSN,                                   \
         RR_SaveRvalHadErrorZero<RR_Compose<RR_CStringRval,       \
                                            RR_WriteOptionalBufferFixedSize<1, PATH_MAX>>>) \
   /* By passing through events when initializing the sandbox, we ensure both */ \
   /* that we actually initialize the process sandbox while replaying as well as */ \