merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 02 Feb 2016 11:50:53 +0100
changeset 319000 5f9ba76eb3b1fd9377bbdb4cc2f98a7e75eabdfb
parent 318907 eb673021691c3c3257546995edf4731a1a7c165c (current diff)
parent 318999 39f872a217ff48786cfda71241a679b5d36e1408 (diff)
child 319009 e5f1b4782e380e1f2d48f77289819f26a0518e63
child 319063 8a6976312049b39e7bd9878635a94d2cce76f9e5
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone47.0a1
first release with
nightly linux32
5f9ba76eb3b1 / 47.0a1 / 20160202030232 / files
nightly linux64
5f9ba76eb3b1 / 47.0a1 / 20160202030232 / files
nightly mac
5f9ba76eb3b1 / 47.0a1 / 20160202030232 / files
nightly win32
5f9ba76eb3b1 / 47.0a1 / 20160202030232 / files
nightly win64
5f9ba76eb3b1 / 47.0a1 / 20160202030232 / 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
browser/base/content/browser.js
configure.in
dom/base/test/empty_worker.js
dom/base/test/test_performance_translate.html
dom/network/interfaces/nsIDOMNetworkStatsManager.idl
dom/payment/interfaces/nsINavigatorPayment.idl
mobile/android/config/mozconfigs/android-api-11/debug
mobile/android/config/mozconfigs/android-api-11/l10n-nightly
mobile/android/config/mozconfigs/android-api-11/l10n-release
mobile/android/config/mozconfigs/android-api-11/nightly
mobile/android/config/mozconfigs/android-api-11/release
python/mozbuild/mozbuild/artifacts.py
python/mozbuild/mozbuild/mach_commands.py
testing/docker/desktop-build/REGISTRY
testing/docker/desktop-build/VERSION
testing/docker/desktop-test/REGISTRY
testing/docker/desktop-test/VERSION
testing/specialpowers/content/MockPaymentsUIGlue.jsm
testing/web-platform/meta/cssom-view/elementsFromPoint.html.ini
--- a/accessible/base/NotificationController.h
+++ b/accessible/base/NotificationController.h
@@ -117,18 +117,25 @@ public:
    */
   void ScheduleChildDocBinding(DocAccessible* aDocument);
 
   /**
    * Schedule the accessible tree update because of rendered text changes.
    */
   inline void ScheduleTextUpdate(nsIContent* aTextNode)
   {
-    if (mTextHash.PutEntry(aTextNode))
-      ScheduleProcessing();
+    // Make sure we are not called with a node that is not in the DOM tree or
+    // not visible.
+    MOZ_ASSERT(aTextNode->GetParentNode(), "A text node is not in DOM");
+    MOZ_ASSERT(aTextNode->GetPrimaryFrame(), "A text node doesn't have a frame");
+    MOZ_ASSERT(aTextNode->GetPrimaryFrame()->StyleVisibility()->IsVisible(),
+               "A text node is not visible");
+
+    mTextHash.PutEntry(aTextNode);
+    ScheduleProcessing();
   }
 
   /**
    * Pend accessible tree update for content insertion.
    */
   void ScheduleContentInsertion(Accessible* aContainer,
                                 nsIContent* aStartChildNode,
                                 nsIContent* aEndChildNode);
--- a/browser/base/content/aboutNetError.xhtml
+++ b/browser/base/content/aboutNetError.xhtml
@@ -139,22 +139,16 @@
 
         if (allowOverride) {
           document.getElementById("overrideWeakCryptoPanel").style.display = "flex";
           var overrideLink = document.getElementById("overrideWeakCrypto");
           overrideLink.addEventListener("click", () => doOverride(overrideLink), false);
         }
       }
 
-      function sendErrorReport() {
-        var event = new CustomEvent("AboutNetErrorSendReport", {bubbles:true});
-
-        document.dispatchEvent(event);
-      }
-
       function initPage()
       {
         var err = getErrorCode();
 
         // if it's an unknown error or there's no title or description
         // defined, get the generic message
         var errTitle = document.getElementById("et_" + err);
         var errDesc  = document.getElementById("ed_" + err);
@@ -255,23 +249,17 @@
                 // set the checkbox
                 checkbox.checked = true;
               }
 
               checkbox.addEventListener('change', function(evt) {
                   var event = new CustomEvent("AboutNetErrorSetAutomatic",
                     {bubbles:true, detail:evt.target.checked});
                   document.dispatchEvent(event);
-                  if (evt.target.checked) {
-                    sendErrorReport();
-                  }
                 }, false);
-
-              var retryBtn = document.getElementById('reportCertificateErrorRetry');
-              retryBtn.addEventListener('click', sendErrorReport, false);
             }
           }
           if (getErrorCode() == "weakCryptoUsed" || getErrorCode() == "sslv3Used") {
             showAdvancedButton(getErrorCode() == "weakCryptoUsed");
           }
         }.bind(this), true, true);
 
         var event = new CustomEvent("AboutNetErrorLoad", {bubbles:true});
@@ -522,22 +510,16 @@
       </script>
 
       <!-- UI for option to report certificate errors to Mozilla. Removed on
            init for other error types .-->
       <div id="certificateErrorReporting">
         <p>
           <input type="checkbox" id="automaticallyReportInFuture" />
           <label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic2;</label>
-
-          <span id="reportingState">
-            <button id="reportCertificateErrorRetry">&errorReporting.tryAgain;</button>
-            <span id="reportSendingMessage">&errorReporting.sending;</span>
-            <span id="reportSentMessage">&errorReporting.sent;</span>
-          </span>
         </p>
       </div>
 
       <div id="weakCryptoAdvancedPanel">
         <div id="weakCryptoAdvancedDescription">
           <p>&weakCryptoAdvanced.longDesc;</p>
         </div>
         <div id="advancedLongDesc" />
--- a/browser/base/content/aboutcerterror/aboutCertError.xhtml
+++ b/browser/base/content/aboutcerterror/aboutCertError.xhtml
@@ -91,23 +91,16 @@
         var checkbox = document.getElementById("automaticallyReportInFuture");
         checkbox.addEventListener("change", function ({target: {checked}}) {
           document.dispatchEvent(new CustomEvent("AboutCertErrorSetAutomatic", {
             detail: checked,
             bubbles: true
           }));
         });
 
-        var retryBtn = document.getElementById("reportCertificateErrorRetry");
-        retryBtn.addEventListener("click", function () {
-          document.dispatchEvent(new CustomEvent("AboutCertErrorSendReport", {
-            bubbles: true
-          }));
-        });
-
         addEventListener("AboutCertErrorOptions", function (event) {
           var options = JSON.parse(event.detail);
           if (options && options.enabled) {
             // Display error reporting UI
             document.getElementById("certificateErrorReporting").style.display = "block";
 
             // set the checkbox
             checkbox.checked = !!options.automatic;
@@ -282,22 +275,16 @@
         </div>
       </div>
 
       <!-- UI for option to report certificate errors to Mozilla. -->
       <div id="certificateErrorReporting">
         <p>
           <input type="checkbox" id="automaticallyReportInFuture" />
           <label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic;</label>
-
-          <span id="reportingState">
-            <button id="reportCertificateErrorRetry">&errorReporting.tryAgain;</button>
-            <span id="reportSendingMessage">&errorReporting.sending;</span>
-            <span id="reportSentMessage">&errorReporting.sent;</span>
-          </span>
         </p>
       </div>
 
       <!-- Advanced panel, which is hidden by default -->
       <div id="advancedPanel" style="visibility: hidden;">
         <p id="technicalContentText"/>
         <button id="exceptionDialogButton">&certerror.addException.label;</button>
       </div>
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -106,60 +106,60 @@ var FullZoom = {
             break;
         }
         break;
     }
   },
 
   // nsIContentPrefObserver
 
-  onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue) {
-    this._onContentPrefChanged(aGroup, aValue);
+  onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue, aIsPrivate) {
+    this._onContentPrefChanged(aGroup, aValue, aIsPrivate);
   },
 
   onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName) {
     this._onContentPrefChanged(aGroup, undefined);
   },
 
   /**
    * Appropriately updates the zoom level after a content preference has
    * changed.
    *
    * @param aGroup  The group of the changed preference.
    * @param aValue  The new value of the changed preference.  Pass undefined to
    *                indicate the preference's removal.
    */
-  _onContentPrefChanged: function FullZoom__onContentPrefChanged(aGroup, aValue) {
+  _onContentPrefChanged: function FullZoom__onContentPrefChanged(aGroup, aValue, aIsPrivate) {
     if (this._isNextContentPrefChangeInternal) {
       // Ignore changes that FullZoom itself makes.  This works because the
       // content pref service calls callbacks before notifying observers, and it
       // does both in the same turn of the event loop.
       delete this._isNextContentPrefChangeInternal;
       return;
     }
 
     let browser = gBrowser.selectedBrowser;
     if (!browser.currentURI)
       return;
 
+    let ctxt = this._loadContextFromBrowser(browser);
     let domain = this._cps2.extractDomain(browser.currentURI.spec);
     if (aGroup) {
-      if (aGroup == domain)
+      if (aGroup == domain && ctxt.usePrivateBrowsing == aIsPrivate)
         this._applyPrefToZoom(aValue, browser);
       return;
     }
 
     this._globalValue = aValue === undefined ? aValue :
                           this._ensureValid(aValue);
 
     // If the current page doesn't have a site-specific preference, then its
     // zoom should be set to the new global preference now that the global
     // preference has changed.
     let hasPref = false;
-    let ctxt = this._loadContextFromBrowser(browser);
     let token = this._getBrowserToken(browser);
     this._cps2.getByDomainAndName(browser.currentURI.spec, this.name, ctxt, {
       handleResult: function () { hasPref = true; },
       handleCompletion: function () {
         if (!hasPref && token.isCurrent)
           this._applyPrefToZoom(undefined, browser);
       }.bind(this)
     });
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2711,110 +2711,33 @@ var BrowserOnClick = {
       break;
       case "Browser:SSLErrorGoBack":
         goBackFromErrorPage();
       break;
     }
   },
 
   onSSLErrorReport: function(browser, documentURI, location, securityInfo) {
-    function showReportStatus(reportStatus) {
-      gBrowser.selectedBrowser
-          .messageManager
-          .sendAsyncMessage("Browser:SSLErrorReportStatus",
-                            {
-                              reportStatus: reportStatus,
-                              documentURI: documentURI
-                            });
-    }
-
     if (!Services.prefs.getBoolPref("security.ssl.errorReporting.enabled")) {
-      showReportStatus("error");
       Cu.reportError("User requested certificate error report sending, but certificate error reporting is disabled");
       return;
     }
 
-    let bin = TLS_ERROR_REPORT_TELEMETRY_MANUAL_SEND;
-    if (Services.prefs.getBoolPref("security.ssl.errorReporting.automatic")) {
-      bin = TLS_ERROR_REPORT_TELEMETRY_AUTO_SEND;
-    }
-    Services.telemetry.getHistogramById("TLS_ERROR_REPORT_UI").add(bin);
-
     let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
                            .getService(Ci.nsISerializationHelper);
     let transportSecurityInfo = serhelper.deserializeObject(securityInfo);
     transportSecurityInfo.QueryInterface(Ci.nsITransportSecurityInfo)
 
-    showReportStatus("activity");
-
-    /*
-     * Requested info for the report:
-     * - Domain of bad connection
-     * - Error type (e.g. Pinning, domain mismatch, etc)
-     * - Cert chain (at minimum, same data to distrust each cert in the
-     *   chain)
-     * - Request data (e.g. User Agent, IP, Timestamp)
-     *
-     * The request data should be added to the report by the receiving server.
-     */
-
-    // Convert the nsIX509CertList into a format that can be parsed into
-    // JSON
-    let asciiCertChain = [];
-
-    if (transportSecurityInfo.failedCertChain) {
-      let certs = transportSecurityInfo.failedCertChain.getEnumerator();
-      while (certs.hasMoreElements()) {
-        let cert = certs.getNext();
-        cert.QueryInterface(Ci.nsIX509Cert);
-        asciiCertChain.push(btoa(getDERString(cert)));
-      }
-    }
-
-    let report = {
-      hostname: location.hostname,
-      port: location.port,
-      timestamp: Math.round(Date.now() / 1000),
-      errorCode: transportSecurityInfo.errorCode,
-      failedCertChain: asciiCertChain,
-      userAgent: window.navigator.userAgent,
-      version: 1,
-      build: gAppInfo.appBuildID,
-      product: gAppInfo.name,
-      channel: UpdateUtils.UpdateChannel
-    }
-
-    let reportURL = Services.prefs.getCharPref("security.ssl.errorReporting.url");
-
-    let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
-        .createInstance(Ci.nsIXMLHttpRequest);
-    try {
-      xhr.open("POST", reportURL);
-    } catch (e) {
-      Cu.reportError("xhr.open exception", e);
-      showReportStatus("error");
-    }
-
-    xhr.onerror = function (e) {
-      // error making request to reportURL
-      Cu.reportError("xhr onerror", e);
-      showReportStatus("error");
-    };
-
-    xhr.onload = function (event) {
-      if (xhr.status !== 201 && xhr.status !== 0) {
-        // request returned non-success status
-        Cu.reportError("xhr returned failure code", xhr.status);
-        showReportStatus("error");
-      } else {
-        showReportStatus("complete");
-      }
-    };
-
-    xhr.send(JSON.stringify(report));
+    let errorReporter = Cc["@mozilla.org/securityreporter;1"]
+                          .getService(Ci.nsISecurityReporter);
+    // if location.port is the empty string, set to -1 (for consistency with
+    // port values from nsIURI)
+    let port = location.port === "" ? -1 : location.port;
+    errorReporter.reportTLSError(transportSecurityInfo,
+                                 location.hostname, port);
   },
 
   onAboutCertError: function (browser, elementId, isTopFrame, location, securityInfoAsString) {
     let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
 
     switch (elementId) {
       case "exceptionDialogButton":
         if (isTopFrame) {
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -205,20 +205,18 @@ Cc["@mozilla.org/eventlistenerservice;1"
 const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0;
 const TLS_ERROR_REPORT_TELEMETRY_EXPANDED = 1;
 const TLS_ERROR_REPORT_TELEMETRY_SUCCESS  = 6;
 const TLS_ERROR_REPORT_TELEMETRY_FAILURE  = 7;
 
 var AboutCertErrorListener = {
   init(chromeGlobal) {
     addMessageListener("AboutCertErrorDetails", this);
-    addMessageListener("Browser:SSLErrorReportStatus", this);
     chromeGlobal.addEventListener("AboutCertErrorLoad", this, false, true);
     chromeGlobal.addEventListener("AboutCertErrorSetAutomatic", this, false, true);
-    chromeGlobal.addEventListener("AboutCertErrorSendReport", this, false, true);
   },
 
   get isAboutCertError() {
     return content.document.documentURI.startsWith("about:certerror");
   },
 
   handleEvent(event) {
     if (!this.isAboutCertError) {
@@ -227,134 +225,90 @@ var AboutCertErrorListener = {
 
     switch (event.type) {
       case "AboutCertErrorLoad":
         this.onLoad(event);
         break;
       case "AboutCertErrorSetAutomatic":
         this.onSetAutomatic(event);
         break;
-      case "AboutCertErrorSendReport":
-        this.onSendReport();
-        break;
     }
   },
 
   receiveMessage(msg) {
     if (!this.isAboutCertError) {
       return;
     }
 
     switch (msg.name) {
       case "AboutCertErrorDetails":
         this.onDetails(msg);
         break;
-      case "Browser:SSLErrorReportStatus":
-        this.onReportStatus(msg);
-        break;
     }
   },
 
   onLoad(event) {
     let originalTarget = event.originalTarget;
     let ownerDoc = originalTarget.ownerDocument;
     ClickEventHandler.onAboutCertError(originalTarget, ownerDoc);
 
+    // Set up the TLS Error Reporting UI - reports are sent automatically
+    // (from nsHttpChannel::OnStopRequest) if the user has previously enabled
+    // automatic sending of reports. The UI ensures that a report is sent
+    // for the certificate error currently displayed if the user enables it
+    // here.
     let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
     content.dispatchEvent(new content.CustomEvent("AboutCertErrorOptions", {
       detail: JSON.stringify({
         enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
         automatic,
       })
     }));
-
-    if (automatic) {
-      this.onSendReport();
-    }
   },
 
   onDetails(msg) {
     let div = content.document.getElementById("certificateErrorText");
     div.textContent = msg.data.info;
   },
 
   onSetAutomatic(event) {
-    if (event.detail) {
-      this.onSendReport();
-    }
-
     sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
       automatic: event.detail
     });
-  },
-
-  onSendReport() {
-    let doc = content.document;
-    let location = doc.location.href;
-
-    let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
-                     .getService(Ci.nsISerializationHelper);
-
-    let serializable =  docShell.failedChannel.securityInfo
-                                .QueryInterface(Ci.nsITransportSecurityInfo)
-                                .QueryInterface(Ci.nsISerializable);
 
-    let serializedSecurityInfo = serhelper.serializeToString(serializable);
+    // if we're enabling reports, send a report for this failure
+    if (event.detail) {
+      let doc = content.document;
+      let location = doc.location.href;
 
-    sendAsyncMessage("Browser:SendSSLErrorReport", {
-      documentURI: doc.documentURI,
-      location: {hostname: doc.location.hostname, port: doc.location.port},
-      securityInfo: serializedSecurityInfo
-    });
-  },
-
-  onReportStatus(msg) {
-    let doc = content.document;
-    if (doc.documentURI != msg.data.documentURI) {
-      return;
-    }
+      let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
+          .getService(Ci.nsISerializationHelper);
 
-    let reportSendingMsg = doc.getElementById("reportSendingMessage");
-    let reportSentMsg = doc.getElementById("reportSentMessage");
-    let retryBtn = doc.getElementById("reportCertificateErrorRetry");
+      let serializable =  docShell.failedChannel.securityInfo
+          .QueryInterface(Ci.nsITransportSecurityInfo)
+          .QueryInterface(Ci.nsISerializable);
+
+      let serializedSecurityInfo = serhelper.serializeToString(serializable);
 
-    switch (msg.data.reportStatus) {
-      case "activity":
-        // Hide the button that was just clicked
-        retryBtn.style.removeProperty("display");
-        reportSentMsg.style.removeProperty("display");
-        reportSendingMsg.style.display = "block";
-        break;
-      case "error":
-        // show the retry button
-        retryBtn.style.display = "block";
-        reportSendingMsg.style.removeProperty("display");
-        sendAsyncMessage("Browser:SSLErrorReportTelemetry",
-                         {reportStatus: TLS_ERROR_REPORT_TELEMETRY_FAILURE});
-        break;
-      case "complete":
-        // Show a success indicator
-        reportSentMsg.style.display = "block";
-        reportSendingMsg.style.removeProperty("display");
-        sendAsyncMessage("Browser:SSLErrorReportTelemetry",
-                         {reportStatus: TLS_ERROR_REPORT_TELEMETRY_SUCCESS});
-        break;
+      sendAsyncMessage("Browser:SendSSLErrorReport", {
+        documentURI: doc.documentURI,
+        location: {hostname: doc.location.hostname, port: doc.location.port},
+        securityInfo: serializedSecurityInfo
+      });
     }
-  }
+  },
 };
 
 AboutCertErrorListener.init(this);
 
 
 var AboutNetErrorListener = {
   init: function(chromeGlobal) {
     chromeGlobal.addEventListener('AboutNetErrorLoad', this, false, true);
     chromeGlobal.addEventListener('AboutNetErrorSetAutomatic', this, false, true);
-    chromeGlobal.addEventListener('AboutNetErrorSendReport', this, false, true);
-    chromeGlobal.addEventListener('AboutNetErrorUIExpanded', this, false, true);
     chromeGlobal.addEventListener('AboutNetErrorOverride', this, false, true);
   },
 
   get isAboutNetError() {
     return content.document.documentURI.startsWith("about:neterror");
   },
 
   handleEvent: function(aEvent) {
@@ -364,117 +318,65 @@ var AboutNetErrorListener = {
 
     switch (aEvent.type) {
     case "AboutNetErrorLoad":
       this.onPageLoad(aEvent);
       break;
     case "AboutNetErrorSetAutomatic":
       this.onSetAutomatic(aEvent);
       break;
-    case "AboutNetErrorSendReport":
-      this.onSendReport(aEvent);
-      break;
-    case "AboutNetErrorUIExpanded":
-      sendAsyncMessage("Browser:SSLErrorReportTelemetry",
-                       {reportStatus: TLS_ERROR_REPORT_TELEMETRY_EXPANDED});
-      break;
     case "AboutNetErrorOverride":
       this.onOverride(aEvent);
       break;
     }
   },
 
   onPageLoad: function(evt) {
     let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
     content.dispatchEvent(new content.CustomEvent("AboutNetErrorOptions", {
-            detail: JSON.stringify({
-              enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
-            automatic: automatic
-            })
-          }
-    ));
+      detail: JSON.stringify({
+        enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
+        automatic: automatic
+      })
+    }));
 
     sendAsyncMessage("Browser:SSLErrorReportTelemetry",
                      {reportStatus: TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN});
-
-    if (automatic) {
-      this.onSendReport(evt);
-    }
-    // hide parts of the UI we don't need yet
-    let contentDoc = content.document;
-
-    let reportSendingMsg = contentDoc.getElementById("reportSendingMessage");
-    let reportSentMsg = contentDoc.getElementById("reportSentMessage");
-    let retryBtn = contentDoc.getElementById("reportCertificateErrorRetry");
-    reportSendingMsg.style.display = "none";
-    reportSentMsg.style.display = "none";
-    retryBtn.style.display = "none";
   },
 
   onSetAutomatic: function(evt) {
     sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
-        automatic: evt.detail
-      });
-  },
-
-  onSendReport: function(evt) {
-    let contentDoc = content.document;
-
-    let reportSendingMsg = contentDoc.getElementById("reportSendingMessage");
-    let reportSentMsg = contentDoc.getElementById("reportSentMessage");
-    let retryBtn = contentDoc.getElementById("reportCertificateErrorRetry");
-
-    addMessageListener("Browser:SSLErrorReportStatus", function(message) {
-      // show and hide bits - but only if this is a message for the right
-      // document - we'll compare on document URI
-      if (contentDoc.documentURI === message.data.documentURI) {
-        switch(message.data.reportStatus) {
-        case "activity":
-          // Hide the button that was just clicked
-          retryBtn.style.display = "none";
-          reportSentMsg.style.display = "none";
-          reportSendingMsg.style.removeProperty("display");
-          break;
-        case "error":
-          // show the retry button
-          retryBtn.style.removeProperty("display");
-          reportSendingMsg.style.display = "none";
-          sendAsyncMessage("Browser:SSLErrorReportTelemetry",
-                           {reportStatus: TLS_ERROR_REPORT_TELEMETRY_FAILURE});
-          break;
-        case "complete":
-          // Show a success indicator
-          reportSentMsg.style.removeProperty("display");
-          reportSendingMsg.style.display = "none";
-          sendAsyncMessage("Browser:SSLErrorReportTelemetry",
-                           {reportStatus: TLS_ERROR_REPORT_TELEMETRY_SUCCESS});
-          break;
-        }
-      }
+      automatic: evt.detail
     });
 
-    let location = contentDoc.location.href;
+    // if we're enabling reports, send a report for this failure
+    if (evt.detail) {
+      let contentDoc = content.document;
+
+      let location = contentDoc.location.href;
 
-    let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
-                      .getService(Ci.nsISerializationHelper);
+      let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
+                        .getService(Ci.nsISerializationHelper);
 
-    let serializable = docShell.failedChannel.securityInfo
-                               .QueryInterface(Ci.nsITransportSecurityInfo)
-                               .QueryInterface(Ci.nsISerializable);
+      let serializable = docShell.failedChannel.securityInfo
+          .QueryInterface(Ci.nsITransportSecurityInfo)
+          .QueryInterface(Ci.nsISerializable);
 
-    let serializedSecurityInfo = serhelper.serializeToString(serializable);
+      let serializedSecurityInfo = serhelper.serializeToString(serializable);
 
-    sendAsyncMessage("Browser:SendSSLErrorReport", {
-      documentURI: contentDoc.documentURI,
-      location: {
-        hostname: contentDoc.location.hostname,
-        port: contentDoc.location.port
-      },
-      securityInfo: serializedSecurityInfo
-    });
+      sendAsyncMessage("Browser:SendSSLErrorReport", {
+        documentURI: contentDoc.documentURI,
+        location: {
+          hostname: contentDoc.location.hostname,
+          port: contentDoc.location.port
+        },
+        securityInfo: serializedSecurityInfo
+      });
+
+    }
   },
 
   onOverride: function(evt) {
     let contentDoc = content.document;
     let location = contentDoc.location;
 
     sendAsyncMessage("Browser:OverrideWeakCrypto", {
       documentURI: contentDoc.documentURI,
--- a/browser/base/content/test/general/browser_ssl_error_reports.js
+++ b/browser/base/content/test/general/browser_ssl_error_reports.js
@@ -23,23 +23,22 @@ function cleanup() {
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
   cleanup();
 });
 
 add_task(function* test_send_report_neterror() {
   yield testSendReportAutomatically(URL_BAD_CHAIN, "succeed", "neterror");
   yield testSendReportAutomatically(URL_NO_CERT, "nocert", "neterror");
-  yield testSendReportFailRetry(URL_NO_CERT, "nocert", "neterror");
   yield testSetAutomatic(URL_NO_CERT, "nocert", "neterror");
 });
 
+
 add_task(function* test_send_report_certerror() {
   yield testSendReportAutomatically(URL_BAD_CERT, "badcert", "certerror");
-  yield testSendReportFailRetry(URL_BAD_CERT, "badcert", "certerror");
   yield testSetAutomatic(URL_BAD_CERT, "badcert", "certerror");
 });
 
 add_task(function* test_send_disabled() {
   Services.prefs.setBoolPref(PREF_REPORT_ENABLED, false);
   Services.prefs.setBoolPref(PREF_REPORT_AUTOMATIC, true);
   Services.prefs.setCharPref(PREF_REPORT_URL, "https://example.com/invalid");
 
@@ -60,78 +59,55 @@ function* testSendReportAutomatically(te
   Services.prefs.setBoolPref(PREF_REPORT_AUTOMATIC, true);
   Services.prefs.setCharPref(PREF_REPORT_URL, URL_REPORTS + suffix);
 
   // Add a tab and wait until it's loaded.
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
   let browser = tab.linkedBrowser;
 
   // Load the page and wait for the error report submission.
-  let promiseReport = createErrorReportPromise(browser);
+  let promiseStatus = createReportResponseStatusPromise(URL_REPORTS + suffix);
   browser.loadURI(testURL);
-  yield promiseReport;
-  ok(true, "SSL error report submitted successfully");
+
+  ok(!isErrorStatus(yield promiseStatus),
+     "SSL error report submitted successfully");
 
   // Check that we loaded the right error page.
   yield checkErrorPage(browser, errorURISuffix);
 
   // Cleanup.
   gBrowser.removeTab(tab);
   cleanup();
 };
 
-function* testSendReportFailRetry(testURL, suffix, errorURISuffix) {
-  try {
-    yield testSendReportAutomatically(testURL, "error", errorURISuffix);
-    ok(false, "sending a report should have failed");
-  } catch (err) {
-    ok(err, "saw a failure notification");
-  }
-
-  Services.prefs.setCharPref(PREF_REPORT_URL, URL_REPORTS + suffix);
-
-  let browser = gBrowser.selectedBrowser;
-  let promiseReport = createErrorReportPromise(browser);
-  let promiseRetry = ContentTask.spawn(browser, null, function* () {
-    content.document.getElementById("reportCertificateErrorRetry").click();
-  });
-
-  yield Promise.all([promiseReport, promiseRetry]);
-  ok(true, "SSL error report submitted successfully");
-
-  // Cleanup.
-  gBrowser.removeCurrentTab();
-  cleanup();
-}
-
 function* testSetAutomatic(testURL, suffix, errorURISuffix) {
   Services.prefs.setBoolPref(PREF_REPORT_ENABLED, true);
   Services.prefs.setBoolPref(PREF_REPORT_AUTOMATIC, false);
   Services.prefs.setCharPref(PREF_REPORT_URL, URL_REPORTS + suffix);
 
   // Add a tab and wait until it's loaded.
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
   let browser = tab.linkedBrowser;
 
   // Load the page.
   browser.loadURI(testURL);
   yield promiseErrorPageLoaded(browser);
 
   // Check that we loaded the right error page.
   yield checkErrorPage(browser, errorURISuffix);
 
+  let statusPromise = createReportResponseStatusPromise(URL_REPORTS + suffix);
+
   // Click the checkbox, enable automatic error reports.
-  let promiseReport = createErrorReportPromise(browser);
   yield ContentTask.spawn(browser, null, function* () {
     content.document.getElementById("automaticallyReportInFuture").click();
   });
 
   // Wait for the error report submission.
-  yield promiseReport;
-  ok(true, "SSL error report submitted successfully");
+  yield statusPromise;
 
   let isAutomaticReportingEnabled = () =>
     Services.prefs.getBoolPref(PREF_REPORT_AUTOMATIC);
 
   // Check that the pref was flipped.
   ok(isAutomaticReportingEnabled(), "automatic SSL report submission enabled");
 
   // Disable automatic error reports.
@@ -165,42 +141,32 @@ function* testSendReportDisabled(testURL
     return content.getComputedStyle(section).display == "none";
   });
   ok(hidden, "error reporting section should be hidden");
 
   // Cleanup.
   gBrowser.removeTab(tab);
 }
 
-function createErrorReportPromise(browser) {
-  return ContentTask.spawn(browser, null, function* () {
-    let type = "Browser:SSLErrorReportStatus";
-    let active = false;
+function isErrorStatus(status) {
+  return status < 200 || status >= 300;
+}
 
-    yield new Promise((resolve, reject) => {
-      addMessageListener(type, function onReportStatus(message) {
-        switch (message.data.reportStatus) {
-          case "activity":
-            active = true;
-            break;
-          case "complete":
-            removeMessageListener(type, onReportStatus);
-            if (active) {
-              resolve(message.data.reportStatus);
-            } else {
-              reject("activity should be seen before success");
-            }
-            break;
-          case "error":
-            removeMessageListener(type, onReportStatus);
-            reject("sending the report failed");
-            break;
-        }
-      });
-    });
+// use the observer service to see when a report is sent
+function createReportResponseStatusPromise(expectedURI) {
+  return new Promise(resolve => {
+    let observer = (subject, topic, data) => {
+      subject.QueryInterface(Ci.nsIHttpChannel);
+      let requestURI = subject.URI.spec;
+      if (requestURI == expectedURI) {
+        Services.obs.removeObserver(observer, "http-on-examine-response");
+        resolve(subject.responseStatus);
+      }
+    };
+    Services.obs.addObserver(observer, "http-on-examine-response", false);
   });
 }
 
 function promiseErrorPageLoaded(browser) {
   return new Promise(resolve => {
     browser.addEventListener("DOMContentLoaded", function onLoad() {
       browser.removeEventListener("DOMContentLoaded", onLoad, false, true);
       resolve();
--- a/browser/base/content/test/general/ssl_error_reports.sjs
+++ b/browser/base/content/test/general/ssl_error_reports.sjs
@@ -80,12 +80,12 @@ function handleRequest(request, response
       response.write("<html>OK</html>");
       break;
     case "error":
       response.setStatusLine("1.1", 500, "Server error");
       response.write("<html>server error</html>");
       break;
     default:
       response.setStatusLine("1.1", 500, "Server error");
-      response.write("<html>succeed, nocert or error expected</html>");
+      response.write("<html>succeed, nocert or error expected (got " + request.queryString + ")</html>");
       break;
   }
 }
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/linux64/source
@@ -0,0 +1,4 @@
+# The source "build" only needs a mozconfig because we use the build system as
+# our script for generating it. This allows us to run configure without any
+# extra dependencies on specific toolchains, e.g. gtk3.
+ac_add_options --disable-compile-environment
--- a/browser/locales/en-US/chrome/browser/aboutCertError.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutCertError.dtd
@@ -31,11 +31,8 @@ can tell &brandShortName; to start trust
 <b>Even if you trust the site, this error could mean that someone is
 tampering with your connection.</b>">
 <!ENTITY certerror.expert.contentPara2 "Don't add an exception unless
 you know there's a good reason why this site doesn't use trusted identification.">
 <!ENTITY certerror.addException.label "Add Exception…">
 <!ENTITY certerror.copyToClipboard.label "Copy text to clipboard">
 
 <!ENTITY errorReporting.automatic "Report errors like this to help Mozilla identify misconfigured sites">
-<!ENTITY errorReporting.sending "Sending report">
-<!ENTITY errorReporting.sent "Report sent">
-<!ENTITY errorReporting.tryAgain "Try again">
--- a/browser/locales/en-US/chrome/overrides/netError.dtd
+++ b/browser/locales/en-US/chrome/overrides/netError.dtd
@@ -201,19 +201,16 @@ functionality specific to firefox. -->
 <p>You should not add an exception if you are using an internet connection that you do not trust completely or if you are not used to seeing a warning for this server.</p>
 
 <button id='getMeOutOfHereButton'>&securityOverride.getMeOutOfHereButton;</button>
 <button id='exceptionDialogButton'>&securityOverride.exceptionButtonLabel;</button>
 ">
 
 <!ENTITY errorReporting.automatic2 "Report errors like this to help Mozilla identify and block malicious sites">
 <!ENTITY errorReporting.learnMore "Learn more…">
-<!ENTITY errorReporting.sending "Sending report">
-<!ENTITY errorReporting.sent "Report sent">
-<!ENTITY errorReporting.tryAgain "Try again">
 
 <!ENTITY remoteXUL.title "Remote XUL">
 <!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
 
 <!ENTITY sslv3Used.title "Unable to Connect Securely">
 <!-- LOCALIZATION NOTE (sslv3Used.longDesc2) - Do not translate
      "SSL_ERROR_UNSUPPORTED_VERSION". -->
 <!ENTITY sslv3Used.longDesc2 "Advanced info: SSL_ERROR_UNSUPPORTED_VERSION">
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -2,16 +2,19 @@
 /* vim: set ts=2 sw=2 et tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/BasePrincipal.h"
 
 #include "nsDocShell.h"
+#ifdef MOZ_CRASHREPORTER
+#include "nsExceptionHandler.h"
+#endif
 #include "nsIAddonPolicyService.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 
 #include "nsPrincipal.h"
 #include "nsNetUtil.h"
 #include "nsIURIWithPrincipal.h"
@@ -116,17 +119,23 @@ OriginAttributes::CreateSuffix(nsACStrin
     params->Set(NS_LITERAL_STRING("appId"), value);
   }
 
   if (mInBrowser) {
     params->Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1"));
   }
 
   if (!mAddonId.IsEmpty()) {
-    MOZ_RELEASE_ASSERT(mAddonId.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound);
+    if (mAddonId.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) != kNotFound) {
+#ifdef MOZ_CRASHREPORTER
+      CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Crash_AddonId"),
+                                         NS_ConvertUTF16toUTF8(mAddonId));
+#endif
+      MOZ_CRASH();
+    }
     params->Set(NS_LITERAL_STRING("addonId"), mAddonId);
   }
 
   if (mUserContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) {
     value.Truncate();
     value.AppendInt(mUserContextId);
     params->Set(NS_LITERAL_STRING("userContextId"), value);
   }
--- a/caps/moz.build
+++ b/caps/moz.build
@@ -27,18 +27,23 @@ EXPORTS += [
     'nsNullPrincipal.h',
     'nsNullPrincipalURI.h',
 ]
 
 EXPORTS.mozilla = [
     'BasePrincipal.h'
 ]
 
+SOURCES += [
+    # Compile this separately since nsExceptionHandler.h conflicts
+    # with something from nsNullPrincipal.cpp.
+    'BasePrincipal.cpp',
+]
+
 UNIFIED_SOURCES += [
-    'BasePrincipal.cpp',
     'DomainPolicy.cpp',
     'nsJSPrincipals.cpp',
     'nsNullPrincipal.cpp',
     'nsNullPrincipalURI.cpp',
     'nsPrincipal.cpp',
     'nsScriptSecurityManager.cpp',
     'nsSystemPrincipal.cpp',
 ]
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -22,16 +22,17 @@
 #include "mozilla/BasePrincipal.h"
 #include "nsSystemPrincipal.h"
 #include "nsPrincipal.h"
 #include "nsNullPrincipal.h"
 #include "DomainPolicy.h"
 #include "nsXPIDLString.h"
 #include "nsCRT.h"
 #include "nsCRTGlue.h"
+#include "nsDocShell.h"
 #include "nsError.h"
 #include "nsDOMCID.h"
 #include "nsIXPConnect.h"
 #include "nsTextFormatter.h"
 #include "nsIStringBundle.h"
 #include "nsNetUtil.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIProperties.h"
--- a/configure.in
+++ b/configure.in
@@ -525,17 +525,17 @@ case "$target" in
         AC_DEFINE(_CRT_NONSTDC_NO_WARNINGS)
         AC_DEFINE(_USE_MATH_DEFINES) # Otherwise MSVC's math.h doesn't #define M_PI.
 
         if test "$_CC_MAJOR_VERSION" = "18" -a "$_CC_BUILD_VERSION" -ge "30723"; then
             _CC_SUITE=12
             MSVS_VERSION=2013
             MSVC_C_RUNTIME_DLL=msvcr120.dll
             MSVC_CXX_RUNTIME_DLL=msvcp120.dll
-        elif test "$_CC_MAJOR_VERSION" = "19"; then
+        elif test "$_CC_MAJOR_VERSION" = "19" -a "$_CC_BUILD_VERSION" -ge "23506"; then
             _CC_SUITE=14
             MSVS_VERSION=2015
             MSVC_C_RUNTIME_DLL=vcruntime140.dll
             MSVC_CXX_RUNTIME_DLL=msvcp140.dll
             MSVC_APPCRT_DLL=appcrt140.dll
             MSVC_DESKTOPCRT_DLL=desktopcrt140.dll
 
             # -Wv:18 disables all warnings introduced after VS2013
@@ -552,17 +552,17 @@ case "$target" in
 
             # https://connect.microsoft.com/VisualStudio/feedback/details/888527/warnings-on-dbghelp-h
             # for dbghelp.h, imagehlp.h, and shobj.h
             # C4091: 'typedef ': ignored on left of '' when no variable is declared
             CFLAGS="$CFLAGS -wd4091"
             CXXFLAGS="$CXXFLAGS -wd4091"
         else
             AC_MSG_ERROR([This version (${_CC_MAJOR_VERSION}.${_CC_MINOR_VERSION}.${_CC_BUILD_VERSION}) of the MSVC compiler is unsupported.
-You must install Visual C++ 2013 Update 3 or newer in order to build.
+You must install Visual C++ 2013 Update 3, Visual C++ 2015 Update 1, or newer in order to build.
 See https://developer.mozilla.org/en/Windows_Build_Prerequisites.])
         fi
         AC_SUBST(MSVS_VERSION)
         AC_SUBST(MSVC_C_RUNTIME_DLL)
         AC_SUBST(MSVC_CXX_RUNTIME_DLL)
         AC_SUBST(MSVC_APPCRT_DLL)
         AC_SUBST(MSVC_DESKTOPCRT_DLL)
 
--- a/docshell/test/browser/browser.ini
+++ b/docshell/test/browser/browser.ini
@@ -67,17 +67,16 @@ support-files =
 [browser_bug441169.js]
 skip-if = buildapp == 'mulet'
 [browser_bug503832.js]
 skip-if = buildapp == 'mulet'
 [browser_bug554155.js]
 [browser_bug655270.js]
 [browser_bug655273.js]
 [browser_bug670318.js]
-skip-if = (os == 'mac' && debug) # Bug 1241704
 [browser_bug673467.js]
 [browser_bug852909.js]
 [browser_bug92473.js]
 [browser_uriFixupIntegration.js]
 [browser_loadDisallowInherit.js]
 [browser_loadURI.js]
 [browser_multiple_pushState.js]
 [browser_onbeforeunload_navigation.js]
--- a/docshell/test/browser/browser_bug670318.js
+++ b/docshell/test/browser/browser_bug670318.js
@@ -9,17 +9,17 @@
  */
 
 const URL = "http://mochi.test:8888/browser/docshell/test/browser/file_bug670318.html";
 
 add_task(function* test() {
   yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" },
                                     function* (browser) {
     yield ContentTask.spawn(browser, URL, function* (URL) {
-      let history = docShell.sessionHistory;
+      let history = docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory;
       let count = 0;
 
       let testDone = {};
       testDone.promise = new Promise(resolve => { testDone.resolve = resolve; });
 
       let listener = {
         OnHistoryNewEntry: function (aNewURI) {
           if (aNewURI.spec == URL && 5 == ++count) {
--- a/dom/archivereader/ArchiveZipEvent.cpp
+++ b/dom/archivereader/ArchiveZipEvent.cpp
@@ -5,16 +5,19 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ArchiveZipEvent.h"
 #include "ArchiveZipFile.h"
 
 #include "nsContentUtils.h"
 #include "nsCExternalHandlerService.h"
 
+#include "mozilla/UniquePtr.h"
+
+using namespace mozilla;
 using namespace mozilla::dom;
 
 USING_ARCHIVEREADER_NAMESPACE
 
 #ifndef PATH_MAX
 #  define PATH_MAX 65536 // The filename length is stored in 2 bytes
 #endif
 
@@ -186,27 +189,28 @@ ArchiveReaderZipEvent::Exec()
 
     // Point to the next item at the top of loop
     centralOffset += ZIPCENTRAL_SIZE + filenameLen + extraLen + commentLen;
     if (filenameLen == 0 || filenameLen >= PATH_MAX || centralOffset >= size) {
       return RunShare(NS_ERROR_FILE_CORRUPTED);
     }
 
     // Read the name:
-    nsAutoArrayPtr<char> filename(new char[filenameLen + 1]);
-    rv = inputStream->Read(filename, filenameLen, &ret);
+    auto filename = MakeUnique<char[]>(filenameLen + 1);
+    rv = inputStream->Read(filename.get(), filenameLen, &ret);
     if (NS_FAILED(rv) || ret != filenameLen) {
       return RunShare(NS_ERROR_UNEXPECTED);
     }
 
     filename[filenameLen] = 0;
 
     // We ignore the directories:
     if (filename[filenameLen - 1] != '/') {
-      mFileList.AppendElement(new ArchiveZipItem(filename, centralStruct, mEncoding));
+      mFileList.AppendElement(new ArchiveZipItem(filename.get(), centralStruct,
+                                                 mEncoding));
     }
 
     // Ignore the rest
     seekableStream->Seek(nsISeekableStream::NS_SEEK_CUR, extraLen + commentLen);
   }
 
   return RunShare(NS_OK);
 }
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -123,16 +123,21 @@
 #include "mozilla/EMEUtils.h"
 #include "mozilla/DetailedPromise.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include <cutils/properties.h>
 #endif
 
+#ifdef MOZ_PAY
+#include "nsIPaymentContentHelperService.h"
+#include "mozilla/dom/DOMRequest.h"
+#endif
+
 namespace mozilla {
 namespace dom {
 
 static bool sDoNotTrackEnabled = false;
 static bool sVibratorEnabled   = false;
 static uint32_t sMaxVibrateMS  = 0;
 static uint32_t sMaxVibrateListLen = 0;
 
@@ -2667,16 +2672,46 @@ Navigator::IsE10sEnabled(JSContext* aCx,
 
 bool
 Navigator::MozE10sEnabled()
 {
   // This will only be called if IsE10sEnabled() is true.
   return true;
 }
 
+#ifdef MOZ_PAY
+already_AddRefed<DOMRequest>
+Navigator::MozPay(JSContext* aCx,
+                  JS::Handle<JS::Value> aJwts,
+                  ErrorResult& aRv)
+{
+  if (!mWindow || !mWindow->GetDocShell()) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  nsresult rv;
+  nsCOMPtr<nsIPaymentContentHelperService> service =
+    do_GetService("@mozilla.org/payment/content-helper-service;1", &rv);
+  if (!service) {
+    aRv.Throw(rv);
+    return nullptr;
+  }
+
+  RefPtr<nsIDOMDOMRequest> request;
+  rv = service->Pay(mWindow, aJwts, getter_AddRefs(request));
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return nullptr;
+  }
+
+  return request.forget().downcast<DOMRequest>();
+}
+#endif // MOZ_PAY
+
 /* static */
 already_AddRefed<nsPIDOMWindowInner>
 Navigator::GetWindowFromGlobal(JSObject* aGlobal)
 {
   nsCOMPtr<nsPIDOMWindowInner> win =
     do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(aGlobal));
   MOZ_ASSERT(!win || win->IsInnerWindow());
   return win.forget();
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -37,16 +37,17 @@ namespace dom {
 class Geolocation;
 class systemMessageCallback;
 class MediaDevices;
 struct MediaStreamConstraints;
 class WakeLock;
 class ArrayBufferViewOrBlobOrStringOrFormData;
 struct MobileIdOptions;
 class ServiceWorkerContainer;
+class DOMRequest;
 } // namespace dom
 } // namespace mozilla
 
 //*****************************************************************************
 // Navigator: Script "navigator" object
 //*****************************************************************************
 
 namespace mozilla {
@@ -310,16 +311,22 @@ public:
   // If in doubt, return true.
   static bool MayResolve(jsid aId);
   void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
                            ErrorResult& aRv);
   void GetLanguages(nsTArray<nsString>& aLanguages);
 
   bool MozE10sEnabled();
 
+#ifdef MOZ_PAY
+  already_AddRefed<DOMRequest> MozPay(JSContext* aCx,
+                                      JS::Handle<JS::Value> aJwts,
+                                      ErrorResult& aRv);
+#endif // MOZ_PAY
+
   static void GetAcceptLanguages(nsTArray<nsString>& aLanguages);
 
   // WebIDL helper methods
   static bool HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */);
   static bool HasCameraSupport(JSContext* /* unused */,
                                JSObject* aGlobal);
   static bool HasWifiManagerSupport(JSContext* /* unused */,
                                   JSObject* aGlobal);
--- a/dom/base/WebKitCSSMatrix.cpp
+++ b/dom/base/WebKitCSSMatrix.cpp
@@ -3,16 +3,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/WebKitCSSMatrix.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/WebKitCSSMatrixBinding.h"
+#include "nsCSSParser.h"
+#include "nsStyleTransformMatrix.h"
 
 namespace mozilla {
 namespace dom {
 
 static const double sRadPerDegree = 2.0 * M_PI / 360.0;
 
 bool
 WebKitCSSMatrix::FeatureEnabled(JSContext* aCx, JSObject* aObj)
@@ -51,21 +53,68 @@ WebKitCSSMatrix::WrapObject(JSContext* a
 {
   return WebKitCSSMatrixBinding::Wrap(aCx, this, aGivenProto);
 }
 
 WebKitCSSMatrix*
 WebKitCSSMatrix::SetMatrixValue(const nsAString& aTransformList,
                                 ErrorResult& aRv)
 {
-  DOMMatrix::SetMatrixValue(aTransformList, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
+  // An empty string is a no-op.
+  if (aTransformList.IsEmpty()) {
+    return this;
+  }
+
+  nsCSSValue value;
+  nsCSSParser parser;
+  bool parseSuccess = parser.ParseTransformProperty(aTransformList,
+                                                    true,
+                                                    value);
+  if (!parseSuccess) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return nullptr;
   }
 
+  // A value of "none" results in a 2D identity matrix.
+  if (value.GetUnit() == eCSSUnit_None) {
+    mMatrix3D = nullptr;
+    mMatrix2D = new gfx::Matrix();
+    return this;
+  }
+
+  // A value other than a transform-list is a syntax error.
+  if (value.GetUnit() != eCSSUnit_SharedList) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return nullptr;
+  }
+
+  RuleNodeCacheConditions dummy;
+  nsStyleTransformMatrix::TransformReferenceBox dummyBox;
+  bool contains3dTransform = false;
+  gfx::Matrix4x4 transform = nsStyleTransformMatrix::ReadTransforms(
+                               value.GetSharedListValue()->mHead,
+                               nullptr, nullptr, dummy, dummyBox,
+                               nsPresContext::AppUnitsPerCSSPixel(),
+                               &contains3dTransform);
+
+  if (!contains3dTransform) {
+    mMatrix3D = nullptr;
+    mMatrix2D = new gfx::Matrix();
+
+    SetA(transform._11);
+    SetB(transform._12);
+    SetC(transform._21);
+    SetD(transform._22);
+    SetE(transform._41);
+    SetF(transform._42);
+  } else {
+    mMatrix3D = new gfx::Matrix4x4(transform);
+    mMatrix2D = nullptr;
+  }
+
   return this;
 }
 
 already_AddRefed<WebKitCSSMatrix>
 WebKitCSSMatrix::Multiply(const WebKitCSSMatrix& other) const
 {
   RefPtr<WebKitCSSMatrix> retval = new WebKitCSSMatrix(mParent, *this);
   retval->MultiplySelf(other);
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3277,58 +3277,108 @@ nsDocument::ElementFromPoint(float aX, f
 }
 
 Element*
 nsIDocument::ElementFromPoint(float aX, float aY)
 {
   return ElementFromPointHelper(aX, aY, false, true);
 }
 
+void
+nsIDocument::ElementsFromPoint(float aX, float aY,
+                               nsTArray<RefPtr<Element>>& aElements)
+{
+  ElementsFromPointHelper(aX, aY, nsIDocument::FLUSH_LAYOUT, aElements);
+}
+
 Element*
 nsDocument::ElementFromPointHelper(float aX, float aY,
                                    bool aIgnoreRootScrollFrame,
                                    bool aFlushLayout)
 {
+  nsAutoTArray<RefPtr<Element>, 1> elementArray;
+  ElementsFromPointHelper(aX, aY,
+                          ((aIgnoreRootScrollFrame ? nsIDocument::IGNORE_ROOT_SCROLL_FRAME : 0) |
+                           (aFlushLayout ? nsIDocument::FLUSH_LAYOUT : 0) |
+                           nsIDocument::IS_ELEMENT_FROM_POINT),
+                          elementArray);
+  if (elementArray.IsEmpty()) {
+    return nullptr;
+  }
+  return elementArray[0];
+}
+
+void
+nsDocument::ElementsFromPointHelper(float aX, float aY,
+                                    uint32_t aFlags,
+                                    nsTArray<RefPtr<mozilla::dom::Element>>& aElements)
+{
   // As per the the spec, we return null if either coord is negative
-  if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0)) {
-    return nullptr;
+  if (!(aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) && (aX < 0 || aY < 0)) {
+    return;
   }
 
   nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
   nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
   nsPoint pt(x, y);
 
   // Make sure the layout information we get is up-to-date, and
   // ensure we get a root frame (for everything but XUL)
-  if (aFlushLayout)
+  if (aFlags & nsIDocument::FLUSH_LAYOUT) {
     FlushPendingNotifications(Flush_Layout);
+  }
 
   nsIPresShell *ps = GetShell();
   if (!ps) {
-    return nullptr;
+    return;
   }
   nsIFrame *rootFrame = ps->GetRootFrame();
 
   // XUL docs, unlike HTML, have no frame tree until everything's done loading
   if (!rootFrame) {
-    return nullptr; // return null to premature XUL callers as a reminder to wait
-  }
-
-  nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt,
+    return; // return null to premature XUL callers as a reminder to wait
+  }
+
+  nsTArray<nsIFrame*> outFrames;
+  // Emulate what GetFrameAtPoint does, since we want all the frames under our
+  // point.
+  nsLayoutUtils::GetFramesForArea(rootFrame, nsRect(pt, nsSize(1, 1)), outFrames,
     nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC |
-    (aIgnoreRootScrollFrame ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0));
-  if (!ptFrame) {
-    return nullptr;
-  }
-
-  nsIContent* elem = GetContentInThisDocument(ptFrame);
-  if (elem && !elem->IsElement()) {
-    elem = elem->GetParent();
-  }
-  return elem ? elem->AsElement() : nullptr;
+    ((aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0));
+
+  // Dunno when this would ever happen, as we should at least have a root frame under us?
+  if (outFrames.IsEmpty()) {
+    return;
+  }
+
+  // Used to filter out repeated elements in sequence.
+  nsIContent* lastAdded = nullptr;
+
+  for (uint32_t i = 0; i < outFrames.Length(); i++) {
+    nsIContent* node = GetContentInThisDocument(outFrames[i]);
+
+    if (!node || !node->IsElement()) {
+      // If this helper is called via ElementsFromPoint, we need to make sure
+      // our frame is an element. Otherwise return whatever the top frame is
+      // even if it isn't the top-painted element.
+      if (!(aFlags & nsIDocument::IS_ELEMENT_FROM_POINT)) {
+        continue;
+      }
+      node = node->GetParent();
+    }
+    if (node && node != lastAdded) {
+      aElements.AppendElement(node->AsElement());
+      lastAdded = node;
+      // If this helper is called via ElementFromPoint, just return the first
+      // element we find.
+      if (aFlags & nsIDocument::IS_ELEMENT_FROM_POINT) {
+        return;
+      }
+    }
+  }
 }
 
 nsresult
 nsDocument::NodesFromRectHelper(float aX, float aY,
                                 float aTopSize, float aRightSize,
                                 float aBottomSize, float aLeftSize,
                                 bool aIgnoreRootScrollFrame,
                                 bool aFlushLayout,
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1026,18 +1026,22 @@ public:
                   mozilla::ErrorResult& aRv) override;
 
   virtual Element*
     GetAnonymousElementByAttribute(nsIContent* aElement,
                                    nsIAtom* aAttrName,
                                    const nsAString& aAttrValue) const override;
 
   virtual Element* ElementFromPointHelper(float aX, float aY,
-                                                      bool aIgnoreRootScrollFrame,
-                                                      bool aFlushLayout) override;
+                                          bool aIgnoreRootScrollFrame,
+                                          bool aFlushLayout) override;
+
+  virtual void ElementsFromPointHelper(float aX, float aY,
+                                       uint32_t aFlags,
+                                       nsTArray<RefPtr<mozilla::dom::Element>>& aElements) override;
 
   virtual nsresult NodesFromRectHelper(float aX, float aY,
                                                    float aTopSize, float aRightSize,
                                                    float aBottomSize, float aLeftSize,
                                                    bool aIgnoreRootScrollFrame,
                                                    bool aFlushLayout,
                                                    nsIDOMNodeList** aReturn) override;
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2335,29 +2335,32 @@ CreateNativeGlobalForInner(JSContext* aC
   // no one creates one accidentally.
   nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(aPrincipal);
   MOZ_RELEASE_ASSERT(!nsEP, "DOMWindow with nsEP is not supported");
 
   nsGlobalWindow *top = nullptr;
   if (aNewInner->GetOuterWindow()) {
     top = aNewInner->GetTopInternal();
   }
+
   JS::CompartmentOptions options;
 
   // Sometimes add-ons load their own XUL windows, either as separate top-level
   // windows or inside a browser element. In such cases we want to tag the
   // window's compartment with the add-on ID. See bug 1092156.
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     options.creationOptions().setAddonId(MapURIToAddonID(aURI));
   }
 
   if (top && top->GetGlobalJSObject()) {
     options.creationOptions().setSameZoneAs(top->GetGlobalJSObject());
   }
 
+  xpc::InitGlobalObjectOptions(options, aPrincipal);
+
   // Determine if we need the Components object.
   bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
                         TreatAsRemoteXUL(aPrincipal);
   uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
   flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
 
   if (!WindowBinding::Wrap(aCx, aNewInner, aNewInner, options,
                            nsJSPrincipals::get(aPrincipal), false, aGlobal) ||
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -1664,16 +1664,26 @@ public:
    * ignoring the scroll frame and/or avoiding layout flushes.
    *
    * @see nsIDOMWindowUtils::elementFromPoint
    */
   virtual Element* ElementFromPointHelper(float aX, float aY,
                                           bool aIgnoreRootScrollFrame,
                                           bool aFlushLayout) = 0;
 
+  enum ElementsFromPointFlags {
+    IGNORE_ROOT_SCROLL_FRAME = 1,
+    FLUSH_LAYOUT = 2,
+    IS_ELEMENT_FROM_POINT = 4
+  };
+
+  virtual void ElementsFromPointHelper(float aX, float aY,
+                                       uint32_t aFlags,
+                                       nsTArray<RefPtr<mozilla::dom::Element>>& aElements) = 0;
+
   virtual nsresult NodesFromRectHelper(float aX, float aY,
                                        float aTopSize, float aRightSize,
                                        float aBottomSize, float aLeftSize,
                                        bool aIgnoreRootScrollFrame,
                                        bool aFlushLayout,
                                        nsIDOMNodeList** aReturn) = 0;
 
   /**
@@ -2526,16 +2536,19 @@ public:
   virtual mozilla::dom::StyleSheetList* StyleSheets() = 0;
   void GetSelectedStyleSheetSet(nsAString& aSheetSet);
   virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) = 0;
   virtual void GetLastStyleSheetSet(nsString& aSheetSet) = 0;
   void GetPreferredStyleSheetSet(nsAString& aSheetSet);
   virtual mozilla::dom::DOMStringList* StyleSheetSets() = 0;
   virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) = 0;
   Element* ElementFromPoint(float aX, float aY);
+  void ElementsFromPoint(float aX,
+                         float aY,
+                         nsTArray<RefPtr<mozilla::dom::Element>>& aElements);
 
   /**
    * Retrieve the location of the caret position (DOM node and character
    * offset within that node), given a point.
    *
    * @param aX Horizontal point at which to determine the caret position, in
    *           page coordinates.
    * @param aY Vertical point at which to determine the caret position, in
--- a/dom/base/nsPerformance.cpp
+++ b/dom/base/nsPerformance.cpp
@@ -6,17 +6,16 @@
 
 #include "nsPerformance.h"
 #include "nsCOMPtr.h"
 #include "nsIHttpChannel.h"
 #include "nsITimedChannel.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
-#include "nsGlobalWindow.h"
 #include "nsIDOMWindow.h"
 #include "nsILoadInfo.h"
 #include "nsIURI.h"
 #include "nsThreadUtils.h"
 #include "PerformanceEntry.h"
 #include "PerformanceMark.h"
 #include "PerformanceMeasure.h"
 #include "PerformanceObserver.h"
@@ -25,18 +24,16 @@
 #include "mozilla/dom/PerformanceBinding.h"
 #include "mozilla/dom/PerformanceEntryEvent.h"
 #include "mozilla/dom/PerformanceTimingBinding.h"
 #include "mozilla/dom/PerformanceNavigationBinding.h"
 #include "mozilla/dom/PerformanceObserverBinding.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/TimeStamp.h"
-#include "SharedWorker.h"
-#include "ServiceWorker.h"
 #include "js/HeapAPI.h"
 #include "GeckoProfiler.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 
 #ifdef MOZ_WIDGET_GONK
 #define PERFLOG(msg, ...)  __android_log_print(ANDROID_LOG_INFO, "PerformanceTiming", msg, ##__VA_ARGS__)
 #else
@@ -914,47 +911,16 @@ PerformanceBase::ClearUserEntries(const 
 void
 PerformanceBase::ClearResourceTimings()
 {
   MOZ_ASSERT(NS_IsMainThread());
   mResourceEntries.Clear();
 }
 
 DOMHighResTimeStamp
-PerformanceBase::TranslateTime(DOMHighResTimeStamp aTime,
-                               const WindowOrWorkerOrSharedWorkerOrServiceWorker& aTimeSource,
-                               ErrorResult& aRv)
-{
-  TimeStamp otherCreationTimeStamp;
-
-  if (aTimeSource.IsWindow()) {
-    RefPtr<nsPerformance> performance = aTimeSource.GetAsWindow().GetPerformance();
-    if (NS_WARN_IF(!performance)) {
-      aRv.Throw(NS_ERROR_FAILURE);
-    }
-    otherCreationTimeStamp = performance->CreationTimeStamp();
-  } else if (aTimeSource.IsWorker()) {
-    otherCreationTimeStamp = aTimeSource.GetAsWorker().CreationTimeStamp();
-  } else if (aTimeSource.IsSharedWorker()) {
-    SharedWorker& sharedWorker = aTimeSource.GetAsSharedWorker();
-    WorkerPrivate* workerPrivate = sharedWorker.GetWorkerPrivate();
-    otherCreationTimeStamp = workerPrivate->CreationTimeStamp();
-  } else if (aTimeSource.IsServiceWorker()) {
-    ServiceWorker& serviceWorker = aTimeSource.GetAsServiceWorker();
-    WorkerPrivate* workerPrivate = serviceWorker.GetWorkerPrivate();
-    otherCreationTimeStamp = workerPrivate->CreationTimeStamp();
-  } else {
-    MOZ_CRASH("This should not be possible.");
-  }
-
-  return RoundTime(
-    aTime + (otherCreationTimeStamp - CreationTimeStamp()).ToMilliseconds());
-}
-
-DOMHighResTimeStamp
 PerformanceBase::RoundTime(double aTime) const
 {
   // Round down to the nearest 5us, because if the timer is too accurate people
   // can do nasty timing attacks with it.  See similar code in the worker
   // Performance implementation.
   const double maxResolutionMs = 0.005;
   return floor(aTime / maxResolutionMs) * maxResolutionMs;
 }
--- a/dom/base/nsPerformance.h
+++ b/dom/base/nsPerformance.h
@@ -25,17 +25,16 @@ class nsIHttpChannel;
 namespace mozilla {
 
 class ErrorResult;
 
 namespace dom {
 
 class PerformanceEntry;
 class PerformanceObserver;
-class WindowOrWorkerOrSharedWorkerOrServiceWorker;
 
 } // namespace dom
 } // namespace mozilla
 
 // Script "performance.timing" object
 class nsPerformanceTiming final : public nsWrapperCache
 {
 public:
@@ -313,21 +312,16 @@ public:
                         nsTArray<RefPtr<PerformanceEntry>>& aRetval);
   void GetEntriesByName(const nsAString& aName,
                         const mozilla::dom::Optional<nsAString>& aEntryType,
                         nsTArray<RefPtr<PerformanceEntry>>& aRetval);
   void ClearResourceTimings();
 
   virtual DOMHighResTimeStamp Now() const = 0;
 
-  DOMHighResTimeStamp
-  TranslateTime(DOMHighResTimeStamp aTime,
-                const mozilla::dom::WindowOrWorkerOrSharedWorkerOrServiceWorker& aTimeSource,
-                mozilla::ErrorResult& aRv);
-
   void Mark(const nsAString& aName, mozilla::ErrorResult& aRv);
   void ClearMarks(const mozilla::dom::Optional<nsAString>& aName);
   void Measure(const nsAString& aName,
                const mozilla::dom::Optional<nsAString>& aStartMark,
                const mozilla::dom::Optional<nsAString>& aEndMark,
                mozilla::ErrorResult& aRv);
   void ClearMeasures(const mozilla::dom::Optional<nsAString>& aName);
 
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -3798,18 +3798,18 @@ ArrayBufferBuilder::getArrayBuffer(JSCon
 {
   if (mMapPtr) {
     JSObject* obj = JS_NewMappedArrayBufferWithContents(aCx, mLength, mMapPtr);
     if (!obj) {
       JS_ReleaseMappedArrayBufferContents(mMapPtr, mLength);
     }
     mMapPtr = nullptr;
 
-    // The memory-mapped contents will be released when obj been finalized(GCed
-    // or neutered).
+    // The memory-mapped contents will be released when the ArrayBuffer becomes
+    // detached or is GC'd.
     return obj;
   }
 
   // we need to check for mLength == 0, because nothing may have been
   // added
   if (mCapacity > mLength || mLength == 0) {
     if (!setCapacity(mLength)) {
       return nullptr;
deleted file mode 100644
--- a/dom/base/test/empty_worker.js
+++ /dev/null
@@ -1,1 +0,0 @@
-/* nothing here */
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -252,17 +252,16 @@ support-files =
   script_postmessages_fileList.js
   iframe_postMessages.html
   test_performance_observer.js
   performance_observer.html
   test_anonymousContent_style_csp.html^headers^
   file_explicit_user_agent.sjs
   referrer_change_server.sjs
   file_change_policy_redirect.html
-  empty_worker.js
   file_bug1198095.js
 
 [test_anonymousContent_api.html]
 [test_anonymousContent_append_after_reflow.html]
 [test_anonymousContent_canvas.html]
 skip-if = buildapp == 'b2g' # Requires webgl support
 [test_anonymousContent_insert.html]
 [test_anonymousContent_manipulate_content.html]
@@ -863,12 +862,11 @@ skip-if = buildapp == 'b2g'
 support-files = worker_postMessages.js
 [test_window_proto.html]
 [test_frameLoader_switchProcess.html]
 skip-if = e10s || os != 'linux' || buildapp != 'browser'
 [test_explicit_user_agent.html]
 [test_change_policy.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_document.all_iteration.html]
-[test_performance_translate.html]
 [test_bug1198095.html]
 [test_bug1187157.html]
 [test_bug769117.html]
deleted file mode 100644
--- a/dom/base/test/test_performance_translate.html
+++ /dev/null
@@ -1,75 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-  <head>
-    <title>Test for performance.translate()</title>
-    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
-    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-    <script type="text/javascript" src="test_performance_user_timing.js"></script>
-  </head>
-  <body>
-    <pre id="test">
-      <script class="testbody" type="text/javascript">
-function testBasic() {
-  ok("translateTime" in performance, "Performance.translateTime exists.");
-  try {
-    performance.translateTime(0, null);
-    ok(false, "Wrong use of performance.translateTime.");
-  } catch(e) {
-    ok(true, "Wrong use of performance.translateTime.");
-  }
-
-  next();
-}
-
-function testWindow() {
-  is(performance.translateTime(42, this), 42, "translating time with the same window.");
-
-  var now = performance.now();
-
-  var ifr = document.createElement('iframe');
-  ifr.src = 'file_empty.html';
-  document.body.appendChild(ifr);
-
-  ifr.onload = function() {
-    var a = performance.translateTime(0, ifr.contentWindow);
-    ok (a >= now, "Time has been translated from a window that started loading later than we did");
-    next();
-  }
-}
-
-function testWorker() {
-  var now = performance.now();
-
-  var w = new Worker('empty_worker.js');
-  var a = performance.translateTime(0, w);
-  // bug 1226147
-  ok (a >= now, "Time has been translated from a Worker that started loading later than we did");
-  next();
-}
-
-function testSharedWorker() {
-  var now = performance.now();
-
-  var w = new SharedWorker('empty_worker.js');
-  var a = performance.translateTime(0, w);
-  ok (a >= now, "Time has been translated from a SharedWorker that started loading later than we did");
-  next();
-}
-
-var tests = [ testBasic, testWindow, testWorker, testSharedWorker ];
-function next() {
-  if (!tests.length) {
-    SimpleTest.finish();
-    return;
-  }
-
-  var test = tests.shift();
-  test();
-}
-
-SimpleTest.waitForExplicitFinish();
-addLoadEvent(next);
-      </script>
-    </pre>
-  </body>
-</html>
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3018,16 +3018,21 @@ struct CreateGlobalOptions<nsGlobalWindo
   static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
 };
 
 nsresult
 RegisterDOMNames();
 
 // The return value is whatever the ProtoHandleGetter we used
 // returned.  This should be the DOM prototype for the global.
+//
+// Typically this method's caller will want to ensure that
+// xpc::InitGlobalObjectOptions is called before, and xpc::InitGlobalObject is
+// called after, this method, to ensure that this global object and its
+// compartment are consistent with other global objects.
 template <class T, ProtoHandleGetter GetProto>
 JS::Handle<JSObject*>
 CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
              const JSClass* aClass, JS::CompartmentOptions& aOptions,
              JSPrincipals* aPrincipal, bool aInitStandardClasses,
              JS::MutableHandle<JSObject*> aGlobal)
 {
   aOptions.creationOptions().setTrace(CreateGlobalOptions<T>::TraceGlobal);
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -2268,28 +2268,27 @@ nsGonkCameraControl::CreatePoster(Image*
     NS_IMETHODIMP Run() override
     {
 #ifdef MOZ_WIDGET_GONK
       // NV21 (yuv420sp) is 12 bits / pixel
       size_t srcLength = (mWidth * mHeight * 3 + 1) / 2;
 
       // ARGB is 32 bits / pixel
       size_t tmpLength = mWidth * mHeight * sizeof(uint32_t);
-      nsAutoArrayPtr<uint8_t> tmp;
-      tmp = new uint8_t[tmpLength];
+      UniquePtr<uint8_t[]> tmp = MakeUnique<uint8_t[]>(tmpLength);
 
       GrallocImage* nativeImage = static_cast<GrallocImage*>(mImage.get());
       android::sp<GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
 
       void* graphicSrc = nullptr;
       graphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_MASK, &graphicSrc);
 
       uint32_t stride = mWidth * 4;
       int err = libyuv::ConvertToARGB(static_cast<uint8_t*>(graphicSrc),
-                                      srcLength, tmp, stride, 0, 0,
+                                      srcLength, tmp.get(), stride, 0, 0,
                                       mWidth, mHeight, mWidth, mHeight,
                                       libyuv::kRotate0, libyuv::FOURCC_NV21);
 
       graphicBuffer->unlock();
       graphicSrc = nullptr;
       graphicBuffer.clear();
       nativeImage = nullptr;
       mImage = nullptr;
@@ -2302,17 +2301,17 @@ nsGonkCameraControl::CreatePoster(Image*
       nsCOMPtr<imgIEncoder> encoder =
         do_CreateInstance("@mozilla.org/image/encoder;2?type=image/jpeg");
       if (NS_WARN_IF(!encoder)) {
         DOM_CAMERA_LOGE("CreatePoster: no JPEG encoder\n");
         return NS_OK;
       }
 
       nsString opt;
-      nsresult rv = encoder->InitFromData(tmp, tmpLength, mWidth,
+      nsresult rv = encoder->InitFromData(tmp.get(), tmpLength, mWidth,
                                           mHeight, stride,
                                           imgIEncoder::INPUT_FORMAT_HOSTARGB,
                                           opt);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         DOM_CAMERA_LOGE("CreatePoster: encoder init failed (0x%x)\n",
                         rv);
         return NS_OK;
       }
--- a/dom/encoding/TextDecoder.cpp
+++ b/dom/encoding/TextDecoder.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/TextDecoder.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/UnionTypes.h"
+#include "mozilla/UniquePtrExtensions.h"
 #include "nsContentUtils.h"
 #include <stdint.h>
 
 namespace mozilla {
 namespace dom {
 
 static const char16_t kReplacementChar = static_cast<char16_t>(0xFFFD);
 
@@ -60,28 +61,28 @@ TextDecoder::Decode(const char* aInput, 
   int32_t outLen;
   nsresult rv = mDecoder->GetMaxLength(aInput, aLength, &outLen);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
   // Need a fallible allocator because the caller may be a content
   // and the content can specify the length of the string.
-  nsAutoArrayPtr<char16_t> buf(new (fallible) char16_t[outLen + 1]);
+  auto buf = MakeUniqueFallible<char16_t[]>(outLen + 1);
   if (!buf) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   int32_t length = aLength;
-  rv = mDecoder->Convert(aInput, &length, buf, &outLen);
+  rv = mDecoder->Convert(aInput, &length, buf.get(), &outLen);
   MOZ_ASSERT(mFatal || rv != NS_ERROR_ILLEGAL_INPUT);
   buf[outLen] = 0;
 
-  if (!aOutDecodedString.Append(buf, outLen, fallible)) {
+  if (!aOutDecodedString.Append(buf.get(), outLen, fallible)) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   // If the internal streaming flag of the decoder object is not set,
   // then reset the encoding algorithm state to the default values
   if (!aStream) {
     mDecoder->Reset();
--- a/dom/encoding/TextEncoder.cpp
+++ b/dom/encoding/TextEncoder.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/TextEncoder.h"
 #include "mozilla/dom/EncodingUtils.h"
+#include "mozilla/UniquePtrExtensions.h"
 #include "nsContentUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 void
 TextEncoder::Init(const nsAString& aEncoding, ErrorResult& aRv)
 {
@@ -49,28 +50,28 @@ TextEncoder::Encode(JSContext* aCx,
   const char16_t* data = aString.BeginReading();
   nsresult rv = mEncoder->GetMaxLength(data, srcLen, &maxLen);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
   // Need a fallible allocator because the caller may be a content
   // and the content can specify the length of the string.
-  nsAutoArrayPtr<char> buf(new (fallible) char[maxLen + 1]);
+  auto buf = MakeUniqueFallible<char[]>(maxLen + 1);
   if (!buf) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   int32_t dstLen = maxLen;
-  rv = mEncoder->Convert(data, &srcLen, buf, &dstLen);
+  rv = mEncoder->Convert(data, &srcLen, buf.get(), &dstLen);
 
   // Now reset the encoding algorithm state to the default values for encoding.
   int32_t finishLen = maxLen - dstLen;
-  rv = mEncoder->Finish(buf + dstLen, &finishLen);
+  rv = mEncoder->Finish(&buf[dstLen], &finishLen);
   if (NS_SUCCEEDED(rv)) {
     dstLen += finishLen;
   }
 
   JSObject* outView = nullptr;
   if (NS_SUCCEEDED(rv)) {
     buf[dstLen] = '\0';
     JSAutoCompartment ac(aCx, aObj);
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -1102,17 +1102,17 @@ Event::TimeStamp() const
   // For dedicated workers, we should make times relative to the navigation
   // start of the document that created the worker, which is the same as the
   // timebase for performance.now().
   workers::WorkerPrivate* workerPrivate =
     workers::GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(workerPrivate);
 
   TimeDuration duration =
-    mEvent->timeStamp - workerPrivate->CreationTimeStamp();
+    mEvent->timeStamp - workerPrivate->NowBaseTimeStamp();
   return duration.ToMilliseconds();
 }
 
 bool
 Event::GetPreventDefault() const
 {
   nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(mOwner));
   if (win) {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2001,16 +2001,17 @@ EventStateManager::GetContentViewer(nsIC
 {
   *aCv = nullptr;
 
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if(!fm) return NS_ERROR_FAILURE;
 
   nsCOMPtr<mozIDOMWindowProxy> focusedWindow;
   fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
+  if (!focusedWindow) return NS_ERROR_FAILURE;
 
   auto* ourWindow = nsPIDOMWindowOuter::From(focusedWindow);
 
   nsCOMPtr<nsPIDOMWindowOuter> rootWindow = ourWindow->GetPrivateRoot();
   if(!rootWindow) return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsPIDOMWindowOuter> contentWindow = nsGlobalWindow::Cast(rootWindow)->GetContent();
   if(!contentWindow) return NS_ERROR_FAILURE;
--- a/dom/events/test/test_eventTimeStamp.html
+++ b/dom/events/test/test_eventTimeStamp.html
@@ -69,19 +69,18 @@ function testRegularEvents() {
 }
 
 function testWorkerEvents() {
   var blob = new Blob([ document.getElementById("worker-src").textContent ],
                       { type: "text/javascript" });
   var worker = new Worker(window.URL.createObjectURL(blob));
   worker.onmessage = function(evt) {
     var timeAfterEvent = window.performance.now();
-    var time = window.performance.translateTime(evt.data, worker);
-    ok(time >= timeBeforeEvent &&
-       time <= timeAfterEvent,
+    ok(evt.data > timeBeforeEvent &&
+       evt.data < timeAfterEvent,
        "Event timestamp in dedicated worker (" + evt.data +
          ") is in expected range: (" +
          timeBeforeEvent + ", " + timeAfterEvent + ")");
     worker.terminate();
     testSharedWorkerEvents();
   };
   var timeBeforeEvent = window.performance.now();
   worker.postMessage("");
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -245,25 +245,23 @@ Directory::GetPath(nsAString& aRetval) c
   } else {
     aRetval = mPath;
   }
 }
 
 already_AddRefed<Promise>
 Directory::GetFilesAndDirectories()
 {
-  nsresult error = NS_OK;
-  nsString realPath;
   ErrorResult rv;
   RefPtr<GetDirectoryListingTask> task =
     new GetDirectoryListingTask(mFileSystem, mPath, mFilters, rv);
   if (NS_WARN_IF(rv.Failed())) {
     return nullptr;
   }
-  task->SetError(error);
+
   FileSystemPermissionRequest::RequestForTask(task);
   return task->GetPromise();
 }
 
 void
 Directory::SetContentFilters(const nsAString& aFilters)
 {
   mFilters = aFilters;
--- a/dom/html/HTMLFrameSetElement.cpp
+++ b/dom/html/HTMLFrameSetElement.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "HTMLFrameSetElement.h"
 #include "mozilla/dom/HTMLFrameSetElementBinding.h"
 #include "mozilla/dom/EventHandlerBinding.h"
 #include "nsGlobalWindow.h"
+#include "mozilla/UniquePtrExtensions.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(FrameSet)
 
 namespace mozilla {
 namespace dom {
 
 HTMLFrameSetElement::~HTMLFrameSetElement()
 {
@@ -76,25 +77,25 @@ HTMLFrameSetElement::SetAttr(int32_t aNa
    *  we want to reflow.  So we set mCurrentRowColHint here, then call
    *  nsGenericHTMLElement::SetAttr, which will end up calling
    *  GetAttributeChangeHint and notifying layout with that hint.
    *  Once nsGenericHTMLElement::SetAttr returns, we want to go back to our
    *  normal hint, which is NS_STYLE_HINT_REFLOW.
    */
   if (aAttribute == nsGkAtoms::rows && aNameSpaceID == kNameSpaceID_None) {
     int32_t oldRows = mNumRows;
-    ParseRowCol(aValue, mNumRows, getter_Transfers(mRowSpecs));
+    ParseRowCol(aValue, mNumRows, &mRowSpecs);
     
     if (mNumRows != oldRows) {
       mCurrentRowColHint = NS_STYLE_HINT_FRAMECHANGE;
     }
   } else if (aAttribute == nsGkAtoms::cols &&
              aNameSpaceID == kNameSpaceID_None) {
     int32_t oldCols = mNumCols;
-    ParseRowCol(aValue, mNumCols, getter_Transfers(mColSpecs));
+    ParseRowCol(aValue, mNumCols, &mColSpecs);
 
     if (mNumCols != oldCols) {
       mCurrentRowColHint = NS_STYLE_HINT_FRAMECHANGE;
     }
   }
   
   rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aAttribute, aPrefix,
                                      aValue, aNotify);
@@ -111,29 +112,29 @@ HTMLFrameSetElement::GetRowSpec(int32_t 
   NS_PRECONDITION(aSpecs, "Must have a pointer to an array of nsFramesetSpecs");
   *aNumValues = 0;
   *aSpecs = nullptr;
   
   if (!mRowSpecs) {
     const nsAttrValue* value = GetParsedAttr(nsGkAtoms::rows);
     if (value && value->Type() == nsAttrValue::eString) {
       nsresult rv = ParseRowCol(value->GetStringValue(), mNumRows,
-                                getter_Transfers(mRowSpecs));
+                                &mRowSpecs);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if (!mRowSpecs) {  // we may not have had an attr or had an empty attr
-      mRowSpecs = new nsFramesetSpec[1];
+      mRowSpecs = MakeUnique<nsFramesetSpec[]>(1);
       mNumRows = 1;
       mRowSpecs[0].mUnit  = eFramesetUnit_Relative;
       mRowSpecs[0].mValue = 1;
     }
   }
 
-  *aSpecs = mRowSpecs;
+  *aSpecs = mRowSpecs.get();
   *aNumValues = mNumRows;
   return NS_OK;
 }
 
 nsresult
 HTMLFrameSetElement::GetColSpec(int32_t *aNumValues,
                                 const nsFramesetSpec** aSpecs)
 {
@@ -141,29 +142,29 @@ HTMLFrameSetElement::GetColSpec(int32_t 
   NS_PRECONDITION(aSpecs, "Must have a pointer to an array of nsFramesetSpecs");
   *aNumValues = 0;
   *aSpecs = nullptr;
 
   if (!mColSpecs) {
     const nsAttrValue* value = GetParsedAttr(nsGkAtoms::cols);
     if (value && value->Type() == nsAttrValue::eString) {
       nsresult rv = ParseRowCol(value->GetStringValue(), mNumCols,
-                                getter_Transfers(mColSpecs));
+                                &mColSpecs);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if (!mColSpecs) {  // we may not have had an attr or had an empty attr
-      mColSpecs = new nsFramesetSpec[1];
+      mColSpecs = MakeUnique<nsFramesetSpec[]>(1);
       mNumCols = 1;
       mColSpecs[0].mUnit  = eFramesetUnit_Relative;
       mColSpecs[0].mValue = 1;
     }
   }
 
-  *aSpecs = mColSpecs;
+  *aSpecs = mColSpecs.get();
   *aNumValues = mNumCols;
   return NS_OK;
 }
 
 
 bool
 HTMLFrameSetElement::ParseAttribute(int32_t aNamespaceID,
                                     nsIAtom* aAttribute,
@@ -200,17 +201,17 @@ HTMLFrameSetElement::GetAttributeChangeH
 }
 
 /**
  * Translate a "rows" or "cols" spec into an array of nsFramesetSpecs
  */
 nsresult
 HTMLFrameSetElement::ParseRowCol(const nsAString & aValue,
                                  int32_t& aNumSpecs,
-                                 nsFramesetSpec** aSpecs) 
+                                 UniquePtr<nsFramesetSpec[]>* aSpecs)
 {
   if (aValue.IsEmpty()) {
     aNumSpecs = 0;
     *aSpecs = nullptr;
     return NS_OK;
   }
 
   static const char16_t sAster('*');
@@ -228,17 +229,17 @@ HTMLFrameSetElement::ParseRowCol(const n
                 "Too many frameset specs allowed to allocate");
   int32_t commaX = spec.FindChar(sComma);
   int32_t count = 1;
   while (commaX != kNotFound && count < NS_MAX_FRAMESET_SPEC_COUNT) {
     count++;
     commaX = spec.FindChar(sComma, commaX + 1);
   }
 
-  nsFramesetSpec* specs = new (fallible) nsFramesetSpec[count];
+  auto specs = MakeUniqueFallible<nsFramesetSpec[]>(count);
   if (!specs) {
     *aSpecs = nullptr;
     aNumSpecs = 0;
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // Pre-grab the compat mode; we may need it later in the loop.
   bool isInQuirks = InNavQuirksMode(OwnerDoc());
@@ -322,18 +323,18 @@ HTMLFrameSetElement::ParseRowCol(const n
         specs[i].mValue = 0;
       }
       start = end + 1;
     }
   }
 
   aNumSpecs = count;
   // Transfer ownership to caller here
-  *aSpecs = specs;
-  
+  *aSpecs = Move(specs);
+
   return NS_OK;
 }
 
 bool
 HTMLFrameSetElement::IsEventAttributeName(nsIAtom *aName)
 {
   return nsContentUtils::IsEventAttributeName(aName,
                                               EventNameType_HTML |
--- a/dom/html/HTMLFrameSetElement.h
+++ b/dom/html/HTMLFrameSetElement.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef HTMLFrameSetElement_h
 #define HTMLFrameSetElement_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/UniquePtr.h"
 #include "nsIDOMHTMLFrameSetElement.h"
 #include "nsGenericHTMLElement.h"
 
 /**
  * The nsFramesetUnit enum is used to denote the type of each entry
  * in the row or column spec.
  */
 enum nsFramesetUnit {
@@ -139,18 +140,18 @@ public:
 
 protected:
   virtual ~HTMLFrameSetElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   nsresult ParseRowCol(const nsAString& aValue,
-                       int32_t&         aNumSpecs,
-                       nsFramesetSpec** aSpecs);
+                       int32_t& aNumSpecs,
+                       UniquePtr<nsFramesetSpec[]>* aSpecs);
 
   /**
    * The number of size specs in our "rows" attr
    */
   int32_t          mNumRows;
   /**
    * The number of size specs in our "cols" attr
    */
@@ -158,19 +159,19 @@ private:
   /**
    * The style hint to return for the rows/cols attrs in
    * GetAttributeChangeHint
    */
   nsChangeHint      mCurrentRowColHint;
   /**
    * The parsed representation of the "rows" attribute
    */
-  nsAutoArrayPtr<nsFramesetSpec>  mRowSpecs; // parsed, non-computed dimensions
+  UniquePtr<nsFramesetSpec[]>  mRowSpecs; // parsed, non-computed dimensions
   /**
    * The parsed representation of the "cols" attribute
    */
-  nsAutoArrayPtr<nsFramesetSpec>  mColSpecs; // parsed, non-computed dimensions
+  UniquePtr<nsFramesetSpec[]>  mColSpecs; // parsed, non-computed dimensions
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // HTMLFrameSetElement_h
--- a/dom/interfaces/base/nsIContentPrefService.idl
+++ b/dom/interfaces/base/nsIContentPrefService.idl
@@ -5,32 +5,37 @@
 #include "nsISupports.idl"
 
 interface nsIVariant;
 interface nsIPropertyBag2;
 interface nsIContentURIGrouper;
 interface nsILoadContext;
 interface mozIStorageConnection;
 
-[scriptable, uuid(746c7a02-f6c1-4869-b434-7c8b86e60e61)]
+[scriptable, uuid(43635c53-b445-4c4e-8cc5-562697299b55)]
 interface nsIContentPrefObserver : nsISupports
 {
   /**
    * Called when a content pref is set to a different value.
-   * 
+   *
    * @param    aGroup      the group to which the pref belongs, or null
    *                       if it's a global pref (applies to all sites)
    * @param    aName       the name of the pref that was set
    * @param    aValue      the new value of the pref
+   * @param    aIsPrivate  an optional flag determining whether the
+   *                       original context is private or not
    */
-  void onContentPrefSet(in AString aGroup, in AString aName, in nsIVariant aValue);
+  void onContentPrefSet(in AString aGroup,
+                        in AString aName,
+                        in nsIVariant aValue,
+                        [optional] in boolean aIsPrivate);
 
   /**
    * Called when a content pref is removed.
-   * 
+   *
    * @param    aGroup      the group to which the pref belongs, or null
    *                       if it's a global pref (applies to all sites)
    * @param    aName       the name of the pref that was removed
    */
   void onContentPrefRemoved(in AString aGroup, in AString aName);
 };
 
 [scriptable, function, uuid(c1b3d6df-5373-4606-8494-8bcf14a7fc62)]
@@ -53,17 +58,17 @@ interface nsIContentPrefService : nsISup
    * to NULL in the database, as well as undefined (nsIDataType::VTYPE_VOID),
    * which means there is no record for this pref in the database.
    *
    * This method can be called from content processes in electrolysis builds.
    * We have a whitelist of values that can be read in such a way.
    *
    * @param    aGroup      the group for which to get the pref, as an nsIURI
    *                       from which the hostname will be used, a string
-   *                       (typically in the format of a hostname), or null 
+   *                       (typically in the format of a hostname), or null
    *                       to get the global pref (applies to all sites)
    * @param    aName       the name of the pref to get
    * @param    aPrivacyContext
    *                       a context from which to determine the privacy status
    *                       of the pref (ie. whether to search in memory or in
    *                       permanent storage for it), obtained from a relevant
    *                       window or channel.
    * @param    aCallback   an optional nsIContentPrefCallback to receive the
@@ -94,17 +99,17 @@ interface nsIContentPrefService : nsISup
    *                       a context from which to determine the privacy status
    *                       of the pref (ie. whether to store it in memory or in
    *                       permanent storage), obtained from a relevant
    *                       window or channel.
    * @throws   NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null
    * @throws   NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string
    */
   void setPref(in nsIVariant aGroup, in AString aName, in nsIVariant aValue, in nsILoadContext aPrivacyContext);
-  
+
   /**
    * Check whether or not a pref exists.
    *
    * @param    aGroup      the group for which to check for the pref, as an nsIURI
    *                       from which the hostname will be used, a string
    *                       (typically in the format of a hostname), or null
    *                       to check for the global pref (applies to all sites)
    * @param    aName       the name of the pref to check for
@@ -137,17 +142,17 @@ interface nsIContentPrefService : nsISup
   boolean hasCachedPref(in nsIVariant aGroup, in AString aName, in nsILoadContext aContext);
 
   /**
    * Remove a pref.
    *
    * @param    aGroup      the group for which to remove the pref, as an nsIURI
    *                       from which the hostname will be used, a string
    *                       (typically in the format of a hostname), or null
-   *                       to remove the global pref (applies to all sites) 
+   *                       to remove the global pref (applies to all sites)
    * @param    aName       the name of the pref to remove
    * @param    aPrivacyContext
    *                       a context from which to determine the privacy status
    *                       of the pref (ie. whether to search in memory or in
    *                       permanent storage for it), obtained from a relevant
    *                       window or channel.
    * @throws   NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null
    * @throws   NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string
@@ -180,52 +185,52 @@ interface nsIContentPrefService : nsISup
   void removePrefsByName(in AString aName, in nsILoadContext aContext);
 
   /**
    * Get the prefs that apply to the given site.
    *
    * @param    aGroup      the group for which to retrieve prefs, as an nsIURI
    *                       from which the hostname will be used, a string
    *                       (typically in the format of a hostname), or null
-   *                       to get the global prefs (apply to all sites) 
+   *                       to get the global prefs (apply to all sites)
    * @param    aPrivacyContext
    *                       a context from which to determine the privacy status
    *                       of the pref (ie. whether to search for prefs in memory
    *                       or in permanent storage), obtained from a relevant
    *                       window or channel.
-   * 
+   *
    * @returns  a property bag of prefs
    * @throws   NS_ERROR_ILLEGAL_VALUE if aGroup is not a string, nsIURI, or null
    */
   nsIPropertyBag2 getPrefs(in nsIVariant aGroup, in nsILoadContext aContext);
 
   /**
    * Get the prefs with the given name.
    *
    * @param    aName        the setting name for which to retrieve prefs
    * @param    aPrivacyContext
    *                        a context from which to determine the privacy status
    *                        of the pref (ie. whether to search for prefs in memory
    *                        or in permanent storage), obtained from a relevant
    *                        window or channel.
-   * 
+   *
    * @returns  a property bag of prefs
    * @throws   NS_ERROR_ILLEGAL_VALUE if aName is null or an empty string
    */
   nsIPropertyBag2 getPrefsByName(in AString aName, in nsILoadContext aContext);
-  
+
   /**
    * Add an observer.
-   * 
+   *
    * @param    aName       the setting to observe, or null to add
    *                       a generic observer that observes all settings
    * @param    aObserver   the observer to add
    */
   void addObserver(in AString aName, in nsIContentPrefObserver aObserver);
-  
+
   /**
    * Remove an observer.
    *
    * @param    aName       the setting being observed, or null to remove
    *                       a generic observer that observes all settings
    * @param    aObserver   the observer to remove
    */
   void removeObserver(in AString aName, in nsIContentPrefObserver aObserver);
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -668,20 +668,16 @@ ContentChild::Init(MessageLoop* aIOLoop,
     return false;
   }
 
   if (!Open(aChannel, aParentPid, aIOLoop)) {
     return false;
   }
   sSingleton = this;
 
-  // Make sure there's an nsAutoScriptBlocker on the stack when dispatching
-  // urgent messages.
-  GetIPCChannel()->BlockScripts();
-
   // If communications with the parent have broken down, take the process
   // down so it's not hanging around.
   bool abortOnError = true;
 #ifdef MOZ_NUWA_PROCESS
   abortOnError &= !IsNuwaProcess();
 #endif
   GetIPCChannel()->SetAbortOnError(abortOnError);
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -33,16 +33,17 @@
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
+#include "mozilla/UniquePtr.h"
 #include "mozilla/unused.h"
 #include "BlobParent.h"
 #include "nsCOMPtr.h"
 #include "nsContentAreaDragDrop.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsFocusManager.h"
 #include "nsFrameLoader.h"
@@ -2120,35 +2121,35 @@ TabParent::RecvRequestFocus(const bool& 
 
 bool
 TabParent::RecvEnableDisableCommands(const nsString& aAction,
                                      nsTArray<nsCString>&& aEnabledCommands,
                                      nsTArray<nsCString>&& aDisabledCommands)
 {
   nsCOMPtr<nsIRemoteBrowser> remoteBrowser = do_QueryInterface(mFrameElement);
   if (remoteBrowser) {
-    nsAutoArrayPtr<const char*> enabledCommands, disabledCommands;
+    UniquePtr<const char*[]> enabledCommands, disabledCommands;
 
     if (aEnabledCommands.Length()) {
-      enabledCommands = new const char* [aEnabledCommands.Length()];
+      enabledCommands = MakeUnique<const char*[]>(aEnabledCommands.Length());
       for (uint32_t c = 0; c < aEnabledCommands.Length(); c++) {
         enabledCommands[c] = aEnabledCommands[c].get();
       }
     }
 
     if (aDisabledCommands.Length()) {
-      disabledCommands = new const char* [aDisabledCommands.Length()];
+      disabledCommands = MakeUnique<const char*[]>(aDisabledCommands.Length());
       for (uint32_t c = 0; c < aDisabledCommands.Length(); c++) {
         disabledCommands[c] = aDisabledCommands[c].get();
       }
     }
 
     remoteBrowser->EnableDisableCommands(aAction,
-                                         aEnabledCommands.Length(), enabledCommands,
-                                         aDisabledCommands.Length(), disabledCommands);
+                                         aEnabledCommands.Length(), enabledCommands.get(),
+                                         aDisabledCommands.Length(), disabledCommands.get());
   }
 
   return true;
 }
 
 NS_IMETHODIMP
 TabParent::GetChildProcessOffset(int32_t* aOutCssX, int32_t* aOutCssY)
 {
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -102,16 +102,17 @@ MP4Decoder::CanHandleMediaType(const nsA
   const bool isMP4Audio = aMIMETypeExcludingCodecs.EqualsASCII("audio/mp4") ||
                           aMIMETypeExcludingCodecs.EqualsASCII("audio/x-m4a");
   const bool isMP4Video =
   // On B2G, treat 3GPP as MP4 when Gonk PDM is available.
 #ifdef MOZ_GONK_MEDIACODEC
     aMIMETypeExcludingCodecs.EqualsASCII(VIDEO_3GPP) ||
 #endif
     aMIMETypeExcludingCodecs.EqualsASCII("video/mp4") ||
+    aMIMETypeExcludingCodecs.EqualsASCII("video/quicktime") ||
     aMIMETypeExcludingCodecs.EqualsASCII("video/x-m4v");
   if (!isMP4Audio && !isMP4Video) {
     return false;
   }
 
   nsTArray<nsCString> codecMimes;
   if (aCodecs.IsEmpty()) {
     // No codecs specified. Assume AAC/H.264
--- a/dom/media/gtest/TestMP4Demuxer.cpp
+++ b/dom/media/gtest/TestMP4Demuxer.cpp
@@ -422,17 +422,26 @@ TEST(MP4Demuxer, GetNextKeyframe)
         EXPECT_EQ(time.ToMicroseconds(), 1000000);
         binding->mTaskQueue->BeginShutdown();
       },
       DO_FAIL
     );
   });
 }
 
-TEST(MP4Demuxer, ZeroInMoov)
+TEST(MP4Demuxer, ZeroInLastMoov)
 {
   RefPtr<MP4DemuxerBinding> binding = new MP4DemuxerBinding("short-zero-in-moov.mp4");
   binding->RunTestAndWait([binding] () {
     // It demuxes without error. That is sufficient.
     binding->mTaskQueue->BeginShutdown();
   });
 }
 
+
+TEST(MP4Demuxer, ZeroInMoovQuickTime)
+{
+  RefPtr<MP4DemuxerBinding> binding = new MP4DemuxerBinding("short-zero-inband.mov");
+  binding->RunTestAndWait([binding] () {
+    // It demuxes without error. That is sufficient.
+    binding->mTaskQueue->BeginShutdown();
+  });
+}
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -44,16 +44,17 @@ TEST_HARNESS_FILES.gtest += [
     '../test/gizmo-frag.mp4',
     '../test/gizmo.mp4',
     'dash_dashinit.mp4',
     'id3v2header.mp3',
     'mediasource_test.mp4',
     'noise.mp3',
     'noise_vbr.mp3',
     'short-zero-in-moov.mp4',
+    'short-zero-inband.mov',
     'small-shot.mp3',
     'test.webm',
     'test_case_1224361.vp8.ivf',
     'test_case_1224363.vp8.ivf',
     'test_case_1224369.vp8.ivf',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9c1864286526a0db4a4ee98bdcb34111539d2625
GIT binary patch
literal 93641
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
--- a/dom/mobilemessage/MobileMessageManager.cpp
+++ b/dom/mobilemessage/MobileMessageManager.cpp
@@ -19,16 +19,17 @@
 #include "mozilla/dom/MozMessageDeletedEvent.h"
 #include "mozilla/dom/MozMmsEvent.h"
 #include "mozilla/dom/MozMobileMessageManagerBinding.h"
 #include "mozilla/dom/MozSmsEvent.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
+#include "mozilla/UniquePtr.h"
 #include "nsIMmsService.h"
 #include "nsIMobileMessageCallback.h"
 #include "nsIMobileMessageDatabaseService.h"
 #include "nsIMobileMessageService.h"
 #include "nsIObserverService.h"
 #include "nsISmsService.h"
 #include "nsServiceManagerUtils.h" // For do_GetService()
 
@@ -419,25 +420,25 @@ MobileMessageManager::GetMessages(const 
   }
 
   bool hasEndDate = !aFilter.mEndDate.IsNull();
   uint64_t endDate = 0;
   if (hasEndDate) {
     endDate = aFilter.mEndDate.Value();
   }
 
-  nsAutoArrayPtr<const char16_t*> ptrNumbers;
+  UniquePtr<const char16_t*[]> ptrNumbers;
   uint32_t numbersCount = 0;
   if (!aFilter.mNumbers.IsNull() &&
       aFilter.mNumbers.Value().Length()) {
     const FallibleTArray<nsString>& numbers = aFilter.mNumbers.Value();
     uint32_t index;
 
     numbersCount = numbers.Length();
-    ptrNumbers = new const char16_t* [numbersCount];
+    ptrNumbers = MakeUnique<const char16_t*[]>(numbersCount);
     for (index = 0; index < numbersCount; index++) {
       ptrNumbers[index] = numbers[index].get();
     }
   }
 
   nsString delivery;
   delivery.SetIsVoid(true);
   if (!aFilter.mDelivery.IsNull()) {
@@ -459,17 +460,17 @@ MobileMessageManager::GetMessages(const 
     threadId = aFilter.mThreadId.Value();
   }
 
   RefPtr<MobileMessageCursorCallback> cursorCallback =
     new MobileMessageCursorCallback();
   nsCOMPtr<nsICursorContinueCallback> continueCallback;
   nsresult rv = dbService->CreateMessageCursor(hasStartDate, startDate,
                                                hasEndDate, endDate,
-                                               ptrNumbers, numbersCount,
+                                               ptrNumbers.get(), numbersCount,
                                                delivery,
                                                hasRead, read,
                                                hasThreadId, threadId,
                                                aReverse, cursorCallback,
                                                getter_AddRefs(continueCallback));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
--- a/dom/mobilemessage/ipc/SmsParent.cpp
+++ b/dom/mobilemessage/ipc/SmsParent.cpp
@@ -17,16 +17,17 @@
 #include "MmsMessageInternal.h"
 #include "nsIMobileMessageDatabaseService.h"
 #include "MobileMessageThreadInternal.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/mobilemessage/Constants.h" // For MessageType
+#include "mozilla/UniquePtr.h"
 #include "nsContentUtils.h"
 #include "nsTArrayHelpers.h"
 #include "xpcpublic.h"
 #include "nsServiceManagerUtils.h"
 #include "DeletedMessageInfo.h"
 
 namespace mozilla {
 namespace dom {
@@ -825,32 +826,32 @@ MobileMessageCursorParent::DoRequest(con
   nsresult rv = NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIMobileMessageDatabaseService> dbService =
     do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID);
   if (dbService) {
     const SmsFilterData& filter = aRequest.filter();
 
     const nsTArray<nsString>& numbers = filter.numbers();
-    nsAutoArrayPtr<const char16_t*> ptrNumbers;
+    UniquePtr<const char16_t*[]> ptrNumbers;
     uint32_t numbersCount = numbers.Length();
     if (numbersCount) {
       uint32_t index;
 
-      ptrNumbers = new const char16_t* [numbersCount];
+      ptrNumbers = MakeUnique<const char16_t*[]>(numbersCount);
       for (index = 0; index < numbersCount; index++) {
         ptrNumbers[index] = numbers[index].get();
       }
     }
 
     rv = dbService->CreateMessageCursor(filter.hasStartDate(),
                                         filter.startDate(),
                                         filter.hasEndDate(),
                                         filter.endDate(),
-                                        ptrNumbers, numbersCount,
+                                        ptrNumbers.get(), numbersCount,
                                         filter.delivery(),
                                         filter.hasRead(),
                                         filter.read(),
                                         filter.hasThreadId(),
                                         filter.threadId(),
                                         aRequest.reverse(),
                                         this,
                                         getter_AddRefs(mContinueCallback));
--- a/dom/network/NetworkStatsManager.js
+++ b/dom/network/NetworkStatsManager.js
@@ -106,61 +106,45 @@ NetworkStatsAlarm.prototype = {
 
   QueryInterface : XPCOMUtils.generateQI([])
 };
 
 // NetworkStatsManager
 
 const NETWORKSTATSMANAGER_CONTRACTID = "@mozilla.org/networkStatsManager;1";
 const NETWORKSTATSMANAGER_CID        = Components.ID("{ceb874cd-cc1a-4e65-b404-cc2d3e42425f}");
-const nsIDOMMozNetworkStatsManager   = Ci.nsIDOMMozNetworkStatsManager;
 
 function NetworkStatsManager() {
   if (DEBUG) {
     debug("Constructor");
   }
 }
 
 NetworkStatsManager.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
-  checkPrivileges: function checkPrivileges() {
-    if (!this.hasPrivileges) {
-      throw Components.Exception("Permission denied", Cr.NS_ERROR_FAILURE);
-    }
-  },
-
   getSamples: function getSamples(aNetwork, aStart, aEnd, aOptions) {
-    this.checkPrivileges();
-
-    if (aStart.constructor.name !== "Date" ||
-        aEnd.constructor.name !== "Date" ||
-        !(aNetwork instanceof this.window.MozNetworkStatsInterface) ||
-        aStart > aEnd) {
+    if (aStart > aEnd) {
       throw Components.results.NS_ERROR_INVALID_ARG;
     }
 
-    let appManifestURL = null;
-    let browsingTrafficOnly = false;
-    let serviceType = null;
-    if (aOptions) {
-      // appManifestURL is used to query network statistics by app;
-      // serviceType is used to query network statistics by system service.
-      // It is illegal to specify both of them at the same time.
-      if (aOptions.appManifestURL && aOptions.serviceType) {
-        throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-      }
-      // browsingTrafficOnly is meaningful only when querying by app.
-      if (!aOptions.appManifestURL && aOptions.browsingTrafficOnly) {
-        throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-      }
-      appManifestURL = aOptions.appManifestURL;
-      serviceType = aOptions.serviceType;
-      browsingTrafficOnly = aOptions.browsingTrafficOnly || false;
+    // appManifestURL is used to query network statistics by app;
+    // serviceType is used to query network statistics by system service.
+    // It is illegal to specify both of them at the same time.
+    if (aOptions.appManifestURL && aOptions.serviceType) {
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
     }
+    // browsingTrafficOnly is meaningful only when querying by app.
+    if (!aOptions.appManifestURL && aOptions.browsingTrafficOnly) {
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    }
+
+    let appManifestURL = aOptions.appManifestURL;
+    let serviceType = aOptions.serviceType;
+    let browsingTrafficOnly = aOptions.browsingTrafficOnly;
 
     // TODO Bug 929410 Date object cannot correctly pass through cpmm/ppmm IPC
     // This is just a work-around by passing timestamp numbers.
     aStart = aStart.getTime();
     aEnd = aEnd.getTime();
 
     let request = this.createRequest();
     cpmm.sendAsyncMessage("NetworkStats:Get",
@@ -170,122 +154,90 @@ NetworkStatsManager.prototype = {
                             appManifestURL: appManifestURL,
                             browsingTrafficOnly: browsingTrafficOnly,
                             serviceType: serviceType,
                             id: this.getRequestId(request) });
     return request;
   },
 
   clearStats: function clearStats(aNetwork) {
-    this.checkPrivileges();
-
-    if (!aNetwork instanceof this.window.MozNetworkStatsInterface) {
-      throw Components.results.NS_ERROR_INVALID_ARG;
-    }
-
     let request = this.createRequest();
     cpmm.sendAsyncMessage("NetworkStats:Clear",
                           { network: aNetwork.toJSON(),
                             id: this.getRequestId(request) });
     return request;
   },
 
   clearAllStats: function clearAllStats() {
-    this.checkPrivileges();
-
     let request = this.createRequest();
     cpmm.sendAsyncMessage("NetworkStats:ClearAll",
                           {id: this.getRequestId(request)});
     return request;
   },
 
   addAlarm: function addAlarm(aNetwork, aThreshold, aOptions) {
-    this.checkPrivileges();
-
-    if (!aOptions) {
-      aOptions = Object.create(null);
-    }
-
-    if (aOptions.startTime && aOptions.startTime.constructor.name !== "Date" ||
-        !(aNetwork instanceof this.window.MozNetworkStatsInterface)) {
-      throw Components.results.NS_ERROR_INVALID_ARG;
-    }
-
     let request = this.createRequest();
     cpmm.sendAsyncMessage("NetworkStats:SetAlarm",
                           {id: this.getRequestId(request),
                            data: {network: aNetwork.toJSON(),
                                   threshold: aThreshold,
                                   startTime: aOptions.startTime,
                                   data: aOptions.data,
                                   manifestURL: this.manifestURL,
                                   pageURL: this.pageURL}});
     return request;
   },
 
   getAllAlarms: function getAllAlarms(aNetwork) {
-    this.checkPrivileges();
-
     let network = null;
     if (aNetwork) {
-      if (!aNetwork instanceof this.window.MozNetworkStatsInterface) {
-        throw Components.results.NS_ERROR_INVALID_ARG;
-      }
       network = aNetwork.toJSON();
     }
 
     let request = this.createRequest();
     cpmm.sendAsyncMessage("NetworkStats:GetAlarms",
                           {id: this.getRequestId(request),
                            data: {network: network,
                                   manifestURL: this.manifestURL}});
     return request;
   },
 
   removeAlarms: function removeAlarms(aAlarmId) {
-    this.checkPrivileges();
-
     if (aAlarmId == 0) {
       aAlarmId = -1;
     }
 
     let request = this.createRequest();
     cpmm.sendAsyncMessage("NetworkStats:RemoveAlarms",
                           {id: this.getRequestId(request),
                            data: {alarmId: aAlarmId,
                                   manifestURL: this.manifestURL}});
 
     return request;
   },
 
   getAvailableNetworks: function getAvailableNetworks() {
-    this.checkPrivileges();
-
     let request = this.createRequest();
     cpmm.sendAsyncMessage("NetworkStats:GetAvailableNetworks",
                           { id: this.getRequestId(request) });
     return request;
   },
 
   getAvailableServiceTypes: function getAvailableServiceTypes() {
-    this.checkPrivileges();
-
     let request = this.createRequest();
     cpmm.sendAsyncMessage("NetworkStats:GetAvailableServiceTypes",
                           { id: this.getRequestId(request) });
     return request;
   },
 
   get sampleRate() {
-    this.checkPrivileges();
     return cpmm.sendSyncMessage("NetworkStats:SampleRate")[0];
   },
 
   get maxStorageAge() {
-    this.checkPrivileges();
     return cpmm.sendSyncMessage("NetworkStats:MaxStorageAge")[0];
   },
 
   receiveMessage: function(aMessage) {
     if (DEBUG) {
       debug("NetworkStatsmanager::receiveMessage: " + aMessage.name);
     }
 
@@ -385,37 +337,17 @@ NetworkStatsManager.prototype = {
       default:
         if (DEBUG) {
           debug("Wrong message: " + aMessage.name);
         }
     }
   },
 
   init: function(aWindow) {
-    // Set navigator.mozNetworkStats to null.
-    if (!Services.prefs.getBoolPref("dom.mozNetworkStats.enabled")) {
-      return null;
-    }
-
     let principal = aWindow.document.nodePrincipal;
-    let secMan = Services.scriptSecurityManager;
-    let perm = principal == secMan.getSystemPrincipal() ?
-                 Ci.nsIPermissionManager.ALLOW_ACTION :
-                 Services.perms.testExactPermissionFromPrincipal(principal,
-                                                                 "networkstats-manage");
-
-    // Only pages with perm set can use the netstats.
-    this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
-    if (DEBUG) {
-      debug("has privileges: " + this.hasPrivileges);
-    }
-
-    if (!this.hasPrivileges) {
-      return null;
-    }
 
     this.initDOMRequestHelper(aWindow, ["NetworkStats:Get:Return",
                                         "NetworkStats:GetAvailableNetworks:Return",
                                         "NetworkStats:GetAvailableServiceTypes:Return",
                                         "NetworkStats:Clear:Return",
                                         "NetworkStats:ClearAll:Return",
                                         "NetworkStats:SetAlarm:Return",
                                         "NetworkStats:GetAlarms:Return",
@@ -438,25 +370,19 @@ NetworkStatsManager.prototype = {
   // Called from DOMRequestIpcHelper
   uninit: function uninit() {
     if (DEBUG) {
       debug("uninit call");
     }
   },
 
   classID : NETWORKSTATSMANAGER_CID,
-  QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsManager,
-                                         Ci.nsIDOMGlobalPropertyInitializer,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsIObserver]),
-
-  classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSMANAGER_CID,
-                                     contractID: NETWORKSTATSMANAGER_CONTRACTID,
-                                     classDescription: "NetworkStatsManager",
-                                     interfaces: [nsIDOMMozNetworkStatsManager],
-                                     flags: nsIClassInfo.DOM_OBJECT})
+  contractID : NETWORKSTATSMANAGER_CONTRACTID,
+  QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
+                                          Ci.nsISupportsWeakReference,
+                                          Ci.nsIObserver]),
 }
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsAlarm,
                                                      NetworkStatsData,
                                                      NetworkStatsInterface,
                                                      NetworkStats,
                                                      NetworkStatsManager]);
--- a/dom/network/NetworkStatsManager.manifest
+++ b/dom/network/NetworkStatsManager.manifest
@@ -7,9 +7,8 @@ contract @mozilla.org/networkStats;1 {28
 component {f540615b-d803-43ff-8200-2a9d145a5645} NetworkStatsManager.js
 contract @mozilla.org/networkstatsinterface;1 {f540615b-d803-43ff-8200-2a9d145a5645}
 
 component {a93ea13e-409c-4189-9b1e-95fff220be55} NetworkStatsManager.js
 contract @mozilla.org/networkstatsalarm;1 {a93ea13e-409c-4189-9b1e-95fff220be55}
 
 component {ceb874cd-cc1a-4e65-b404-cc2d3e42425f} NetworkStatsManager.js
 contract @mozilla.org/networkStatsManager;1 {ceb874cd-cc1a-4e65-b404-cc2d3e42425f}
-category JavaScript-navigator-property mozNetworkStats @mozilla.org/networkStatsManager;1
--- a/dom/network/interfaces/moz.build
+++ b/dom/network/interfaces/moz.build
@@ -7,13 +7,12 @@
 XPIDL_SOURCES += [
     'nsIMozNavigatorNetwork.idl',
     'nsITCPSocketCallback.idl',
     'nsIUDPSocketChild.idl',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     XPIDL_SOURCES += [
-        'nsIDOMNetworkStatsManager.idl',
         'nsINetworkStatsServiceProxy.idl',
     ]
 
 XPIDL_MODULE = 'dom_network'
deleted file mode 100644
--- a/dom/network/interfaces/nsIDOMNetworkStatsManager.idl
+++ /dev/null
@@ -1,96 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-interface nsIDOMDOMRequest;
-
-[scriptable,  uuid(72c4e583-389d-4d1b-9424-702feabb6055)]
-interface nsIDOMMozNetworkStatsManager : nsISupports
-{
-  /**
-   * Constants for known interface types.
-   */
-  const long WIFI = 0;
-  const long MOBILE = 1;
-
-  /**
-   * Find samples between two dates start and end, both included.
-   *
-   * If options is provided, per-app or per-system service usage will be
-   * retrieved; otherwise the target will be overall system usage.
-   *
-   * If success, the request result will be an nsIDOMMozNetworkStats object.
-   */
-  nsIDOMDOMRequest getSamples(in nsISupports network,
-                              in jsval start,
-                              in jsval end,
-                   [optional] in jsval options /* NetworkStatsGetOptions */);
-
-  /**
-   * Install an alarm on a network. The network must be in the return of
-   * getAvailableNetworks() otherwise an "InvalidNetwork" exception will
-   * be raised.
-   *
-   * When total data usage reaches threshold bytes, a "networkstats-alarm"
-   * system message is sent to the application, where the optional parameter
-   * |data| must be a cloneable object.
-   *
-   * If success, the |result| field of the DOMRequest keeps the alarm Id.
-   */
-  nsIDOMDOMRequest addAlarm(in nsISupports network,
-                            in long long threshold,
-                            [optional] in jsval options /* NetworkStatsAlarmOptions */);
-
-  /**
-   * Obtain all alarms for those networks returned by getAvailableNetworks().
-   * If a network is provided, only retrieves the alarms for that network.
-   * The network must be one of those returned by getAvailebleNetworks() or an
-   * "InvalidNetwork" exception will be raised.
-   *
-   * Each alarm object has the same fields as that in the system message:
-   *  - alarmId
-   *  - network
-   *  - threshold
-   *  - data
-   */
-  nsIDOMDOMRequest getAllAlarms([optional] in nsISupports network);
-
-  /**
-   * Remove all network alarms. If an |alarmId| is provided, then only that
-   * alarm is removed.
-   */
-  nsIDOMDOMRequest removeAlarms([optional] in long alarmId);
-
-  /**
-   * Remove all stats related with the provided network from DB.
-   */
-  nsIDOMDOMRequest clearStats(in nsISupports network);
-
-  /**
-   * Remove all stats in the database.
-   */
-  nsIDOMDOMRequest clearAllStats();
-
-  /**
-   * Return available networks that used to be saved in the database.
-   */
-  nsIDOMDOMRequest getAvailableNetworks(); // array of MozNetworkStatsInterface.
-
-  /**
-   * Return available service types that used to be saved in the database.
-   */
-  nsIDOMDOMRequest getAvailableServiceTypes(); // array of string.
-
-  /**
-   * Minimum time in milliseconds between samples stored in the database.
-   */
-  readonly attribute long sampleRate;
-
-  /**
-   * Time in milliseconds recorded by the API until present time. All samples
-   * older than maxStorageAge from now are deleted.
-   */
-  readonly attribute long long maxStorageAge;
-};
--- a/dom/network/tests/test_networkstats_alarms.html
+++ b/dom/network/tests/test_networkstats_alarms.html
@@ -43,53 +43,51 @@ var steps = [
     req = navigator.mozNetworkStats
                    .getAllAlarms(new window.MozNetworkStatsInterface(mobile));
 
     req.onsuccess = function () {
       ok(false, "getAllAlarms() shouldn't succeed!");
     };
 
     req.onerror = function () {
-      ok(req.error.name == "InvalidInterface", "Get InvalidInterface error");
+      is(req.error.name, "InvalidInterface", "Get InvalidInterface error");
       next();
     }
   },
   function () {
     ok(true, "Calling addAlarm() with invalid network or parameters.");
+    var msg = "TypeError: Not enough arguments to MozNetworkStatsManager.addAlarm.";
 
     try {
       navigator.mozNetworkStats.addAlarm();
     } catch(ex) {
-      ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
-         "addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no parameters");
+      is(ex.toString(), msg, "addAlarm() throws \"" + msg + "\" when no parameters");
     }
 
     try {
       navigator.mozNetworkStats.addAlarm(100000);
     } catch(ex) {
-      ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
-         "addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no network");
+      is(ex.toString(), msg, "addAlarm() throws " + msg + " when no network");
     }
 
     try {
       navigator.mozNetworkStats.addAlarm(new window.MozNetworkStatsInterface(wifi));
     } catch(ex) {
-      ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS,
-         "addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no threshold");
+      is(ex.toString(), msg, "addAlarm() throws " + msg + " when no threshold");
     }
 
     req = navigator.mozNetworkStats
                    .addAlarm(new window.MozNetworkStatsInterface(mobile), -100000);
 
     req.onsuccess = function () {
       ok(false, "addAlarm() shouldn't succeed with negative threshold.");
     };
 
     req.onerror = function () {
-      ok(req.error.name == "InvalidThresholdValue", "Get InvalidThresholdValue error");
+      is(req.error.name, "InvalidThresholdValue", "Get InvalidThresholdValue error");
       next();
     }
   },
   function () {
     ok(true, "Calling addAlarm()");
 
     req = navigator.mozNetworkStats
                    .addAlarm(new window.MozNetworkStatsInterface(wifi), 100000000);
@@ -104,18 +102,18 @@ var steps = [
   },
   function () {
     ok(true, "Calling getAllAlarms()");
 
     req = navigator.mozNetworkStats
                    .getAllAlarms(new window.MozNetworkStatsInterface(wifi));
 
     req.onsuccess = function () {
-      ok(req.result.length == 1, "Only one alarm");
-      ok(req.result[0].alarmId == 1, "Get correct alarmId");
+      is(req.result.length, 1, "Only one alarm");
+      is(req.result[0].alarmId, 1, "Get correct alarmId");
       next();
     };
 
     req.onerror = function () {
       ok(false, "getAllAlarms() shouldn't fail.");
     }
   },
   function () {
@@ -221,18 +219,18 @@ SpecialPowers.pushPrefEnv({'set': [["dom
     ok(SpecialPowers.hasPermission("networkstats-manage", document),
        "Has permission 'networkstats-manage'.");
 
     ok(SpecialPowers.getBoolPref("dom.mozNetworkStats.enabled"),
        "Preference 'dom.mozNetworkStats.enabled' is true.");
 
     ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist");
 
-    ok(navigator.mozNetworkStats instanceof SpecialPowers.Ci.nsIDOMMozNetworkStatsManager,
-       "navigator.mozNetworkStats should be a nsIDOMMozNetworkStatsManager object");
+    ok(navigator.mozNetworkStats instanceof MozNetworkStatsManager,
+       "navigator.mozNetworkStats should be a MozNetworkStatsManager object");
 
     test();
   });
 });
 
 </script>
 </pre>
 </body>
--- a/dom/network/tests/test_networkstats_basics.html
+++ b/dom/network/tests/test_networkstats_basics.html
@@ -328,18 +328,18 @@ SpecialPowers.pushPrefEnv({'set': [["dom
     ok(SpecialPowers.hasPermission("networkstats-manage", document),
        "Has permission 'networkstats-manage'.");
 
     ok(SpecialPowers.getBoolPref("dom.mozNetworkStats.enabled"),
        "Preference 'dom.mozNetworkStats.enabled' is true.");
 
     ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist");
 
-    ok(navigator.mozNetworkStats instanceof SpecialPowers.Ci.nsIDOMMozNetworkStatsManager,
-       "navigator.mozNetworkStats should be a nsIDOMMozNetworkStatsManager object");
+    ok(navigator.mozNetworkStats instanceof MozNetworkStatsManager,
+       "navigator.mozNetworkStats should be a MozNetworkStatsManager object");
 
     test();
   });
 });
 
 </script>
 </pre>
 </body>
--- a/dom/network/tests/test_networkstats_disabled.html
+++ b/dom/network/tests/test_networkstats_disabled.html
@@ -17,20 +17,18 @@
 SimpleTest.waitForExplicitFinish();
 
 // Test to ensure NetworkStats is not accessible when it is disabled
 SpecialPowers.pushPrefEnv({'set': [["dom.mozNetworkStats.enabled", false]]},
                           function() {
   ok(!SpecialPowers.getBoolPref("dom.mozNetworkStats.enabled"),
      "Preference 'dom.mozNetworkStats.enabled' is false.");
 
-  ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist");
-
-  is(navigator.mozNetworkStats, null,
-     "mozNetworkStats should be null when not enabled.");
+  ok(!('mozNetworkStats' in navigator),
+     "navigator.mozNetworkStats should not exist when pref not set");
 
   SimpleTest.finish();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/network/tests/test_networkstats_enabled_no_perm.html
+++ b/dom/network/tests/test_networkstats_enabled_no_perm.html
@@ -22,31 +22,17 @@
 
   function runTest() {
     ok(SpecialPowers.getBoolPref("dom.mozNetworkStats.enabled"),
       "Preference 'dom.mozNetworkStats.enabled' is true.");
 
     ok(!SpecialPowers.hasPermission("networkstats-manage", document),
       "Has no permission 'networkstats-manage'.");
 
-    ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist");
-
-    is(navigator.mozNetworkStats, null,
-      "mozNetworkStats should be null when no permission.");
-
-    var error;
-    try {
-      navigator.mozNetworkStats.getAvailableNetworks;
+    ok(!('mozNetworkStats' in navigator),
+       "navigator.mozNetworkStats should not exist when permission not set");
 
-      ok(false,
-    	   "Accessing navigator.mozNetworkStats.getAvailableNetworks should throw!");
-        } catch (ex) {
-          error = ex;
-        }
-
-   ok(error,
-     "Got an exception accessing navigator.mozNetworkStats.getAvailableNetworks");
-   SimpleTest.finish();
-}
+    SimpleTest.finish();
+  }
 </script>
 </pre>
 </body>
 </html>
--- a/dom/network/tests/test_networkstats_enabled_perm.html
+++ b/dom/network/tests/test_networkstats_enabled_perm.html
@@ -25,18 +25,18 @@ SpecialPowers.pushPrefEnv({'set': [["dom
     ok(SpecialPowers.hasPermission("networkstats-manage", document),
        "Has permission 'networkstats-manage'.");
 
     ok(SpecialPowers.getBoolPref("dom.mozNetworkStats.enabled"),
        "Preference 'dom.mozNetworkStats.enabled' is true.");
 
     ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist");
 
-    ok(navigator.mozNetworkStats instanceof SpecialPowers.Ci.nsIDOMMozNetworkStatsManager,
-       "navigator.mozNetworkStats should be a nsIDOMMozNetworkStatsManager object");
+    ok(navigator.mozNetworkStats instanceof MozNetworkStatsManager,
+       "navigator.mozNetworkStats should be a MozNetworkStatsManager object");
 
     SimpleTest.finish();
   });
 });
 
 </script>
 </pre>
 </body>
--- a/dom/network/tests/unit_stats/test_networkstats_db.js
+++ b/dom/network/tests/unit_stats/test_networkstats_db.js
@@ -36,18 +36,18 @@ add_test(function prepareDatabase() {
 
 function filterTimestamp(date) {
   var sampleRate = netStatsDb.sampleRate;
   var offset = date.getTimezoneOffset() * 60 * 1000;
   return Math.floor((date.getTime() - offset) / sampleRate) * sampleRate;
 }
 
 function getNetworks() {
-  return [{ id: '0', type: Ci.nsIDOMMozNetworkStatsManager.WIFI },
-          { id: '1234', type: Ci.nsIDOMMozNetworkStatsManager.MOBILE }];
+  return [{ id: '0', type: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI },
+          { id: '1234', type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE }];
 }
 
 function compareNetworks(networkA, networkB) {
   return (networkA[0] == networkB[0] && networkA[1] == networkB[1]);
 }
 
 add_test(function test_sampleRate() {
   var sampleRate = netStatsDb.sampleRate;
--- a/dom/network/tests/unit_stats/test_networkstats_service.js
+++ b/dom/network/tests/unit_stats/test_networkstats_service.js
@@ -153,22 +153,22 @@ add_test(function test_queue() {
     MockNetdRequest(function () {
       if (aCallback) {
         aCallback(true, "ok");
       }
     });
   };
 
   // Fill networks with fake network interfaces to enable netd async requests.
-  var network = {id: "1234", type: Ci.nsIDOMMozNetworkStatsManager.MOBILE};
+  var network = {id: "1234", type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE};
   var netId1 = NetworkStatsService.getNetworkId(network.id, network.type);
   NetworkStatsService._networks[netId1] = { network: network,
                                             interfaceName: "net1" };
 
-  network = {id: "5678", type: Ci.nsIDOMMozNetworkStatsManager.MOBILE};
+  network = {id: "5678", type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE};
   var netId2 = NetworkStatsService.getNetworkId(network.id, network.type);
   NetworkStatsService._networks[netId2] = { network: network,
                                             interfaceName: "net2" };
 
   NetworkStatsService.updateStats(netId1);
   NetworkStatsService.updateStats(netId2);
   do_check_eq(NetworkStatsService.updateQueue.length, 2);
   do_check_eq(NetworkStatsService.updateQueue[0].callbacks.length, 1);
--- a/dom/payment/Payment.js
+++ b/dom/payment/Payment.js
@@ -5,61 +5,101 @@
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 
-const PAYMENTCONTENTHELPER_CID =
-  Components.ID("{a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0}");
-
 const PAYMENT_IPC_MSG_NAMES = ["Payment:Success",
                                "Payment:Failed"];
 
 const PREF_DEBUG = "dom.payment.debug";
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
-function PaymentContentHelper() {
+var _debug;
+try {
+  _debug = Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
+           && Services.prefs.getBoolPref(PREF_DEBUG);
+} catch(e) {
+  _debug = false;
+}
+
+function LOG(s) {
+  if (!_debug) {
+    return;
+  }
+  dump("-*- PaymentContentHelper: " + s + "\n");
+}
+
+function PaymentContentHelper(aWindow) {
+  this.initDOMRequestHelper(aWindow, PAYMENT_IPC_MSG_NAMES);
 };
 
 PaymentContentHelper.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsINavigatorPayment,
-                                         Ci.nsIDOMGlobalPropertyInitializer,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsIObserver]),
-  classID:        PAYMENTCONTENTHELPER_CID,
-  classInfo:      XPCOMUtils.generateCI({
-    classID: PAYMENTCONTENTHELPER_CID,
-    contractID: "@mozilla.org/payment/content-helper;1",
-    classDescription: "Payment Content Helper",
-    flags: Ci.nsIClassInfo.DOM_OBJECT,
-    interfaces: [Ci.nsINavigatorPayment]
-  }),
+  receiveMessage: function receiveMessage(aMessage) {
+    let name = aMessage.name;
+    let msg = aMessage.json;
+    if (_debug) {
+      LOG("Received message '" + name + "': " + JSON.stringify(msg));
+    }
+    let requestId = msg.requestId;
+    let request = this.takeRequest(requestId);
+    if (!request) {
+      return;
+    }
+    switch (name) {
+      case "Payment:Success":
+        Services.DOMRequest.fireSuccess(request, msg.result);
+        break;
+      case "Payment:Failed":
+        Services.DOMRequest.fireError(request, msg.errorMsg);
+        break;
+    }
+  },
+};
+
+function PaymentContentHelperService() {
+};
+
+PaymentContentHelperService.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentContentHelperService]),
+  classID: Components.ID("{80035846-6732-4fcc-961b-f336b65218f4}"),
+  contractID: "@mozilla.org/payment/content-helper-service;1",
+
+  _xpcom_factory: XPCOMUtils.generateSingletonFactory(PaymentContentHelperService),
+
+  // keys are windows and values are PaymentContentHelpers
+  helpers: new WeakMap(),
 
   // nsINavigatorPayment
+  pay: function pay(aWindow, aJwts) {
+    let requestHelper = this.helpers.get(aWindow);
+    if (!requestHelper) {
+      requestHelper = new PaymentContentHelper(aWindow);
+      this.helpers.set(aWindow, requestHelper);
+    }
+    let request = requestHelper.createRequest();
+    let requestId = requestHelper.getRequestId(request);
 
-  pay: function pay(aJwts) {
-    let request = this.createRequest();
-    let requestId = this.getRequestId(request);
-
-    let docShell = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
+    let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIWebNavigation)
                    .QueryInterface(Ci.nsIDocShell);
     if (!docShell.isActive) {
-      if (this._debug) {
-        this.LOG("The caller application is a background app. No request " +
-                  "will be sent");
+      if (_debug) {
+        LOG("The caller application is a background app. No request will be " +
+            "sent");
       }
+
       let runnable = {
         run: function run() {
           Services.DOMRequest.fireError(request, "BACKGROUND_APP");
         }
       }
       Services.tm.currentThread.dispatch(runnable,
                                          Ci.nsIThread.DISPATCH_NORMAL);
       return request;
@@ -70,66 +110,11 @@ PaymentContentHelper.prototype = {
     }
 
     cpmm.sendAsyncMessage("Payment:Pay", {
       jwts: aJwts,
       requestId: requestId
     });
     return request;
   },
-
-  // nsIDOMGlobalPropertyInitializer
-
-  init: function(aWindow) {
-    try {
-      if (!Services.prefs.getBoolPref("dom.mozPay.enabled")) {
-        return null;
-      }
-    } catch (e) {
-      return null;
-    }
-
-    this._window = aWindow;
-    this.initDOMRequestHelper(aWindow, PAYMENT_IPC_MSG_NAMES);
-
-    try {
-      this._debug =
-        Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
-        && Services.prefs.getBoolPref(PREF_DEBUG);
-    } catch(e) {
-      this._debug = false;
-    }
-
-    return Cu.exportFunction(this.pay.bind(this), aWindow);
-  },
-
-  // nsIFrameMessageListener
-
-  receiveMessage: function receiveMessage(aMessage) {
-    let name = aMessage.name;
-    let msg = aMessage.json;
-    if (this._debug) {
-      this.LOG("Received message '" + name + "': " + JSON.stringify(msg));
-    }
-    let requestId = msg.requestId;
-    let request = this.takeRequest(requestId);
-    if (!request) {
-      return;
-    }
-    switch (name) {
-      case "Payment:Success":
-        Services.DOMRequest.fireSuccess(request, msg.result);
-        break;
-      case "Payment:Failed":
-        Services.DOMRequest.fireError(request, msg.errorMsg);
-        break;
-    }
-  },
-
-  LOG: function LOG(s) {
-    if (!this._debug) {
-      return;
-    }
-    dump("-*- PaymentContentHelper: " + s + "\n");
-  }
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentContentHelper]);
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentContentHelperService]);
--- a/dom/payment/Payment.manifest
+++ b/dom/payment/Payment.manifest
@@ -1,9 +1,8 @@
-component {a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0} Payment.js
-contract @mozilla.org/payment/content-helper;1 {a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0}
-category JavaScript-navigator-property mozPay @mozilla.org/payment/content-helper;1
+component {80035846-6732-4fcc-961b-f336b65218f4} Payment.js
+contract @mozilla.org/payment/content-helper-service;1 {80035846-6732-4fcc-961b-f336b65218f4}
 
 component {b8bce4e7-fbf0-4719-a634-b1bf9018657c} PaymentFlowInfo.js
 contract @mozilla.org/payment/flow-info;1 {b8bce4e7-fbf0-4719-a634-b1bf9018657c}
 
 component {82144756-72ab-45b7-8621-f3dad431dd2f} PaymentProvider.js
 contract @mozilla.org/payment/provider;1 {82144756-72ab-45b7-8621-f3dad431dd2f}
--- a/dom/payment/interfaces/moz.build
+++ b/dom/payment/interfaces/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
-    'nsINavigatorPayment.idl',
+    'nsIPaymentContentHelperService.idl',
     'nsIPaymentFlowInfo.idl',
     'nsIPaymentProviderStrategy.idl',
     'nsIPaymentUIGlue.idl',
 ]
 
 XPIDL_MODULE = 'dom_payment'
 
rename from dom/payment/interfaces/nsINavigatorPayment.idl
rename to dom/payment/interfaces/nsIPaymentContentHelperService.idl
--- a/dom/payment/interfaces/nsINavigatorPayment.idl
+++ b/dom/payment/interfaces/nsIPaymentContentHelperService.idl
@@ -1,17 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
 interface nsIDOMDOMRequest;
+interface mozIDOMWindow;
 
-[scriptable, uuid(44fb7308-7d7b-4975-8a27-e01fe9623bdb)]
-interface nsINavigatorPayment : nsISupports
+[scriptable, uuid(80035846-6732-4fcc-961b-f336b65218f4)]
+interface nsIPaymentContentHelperService : nsISupports
 {
   // The 'jwts' parameter can be either a single DOMString or an array of
   // DOMStrings. In both cases, it represents the base64url encoded and
   // digitally signed payment information. Each payment provider should
   // define its supported JWT format.
-  nsIDOMDOMRequest pay(in jsval jwts);
+  nsIDOMDOMRequest pay(in mozIDOMWindow window, in jsval jwts);
 };
rename from testing/specialpowers/content/MockPaymentsUIGlue.jsm
rename to dom/payment/tests/mochitest/MockPaymentsUIChromeScript.js
--- a/testing/specialpowers/content/MockPaymentsUIGlue.jsm
+++ b/dom/payment/tests/mochitest/MockPaymentsUIChromeScript.js
@@ -1,110 +1,91 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-this.EXPORTED_SYMBOLS = ["MockPaymentsUIGlue"];
-
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cm = Components.manager;
 const Cu = Components.utils;
 
 const CONTRACT_ID = "@mozilla.org/payment/ui-glue;1";
 
-Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
-var classID;
-var oldFactory;
-var newFactory = function(window) {
-  return {
-    createInstance: function(aOuter, aIID) {
-      if (aOuter) {
-        throw Components.results.NS_ERROR_NO_AGGREGATION;
-      }
-      return new MockPaymentsUIGlueInstance(window).QueryInterface(aIID);
-    },
-    lockFactory: function(aLock) {
-      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-    },
-    QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
-  };
+var oldClassID, oldFactory;
+var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
+var newFactory = {
+  createInstance: function(aOuter, aIID) {
+    if (aOuter) {
+      throw Components.results.NS_ERROR_NO_AGGREGATION;
+    }
+    return new MockPaymentsUIGlueInstance().QueryInterface(aIID);
+  },
+  lockFactory: function(aLock) {
+    throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
 };
 
-this.MockPaymentsUIGlue = {
-  init: function(aWindow) {
-    try {
-      classID = registrar.contractIDToCID(CONTRACT_ID);
-      oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
-    } catch (ex) {
-      oldClassID = "";
-      oldFactory = null;
-      dump("TEST-INFO | can't get payments ui glue registered component, " +
-          "assuming there is none");
-    }
-    if (oldFactory) {
-      registrar.unregisterFactory(classID, oldFactory);
-    }
-    registrar.registerFactory(classID, "", CONTRACT_ID,
-                              new newFactory(aWindow));
-  },
+addMessageListener("MockPaymentsUIGlue.init", function (message) {
+  try {
+    oldClassID = registrar.contractIDToCID(CONTRACT_ID);
+    oldFactory = Cm.getClassObject(oldClassID, Ci.nsIFactory);
+  } catch (ex) {
+    oldClassID = "";
+    oldFactory = null;
+    dump("TEST-INFO | can't get payments ui glue registered component, " +
+         "assuming there is none\n");
+  }
+  if (oldFactory) {
+    registrar.unregisterFactory(oldClassID, oldFactory);
+  }
+  registrar.registerFactory(newClassID, "", CONTRACT_ID, newFactory);});
 
-  reset: function() {
-  },
+addMessageListener("MockPaymentsUIGlue.cleanup", function (message) {
+  if (oldClassID) {
+    registrar.registerFactory(oldClassID, "", CONTRACT_ID, null);
+  }
+});
 
-  cleanup: function() {
-    this.reset();
-    if (oldFactory) {
-      registrar.unregisterFactory(classID, newFactory);
-      registrar.registerFactory(classID, "", CONTRACT_ID, oldFactory);
-    }
-  }
-};
+var payments = new Map();
 
-function MockPaymentsUIGlueInstance(aWindow) {
-  this.window = aWindow;
+function MockPaymentsUIGlueInstance() {
 };
 
 MockPaymentsUIGlueInstance.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue]),
 
   confirmPaymentRequest: function(aRequestId,
                                   aRequests,
                                   aSuccessCb,
                                   aErrorCb) {
     aSuccessCb.onresult(aRequestId, aRequests[0].type);
   },
 
   showPaymentFlow: function(aRequestId,
                             aPaymentFlowInfo,
                             aErrorCb) {
-    let document = this.window.document;
-    let frame = document.createElement("iframe");
-    frame.setAttribute("mozbrowser", true);
-    frame.setAttribute("remote", true);
-    document.body.appendChild(frame);
-    let docshell = frame.contentWindow
-                        .QueryInterface(Ci.nsIInterfaceRequestor)
-                        .getInterface(Ci.nsIWebNavigation)
-                        .QueryInterface(Ci.nsIDocShell);
+    let win = Services.ww.openWindow(null,
+                                     null,
+                                     "_blank",
+                                     "chrome,dialog=no,resizable,scrollbars,centerscreen",
+                                     null);
+
+    payments.set(aRequestId, win);
+    let docshell = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                      .getInterface(Ci.nsIWebNavigation)
+                      .QueryInterface(Ci.nsIDocShell);
     docshell.paymentRequestId = aRequestId;
-    frame.src = aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt;
+
+    win.document.location = aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt;
   },
 
   closePaymentFlow: function(aRequestId) {
+    payments.get(aRequestId).close();
+    payments.delete(aRequestId);
+
     return Promise.resolve();
-  }
+  },
 };
-// Expose everything to content. We call reset() here so that all of the relevant
-// lazy expandos get added.
-MockPaymentsUIGlue.reset();
-function exposeAll(obj) {
-  var props = {};
-  for (var prop in obj)
-    props[prop] = 'rw';
-  obj.__exposedProps__ = props;
-}
-exposeAll(MockPaymentsUIGlue);
-exposeAll(MockPaymentsUIGlueInstance.prototype);
--- a/dom/payment/tests/mochitest/mochitest.ini
+++ b/dom/payment/tests/mochitest/mochitest.ini
@@ -1,12 +1,11 @@
 [DEFAULT]
-skip-if=true # This test uses MockPaymentsUIGlue which uses __exposedProps__
-             # we need to move this to a chrome test, but these are not
-             # available in b2g or android for now.
+skip-if=buildapp != 'b2g' && toolkit != 'android'
 
 support-files=
   file_mozpayproviderchecker.html
   file_payprovidersuccess.html
   file_payproviderfailure.html
+  MockPaymentsUIChromeScript.js
 
 [test_mozpaymentprovider.html]
 [test_mozpay_callbacks.html]
--- a/dom/payment/tests/mochitest/test_mozpay_callbacks.html
+++ b/dom/payment/tests/mochitest/test_mozpay_callbacks.html
@@ -74,32 +74,36 @@ function runTest() {
   if (!tests.length) {
     ok(true, "Done!");
     SimpleTest.finish();
     return;
   }
   tests.shift()();
 }
 
-SpecialPowers.MockPaymentsUIGlue.init(window);
+const uiGlue = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('MockPaymentsUIChromeScript.js'));
+SimpleTest.registerCleanupFunction(() => {
+ uiGlue.sendAsyncMessage("MockPaymentsUIGlue.cleanup", {});
+});
+uiGlue.sendAsyncMessage("MockPaymentsUIGlue.init", {});
 
 SpecialPowers.pushPrefEnv({
   "set": [
     ["dom.payment.skipHTTPSCheck", "true"],
     ["dom.payment.debug", "true"],
     ["dom.payment.provider.1.name", "SuccessProvider"],
     ["dom.payment.provider.1.description", ""],
     ["dom.payment.provider.1.uri",
-     "http://mochi.test:8888/tests/dom/payment/tests/mochitest/file_payprovidersuccess.html?req="],
+     "https://example.com:443/tests/dom/payment/tests/mochitest/file_payprovidersuccess.html?req="],
     ["dom.payment.provider.1.type", "mozilla/payments/test/success"],
     ["dom.payment.provider.1.requestMethod", "GET"],
     ["dom.payment.provider.2.name", "FailureProvider"],
     ["dom.payment.provider.2.description", ""],
     ["dom.payment.provider.2.uri",
-     "http://mochi.test:8888/tests/dom/payment/tests/mochitest/file_payproviderfailure.html?req="],
+     "https://example.com:443/tests/dom/payment/tests/mochitest/file_payproviderfailure.html?req="],
     ["dom.payment.provider.2.type", "mozilla/payments/test/failure"],
     ["dom.payment.provider.2.requestMethod", "GET"],
   ]
   }, () => {
     runTest();
   });
 
 </script>
--- a/dom/permission/tests/test_networkstats-manage.html
+++ b/dom/permission/tests/test_networkstats-manage.html
@@ -15,17 +15,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none"></div>
 <pre id="test">
 <script type="application/javascript;version=1.8" src="file_framework.js"></script>
 <script type="application/javascript;version=1.8">
 var gData = [
   {
     perm: ["networkstats-manage"],
     obj: "mozNetworkStats",
-    idl: "nsIDOMMozNetworkStatsManager",
+    webidl: "MozNetworkStatsManager",
     settings: [["dom.mozNetworkStats.enabled", true]],
   },
 ]
 </script>
 </pre>
 </body>
 </html>
 
--- a/dom/plugins/test/crashtests/crashtests.list
+++ b/dom/plugins/test/crashtests/crashtests.list
@@ -1,13 +1,13 @@
 load 41276-1.html
 load 48856-1.html
 load 110650-1.html
 skip-if(!haveTestPlugin) script 539897-1.html
-skip-if(!haveTestPlugin) script 540114-1.html
+asserts(0-1) skip-if(!haveTestPlugin) script 540114-1.html
 load 570884.html
 # This test relies on the reading of screenX/Y forcing a round trip to
 # the X server, which is a bad assumption for <browser remote>.
 # Plugin arch is going to change anyway with OOP content so skipping
 # this test for now is OK.
 skip-if(!haveTestPlugin||http.platform!="X11") load 598862.html
 skip-if(Android) load 626602-1.html # bug 908363
 load 752340.html
--- a/dom/svg/SVGFEConvolveMatrixElement.cpp
+++ b/dom/svg/SVGFEConvolveMatrixElement.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFEConvolveMatrixElement.h"
 #include "mozilla/dom/SVGFEConvolveMatrixElementBinding.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/UniquePtrExtensions.h"
 #include "DOMSVGAnimatedNumberList.h"
 #include "nsSVGUtils.h"
 #include "nsSVGFilterInstance.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEConvolveMatrix)
 
 using namespace mozilla::gfx;
 
@@ -198,17 +200,17 @@ SVGFEConvolveMatrixElement::GetPrimitive
       return failureDescription;
   } else {
     targetY = orderY / 2;
   }
 
   if (orderX > NS_SVG_OFFSCREEN_MAX_DIMENSION ||
       orderY > NS_SVG_OFFSCREEN_MAX_DIMENSION)
     return failureDescription;
-  nsAutoArrayPtr<float> kernel(new (fallible) float[orderX * orderY]);
+  UniquePtr<float[]> kernel = MakeUniqueFallible<float[]>(orderX * orderY);
   if (!kernel)
     return failureDescription;
   for (uint32_t i = 0; i < kmLength; i++) {
     kernel[kmLength - 1 - i] = kernelMatrix[i];
   }
 
   float divisor;
   if (mNumberAttributes[DIVISOR].IsExplicitlySet()) {
--- a/dom/telephony/ipc/TelephonyChild.cpp
+++ b/dom/telephony/ipc/TelephonyChild.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TelephonyChild.h"
 
 #include "mozilla/dom/telephony/TelephonyDialCallback.h"
+#include "mozilla/UniquePtr.h"
 #include "TelephonyIPCService.h"
 
 USING_TELEPHONY_NAMESPACE
 
 /*******************************************************************************
  * TelephonyChild
  ******************************************************************************/
 
@@ -207,22 +208,23 @@ TelephonyRequestChild::DoResponse(const 
       break;
     case AdditionalInformation::Tuint16_t:
       callback->NotifyDialMMISuccessWithInteger(statusMessage, info.get_uint16_t());
       break;
     case AdditionalInformation::TArrayOfnsString: {
       uint32_t count = info.get_ArrayOfnsString().Length();
       const nsTArray<nsString>& additionalInformation = info.get_ArrayOfnsString();
 
-      nsAutoArrayPtr<const char16_t*> additionalInfoPtrs(new const char16_t*[count]);
+      auto additionalInfoPtrs = MakeUnique<const char16_t*[]>(count);
       for (size_t i = 0; i < count; ++i) {
         additionalInfoPtrs[i] = additionalInformation[i].get();
       }
 
-      callback->NotifyDialMMISuccessWithStrings(statusMessage, count, additionalInfoPtrs);
+      callback->NotifyDialMMISuccessWithStrings(statusMessage, count,
+                                                additionalInfoPtrs.get());
       break;
     }
     case AdditionalInformation::TArrayOfnsMobileCallForwardingOptions: {
       uint32_t count = info.get_ArrayOfnsMobileCallForwardingOptions().Length();
 
       nsTArray<nsCOMPtr<nsIMobileCallForwardingOptions>> results;
       for (uint32_t i = 0; i < count; i++) {
         // Use dont_AddRef here because these instances are already AddRef-ed in
--- a/dom/tests/mochitest/chrome/chrome.ini
+++ b/dom/tests/mochitest/chrome/chrome.ini
@@ -32,19 +32,21 @@ support-files =
 [test_DOMWindowCreated.xul]
 [test_DOM_element_instanceof.xul]
 [test_activation.xul]
 [test_bug799299.xul]
 [test_bug800817.xul]
 [test_bug830396.xul]
 [test_bug830858.xul]
 [test_bug1224790-1.xul]
-skip-if = os != 'cocoa'
+# synthesizeNativeOSXClick does not work on 10.6
+skip-if = os != 'mac' || os_version == '10.6'
 [test_bug1224790-2.xul]
-skip-if = os != 'cocoa'
+# synthesizeNativeOSXClick does not work on 10.6
+skip-if = os != 'mac' || os_version == '10.6'
 [test_callback_wrapping.xul]
 [test_clonewrapper.xul]
 [test_cyclecollector.xul]
 [test_docshell_swap.xul]
 [test_focus.xul]
 skip-if = buildapp == 'mulet'
 [test_focus_docnav.xul]
 [test_focus_switchbinding.xul]
--- a/dom/tests/mochitest/general/test_WebKitCSSMatrix.html
+++ b/dom/tests/mochitest/general/test_WebKitCSSMatrix.html
@@ -303,9 +303,24 @@ test(function() {
   assert_true(RoughCompareMatrix(m1r, m2r), "skewY should return the same result as DOMMatrixReadOnly.");
   assert_true(CompareMatrix(m1, m3), "skewY should not mutate original matrix.");
 }, "Test skewY.");
 
 test(function() {
   var m = new WebKitCSSMatrix("matrix(1,0,0,0,0,0)");
   assert_throws("NotSupportedError", function() { m.inverse(); }, "Inverting an invertible matrix should throw.")
 }, "Test that inverting an invertible matrix throws.");
+
+test(function() {
+  var m1 = new WebKitCSSMatrix("translate(10px, 10px)");
+  var m2 = new DOMMatrix();
+  m2.translateSelf(10, 10);
+  assert_true(RoughCompareMatrix(m1, m2), "translate in constructor should result in translated matrix");
+
+  assert_throws("SyntaxError", function() { new WebKitCSSMatrix("translate(10em, 10em)"); }, "Transform function may not contain relative units.")
+  assert_throws("SyntaxError", function() { new WebKitCSSMatrix("translate(10%, 10%)"); }, "Transform function may not contain percentage.")
+}, "Test constructor with translate");
+
+test(function() {
+  assert_throws("SyntaxError", function() { new WebKitCSSMatrix("initial"); }, "initial is not a valid constructor argument.")
+  assert_throws("SyntaxError", function() { new WebKitCSSMatrix("inherit"); }, "inherit is not a valid constructor arugment.")
+}, "Test invalid constructor arguments.");
 </script>
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -273,17 +273,17 @@ partial interface Document {
     [Constant]
     readonly attribute DOMStringList styleSheetSets;
     void enableStyleSheetsForSet (DOMString? name);
 };
 
 // http://dev.w3.org/csswg/cssom-view/#extensions-to-the-document-interface
 partial interface Document {
     Element? elementFromPoint (float x, float y);
-
+    sequence<Element> elementsFromPoint (float x, float y);
     CaretPosition? caretPositionFromPoint (float x, float y);
 
     [Pref="dom.document.scrollingElement.enabled"]
     readonly attribute Element? scrollingElement;
 };
 
 // http://dvcs.w3.org/hg/undomanager/raw-file/tip/undomanager.html
 partial interface Document {
--- a/dom/webidl/MozNetworkStats.webidl
+++ b/dom/webidl/MozNetworkStats.webidl
@@ -9,25 +9,25 @@
 dictionary NetworkStatsGetOptions
 {
   /**
    * App manifest URL is used to filter network stats by app, while service type
    * is used to filter stats by system service.
    * Note that, these two options cannot be specified at the same time for now;
    * others, an NS_ERROR_NOT_IMPLMENTED exception will be thrown.
    */
-  DOMString appManifestURL;
-  DOMString serviceType;
+  DOMString? appManifestURL = null;
+  DOMString serviceType = "";
   /**
    * If it is set as true, only the browsing traffic, which is generated from
    * the mozbrowser iframe element within an app, is returned in result.
    * If it is set as false or not set, the total traffic, which is generated
    * from both the mozapp and mozbrowser iframe elements, is returned.
    */
-  boolean browsingTrafficOnly;
+  boolean browsingTrafficOnly = false;
 };
 
 dictionary NetworkStatsAlarmOptions
 {
   Date startTime;
   Date data;
 };
 
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozNetworkStatsManager.webidl
@@ -0,0 +1,96 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[NavigatorProperty="mozNetworkStats",
+ JSImplementation="@mozilla.org/networkStatsManager;1",
+ CheckAnyPermissions="networkstats-manage",
+ Pref="dom.mozNetworkStats.enabled"]
+interface MozNetworkStatsManager {
+  /**
+   * Constants for known interface types.
+   */
+  const long WIFI = 0;
+  const long MOBILE = 1;
+
+  /**
+   * Find samples between two dates start and end, both included.
+   *
+   * If options is provided, per-app or per-system service usage will be
+   * retrieved; otherwise the target will be overall system usage.
+   *
+   * If success, the request result will be an MozNetworkStats object.
+   */
+  DOMRequest getSamples(MozNetworkStatsInterface network,
+                        Date start,
+                        Date end,
+               optional NetworkStatsGetOptions options);
+
+  /**
+   * Install an alarm on a network. The network must be in the return of
+   * getAvailableNetworks() otherwise an "InvalidNetwork" exception will
+   * be raised.
+   *
+   * When total data usage reaches threshold bytes, a "networkstats-alarm"
+   * system message is sent to the application, where the optional parameter
+   * |data| must be a cloneable object.
+   *
+   * If success, the |result| field of the DOMRequest keeps the alarm Id.
+   */
+  DOMRequest addAlarm(MozNetworkStatsInterface network,
+                      long long threshold,
+             optional NetworkStatsAlarmOptions options);
+
+  /**
+   * Obtain all alarms for those networks returned by getAvailableNetworks().
+   * If a network is provided, only retrieves the alarms for that network.
+   * The network must be one of those returned by getAvailebleNetworks() or an
+   * "InvalidNetwork" exception will be raised.
+   *
+   * Each alarm object has the same fields as that in the system message:
+   *  - alarmId
+   *  - network
+   *  - threshold
+   *  - data
+   */
+  DOMRequest getAllAlarms(optional MozNetworkStatsInterface network);
+
+  /**
+   * Remove all network alarms. If an |alarmId| is provided, then only that
+   * alarm is removed.
+   */
+  DOMRequest removeAlarms(optional unsigned long alarmId = 0);
+
+  /**
+   * Remove all stats related with the provided network from DB.
+   */
+  DOMRequest clearStats(MozNetworkStatsInterface network);
+
+  /**
+   * Remove all stats in the database.
+   */
+  DOMRequest clearAllStats();
+
+  /**
+   * Return available networks that used to be saved in the database.
+   */
+  DOMRequest getAvailableNetworks(); // array of MozNetworkStatsInterface.
+
+  /**
+   * Return available service types that used to be saved in the database.
+   */
+  DOMRequest getAvailableServiceTypes(); // array of string.
+
+  /**
+   * Minimum time in milliseconds between samples stored in the database.
+   */
+  readonly attribute long sampleRate;
+
+  /**
+   * Time in milliseconds recorded by the API until present time. All samples
+   * older than maxStorageAge from now are deleted.
+   */
+  readonly attribute long long maxStorageAge;
+};
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -460,8 +460,19 @@ partial interface Navigator {
 #endif
 
 #ifdef NIGHTLY_BUILD
 partial interface Navigator {
   [Func="Navigator::IsE10sEnabled"]
   readonly attribute boolean mozE10sEnabled;
 };
 #endif
+
+#ifdef MOZ_PAY
+partial interface Navigator {
+  [Throws, NewObject, Pref="dom.mozPay.enabled"]
+  // The 'jwts' parameter can be either a single DOMString or an array of
+  // DOMStrings. In both cases, it represents the base64url encoded and
+  // digitally signed payment information. Each payment provider should
+  // define its supported JWT format.
+  DOMRequest mozPay(any jwts);
+};
+#endif
--- a/dom/webidl/Performance.webidl
+++ b/dom/webidl/Performance.webidl
@@ -12,19 +12,16 @@
 
 typedef double DOMHighResTimeStamp;
 typedef sequence <PerformanceEntry> PerformanceEntryList;
 
 [Exposed=(Window,Worker)]
 interface Performance {
   [DependsOn=DeviceState, Affects=Nothing]
   DOMHighResTimeStamp now();
-
-  [Throws]
-  DOMHighResTimeStamp translateTime(DOMHighResTimeStamp time, (Window or Worker or SharedWorker or ServiceWorker) timeSource);
 };
 
 [Exposed=Window]
 partial interface Performance {
   [Constant]
   readonly attribute PerformanceTiming timing;
   [Constant]
   readonly attribute PerformanceNavigation navigation;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -745,16 +745,17 @@ if CONFIG['MOZ_SECUREELEMENT']:
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     WEBIDL_FILES += [
         'MozNetworkStats.webidl',
         'MozNetworkStatsAlarm.webidl',
         'MozNetworkStatsData.webidl',
         'MozNetworkStatsInterface.webidl',
+        'MozNetworkStatsManager.webidl',
         'MozSpeakerManager.webidl',
         'MozWifiCapabilities.webidl',
         'MozWifiManager.webidl',
         'MozWifiP2pManager.webidl',
     ]
 else:
     WEBIDL_FILES += [
         'InstallTrigger.webidl',
--- a/dom/workers/Performance.cpp
+++ b/dom/workers/Performance.cpp
@@ -27,17 +27,17 @@ Performance::WrapObject(JSContext* aCx, 
 {
   return PerformanceBinding_workers::Wrap(aCx, this, aGivenProto);
 }
 
 DOMHighResTimeStamp
 Performance::Now() const
 {
   TimeDuration duration =
-    TimeStamp::Now() - mWorkerPrivate->CreationTimeStamp();
+    TimeStamp::Now() - mWorkerPrivate->NowBaseTimeStamp();
   return RoundTime(duration.ToMilliseconds());
 }
 
 // To be removed once bug 1124165 lands
 bool
 Performance::IsPerformanceTimingAttribute(const nsAString& aName)
 {
   // In workers we just support navigationStart.
@@ -47,17 +47,17 @@ Performance::IsPerformanceTimingAttribut
 DOMHighResTimeStamp
 Performance::GetPerformanceTimingFromString(const nsAString& aProperty)
 {
   if (!IsPerformanceTimingAttribute(aProperty)) {
     return 0;
   }
 
   if (aProperty.EqualsLiteral("navigationStart")) {
-    return mWorkerPrivate->CreationTime();
+    return mWorkerPrivate->NowBaseTime();
   }
 
   MOZ_CRASH("IsPerformanceTimingAttribute and GetPerformanceTimingFromString are out of sync");
   return 0;
 }
 
 void
 Performance::InsertUserEntry(PerformanceEntry* aEntry)
@@ -72,23 +72,23 @@ Performance::InsertUserEntry(Performance
     PerformanceBase::LogEntry(aEntry, uri);
   }
   PerformanceBase::InsertUserEntry(aEntry);
 }
 
 TimeStamp
 Performance::CreationTimeStamp() const
 {
-  return mWorkerPrivate->CreationTimeStamp();
+  return mWorkerPrivate->NowBaseTimeStamp();
 }
 
 DOMHighResTimeStamp
 Performance::CreationTime() const
 {
-  return mWorkerPrivate->CreationTime();
+  return mWorkerPrivate->NowBaseTime();
 }
 
 void
 Performance::DispatchBufferFullEvent()
 {
   // This method is needed just for InsertResourceEntry, but this method is not
   // exposed to workers.
   MOZ_CRASH("This should not be called.");
--- a/dom/workers/ServiceWorker.cpp
+++ b/dom/workers/ServiceWorker.cpp
@@ -96,18 +96,11 @@ ServiceWorker::PostMessage(JSContext* aC
     return;
   }
 
   UniquePtr<ServiceWorkerClientInfo> clientInfo(new ServiceWorkerClientInfo(window->GetExtantDoc()));
   ServiceWorkerPrivate* workerPrivate = mInfo->WorkerPrivate();
   aRv = workerPrivate->SendMessageEvent(aCx, aMessage, aTransferable, Move(clientInfo));
 }
 
-WorkerPrivate*
-ServiceWorker::GetWorkerPrivate() const
-{
-  ServiceWorkerPrivate* workerPrivate = mInfo->WorkerPrivate();
-  return workerPrivate->GetWorkerPrivate();
-}
-
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/ServiceWorker.h
+++ b/dom/workers/ServiceWorker.h
@@ -62,19 +62,16 @@ public:
 #undef PostMessage
 #endif
 
   void
   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
               const Optional<Sequence<JS::Value>>& aTransferable,
               ErrorResult& aRv);
 
-  WorkerPrivate*
-  GetWorkerPrivate() const;
-
 private:
   // This class can only be created from the ServiceWorkerManager.
   ServiceWorker(nsPIDOMWindowInner* aWindow, ServiceWorkerInfo* aInfo);
 
   // This class is reference-counted and will be destroyed from Release().
   ~ServiceWorker();
 
   ServiceWorkerState mState;
--- a/dom/workers/ServiceWorkerPrivate.h
+++ b/dom/workers/ServiceWorkerPrivate.h
@@ -121,22 +121,16 @@ public:
   TerminateWorker();
 
   void
   NoteDeadServiceWorkerInfo();
 
   void
   NoteStoppedControllingDocuments();
 
-  WorkerPrivate*
-  GetWorkerPrivate() const
-  {
-    return mWorkerPrivate;
-  }
-
   void
   Activated();
 
   nsresult
   GetDebugger(nsIWorkerDebugger** aResult);
 
   nsresult
   AttachDebugger();
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2218,21 +2218,35 @@ WorkerPrivateParent<Derived>::WorkerPriv
   mLoadInfo.StealFrom(aLoadInfo);
 
   if (aParent) {
     aParent->AssertIsOnWorkerThread();
 
     aParent->CopyJSSettings(mJSSettings);
 
     MOZ_ASSERT(IsDedicatedWorker());
+    mNowBaseTimeStamp = aParent->NowBaseTimeStamp();
+    mNowBaseTimeHighRes = aParent->NowBaseTime();
   }
   else {
     AssertIsOnMainThread();
 
     RuntimeService::GetDefaultJSSettings(mJSSettings);
+
+    if (IsDedicatedWorker() && mLoadInfo.mWindow &&
+        mLoadInfo.mWindow->GetPerformance()) {
+      mNowBaseTimeStamp = mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
+        GetNavigationStartTimeStamp();
+      mNowBaseTimeHighRes =
+      mLoadInfo.mWindow->GetPerformance()->GetDOMTiming()->
+        GetNavigationStartHighRes();
+    } else {
+      mNowBaseTimeStamp = CreationTimeStamp();
+      mNowBaseTimeHighRes = CreationTime();
+    }
   }
 }
 
 template <class Derived>
 WorkerPrivateParent<Derived>::~WorkerPrivateParent()
 {
   DropJSObjects(this);
 }
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -187,16 +187,18 @@ private:
   Status mParentStatus;
   bool mParentFrozen;
   bool mParentSuspended;
   bool mIsChromeWorker;
   bool mMainThreadObjectsForgotten;
   WorkerType mWorkerType;
   TimeStamp mCreationTimeStamp;
   DOMHighResTimeStamp mCreationTimeHighRes;
+  TimeStamp mNowBaseTimeStamp;
+  DOMHighResTimeStamp mNowBaseTimeHighRes;
 
 protected:
   // The worker is owned by its thread, which is represented here.  This is set
   // in Construct() and emptied by WorkerFinishedRunnable, and conditionally
   // traversed by the cycle collector if the busy count is zero.
   RefPtr<WorkerPrivate> mSelfRef;
 
   WorkerPrivateParent(JSContext* aCx, WorkerPrivate* aParent,
@@ -548,16 +550,26 @@ public:
     return mCreationTimeStamp;
   }
 
   DOMHighResTimeStamp CreationTime() const
   {
     return mCreationTimeHighRes;
   }
 
+  TimeStamp NowBaseTimeStamp() const
+  {
+    return mNowBaseTimeStamp;
+  }
+
+  DOMHighResTimeStamp NowBaseTime() const
+  {
+    return mNowBaseTimeHighRes;
+  }
+
   nsIPrincipal*
   GetPrincipal() const
   {
     AssertIsOnMainThread();
     return mLoadInfo.mPrincipal;
   }
 
   nsILoadGroup*
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -432,18 +432,22 @@ DedicatedWorkerGlobalScope::WrapGlobalOb
                              xpc::ShouldDiscardSystemSource();
   const bool extraWarnings = usesSystemPrincipal &&
                              xpc::ExtraWarningsForSystemJS();
 
   JS::CompartmentBehaviors& behaviors = options.behaviors();
   behaviors.setDiscardSource(discardSource)
            .extraWarningsOverride().set(extraWarnings);
 
+  const bool inCertifiedApp = mWorkerPrivate->IsInCertifiedApp();
+  const bool sharedMemoryEnabled = xpc::SharedMemoryEnabled();
+
   JS::CompartmentCreationOptions& creationOptions = options.creationOptions();
-  creationOptions.setSharedMemoryAndAtomicsEnabled(xpc::SharedMemoryEnabled());
+  creationOptions.setSharedMemoryAndAtomicsEnabled(sharedMemoryEnabled)
+                 .setExperimentalDateTimeFormatFormatToPartsEnabled(inCertifiedApp);
 
   return DedicatedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this,
                                                          options,
                                                          GetWorkerPrincipal(),
                                                          true, aReflector);
 }
 
 void
--- a/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
+++ b/dom/xslt/xpath/txXPCOMExtensionFunction.cpp
@@ -12,18 +12,21 @@
 #include "txExpr.h"
 #include "txIFunctionEvaluationContext.h"
 #include "txIXPathContext.h"
 #include "txNodeSetAdaptor.h"
 #include "txXPathTreeWalker.h"
 #include "xptcall.h"
 #include "txXPathObjectAdaptor.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/UniquePtr.h"
+#include "nsContentUtils.h"
 #include "nsIClassInfo.h"
 #include "nsIInterfaceInfo.h"
+#include "js/RootingAPI.h"
 
 NS_IMPL_ISUPPORTS(txXPathObjectAdaptor, txIXPathObject)
 
 class txFunctionEvaluationContext final : public txIFunctionEvaluationContext
 {
 public:
     txFunctionEvaluationContext(txIEvalContext *aContext, nsISupports *aState);
 
@@ -290,33 +293,48 @@ txXPCOMExtensionFunctionCall::GetParamTy
         default:
         {
             // XXX Error!
             return eUNKNOWN;
         }
     }
 }
 
-class txParamArrayHolder
+class txParamArrayHolder : public JS::Traceable
 {
 public:
     txParamArrayHolder()
         : mCount(0)
     {
     }
+    txParamArrayHolder(txParamArrayHolder&& rhs)
+      : mArray(mozilla::Move(rhs.mArray))
+      , mCount(rhs.mCount)
+    {
+        rhs.mCount = 0;
+    }
     ~txParamArrayHolder();
 
     bool Init(uint8_t aCount);
     operator nsXPTCVariant*() const
     {
-      return mArray;
+      return mArray.get();
+    }
+
+    static void trace(txParamArrayHolder* holder, JSTracer* trc) { holder->trace(trc); }
+    void trace(JSTracer* trc) {
+        for (uint8_t i = 0; i < mCount; ++i) {
+            if (mArray[i].type == nsXPTType::T_JSVAL) {
+                JS::UnsafeTraceRoot(trc, &mArray[i].val.j, "txParam value");
+            }
+        }
     }
 
 private:
-    nsAutoArrayPtr<nsXPTCVariant> mArray;
+    mozilla::UniquePtr<nsXPTCVariant[]> mArray;
     uint8_t mCount;
 };
 
 txParamArrayHolder::~txParamArrayHolder()
 {
     uint8_t i;
     for (i = 0; i < mCount; ++i) {
         nsXPTCVariant &variant = mArray[i];
@@ -333,18 +351,22 @@ txParamArrayHolder::~txParamArrayHolder(
         }
     }
 }
 
 bool
 txParamArrayHolder::Init(uint8_t aCount)
 {
     mCount = aCount;
-    mArray = new nsXPTCVariant[mCount];
-    memset(mArray, 0, mCount * sizeof(nsXPTCVariant));
+    mArray = mozilla::MakeUnique<nsXPTCVariant[]>(mCount);
+    if (!mArray) {
+        return false;
+    }
+
+    memset(mArray.get(), 0, mCount * sizeof(nsXPTCVariant));
 
     return true;
 }
 
 nsresult
 txXPCOMExtensionFunctionCall::evaluate(txIEvalContext* aContext,
                                        txAExprResult** aResult)
 {
@@ -358,18 +380,18 @@ txXPCOMExtensionFunctionCall::evaluate(t
 
     const nsXPTMethodInfo *methodInfo;
     rv = info->GetMethodInfo(mMethodIndex, &methodInfo);
     NS_ENSURE_SUCCESS(rv, rv);
 
     uint8_t paramCount = methodInfo->GetParamCount();
     uint8_t inArgs = paramCount - 1;
 
-    txParamArrayHolder invokeParams;
-    if (!invokeParams.Init(paramCount)) {
+    JS::Rooted<txParamArrayHolder> invokeParams(nsContentUtils::RootingCxForThread());
+    if (!invokeParams.get().Init(paramCount)) {
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     const nsXPTParamInfo &paramInfo = methodInfo->GetParam(0);
     txArgumentType type = GetParamType(paramInfo, info);
     if (type == eUNKNOWN) {
         return NS_ERROR_FAILURE;
     }
@@ -380,17 +402,17 @@ txXPCOMExtensionFunctionCall::evaluate(t
         if (paramInfo.IsOut()) {
             // We don't support out values.
             return NS_ERROR_FAILURE;
         }
 
         // Create context wrapper.
         context = new txFunctionEvaluationContext(aContext, mState);
 
-        nsXPTCVariant &invokeParam = invokeParams[0];
+        nsXPTCVariant &invokeParam = invokeParams.get()[0];
         invokeParam.type = paramInfo.GetType();
         invokeParam.SetValNeedsCleanup();
         NS_ADDREF((txIFunctionEvaluationContext*&)invokeParam.val.p = context);
 
         // Skip first argument, since it's the context.
         paramStart = 1;
     }
     else {
@@ -407,17 +429,17 @@ txXPCOMExtensionFunctionCall::evaluate(t
         Expr* expr = mParams[i - paramStart];
 
         const nsXPTParamInfo &paramInfo = methodInfo->GetParam(i);
         txArgumentType type = GetParamType(paramInfo, info);
         if (type == eUNKNOWN) {
             return NS_ERROR_FAILURE;
         }
 
-        nsXPTCVariant &invokeParam = invokeParams[i];
+        nsXPTCVariant &invokeParam = invokeParams.get()[i];
         if (paramInfo.IsOut()) {
             // We don't support out values.
             return NS_ERROR_FAILURE;
         }
 
         invokeParam.type = paramInfo.GetType();
         switch (type) {
             case eNODESET:
@@ -495,31 +517,31 @@ txXPCOMExtensionFunctionCall::evaluate(t
     }
 
     const nsXPTParamInfo &returnInfo = methodInfo->GetParam(inArgs);
     txArgumentType returnType = GetParamType(returnInfo, info);
     if (returnType == eUNKNOWN) {
         return NS_ERROR_FAILURE;
     }
 
-    nsXPTCVariant &returnParam = invokeParams[inArgs];
+    nsXPTCVariant &returnParam = invokeParams.get()[inArgs];
     returnParam.type = returnInfo.GetType();
     if (returnType == eSTRING) {
         nsString *value = new nsString();
         returnParam.SetValNeedsCleanup();
         returnParam.val.p = value;
     }
     else {
         returnParam.SetIndirect();
         if (returnType == eNODESET || returnType == eOBJECT) {
             returnParam.SetValNeedsCleanup();
         }
     }
 
-    rv = NS_InvokeByIndex(mHelper, mMethodIndex, paramCount, invokeParams);
+    rv = NS_InvokeByIndex(mHelper, mMethodIndex, paramCount, invokeParams.get());
 
     // In case someone is holding on to the txFunctionEvaluationContext which
     // could thus stay alive longer than this function.
     if (context) {
         context->ClearContext();
     }
 
     NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -34,16 +34,17 @@
 #include "nsAttrName.h"
 #include "nsIScriptError.h"
 #include "nsIURL.h"
 #include "nsCORSListenerProxy.h"
 #include "nsError.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/EncodingUtils.h"
+#include "mozilla/UniquePtr.h"
 
 using namespace mozilla;
 using mozilla::dom::EncodingUtils;
 using mozilla::net::ReferrerPolicy;
 
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 
 static void
@@ -518,35 +519,35 @@ static nsresult
 handleNode(nsINode* aNode, txStylesheetCompiler* aCompiler)
 {
     nsresult rv = NS_OK;
     
     if (aNode->IsElement()) {
         dom::Element* element = aNode->AsElement();
 
         uint32_t attsCount = element->GetAttrCount();
-        nsAutoArrayPtr<txStylesheetAttr> atts;
+        UniquePtr<txStylesheetAttr[]> atts;
         if (attsCount > 0) {
-            atts = new txStylesheetAttr[attsCount];
+            atts = MakeUnique<txStylesheetAttr[]>(attsCount);
             uint32_t counter;
             for (counter = 0; counter < attsCount; ++counter) {
                 txStylesheetAttr& att = atts[counter];
                 const nsAttrName* name = element->GetAttrNameAt(counter);
                 att.mNamespaceID = name->NamespaceID();
                 att.mLocalName = name->LocalName();
                 att.mPrefix = name->GetPrefix();
                 element->GetAttr(att.mNamespaceID, att.mLocalName, att.mValue);
             }
         }
 
         mozilla::dom::NodeInfo *ni = element->NodeInfo();
 
         rv = aCompiler->startElement(ni->NamespaceID(),
                                      ni->NameAtom(),
-                                     ni->GetPrefixAtom(), atts,
+                                     ni->GetPrefixAtom(), atts.get(),
                                      attsCount);
         NS_ENSURE_SUCCESS(rv, rv);
 
         // explicitly destroy the attrs here since we no longer need it
         atts = nullptr;
 
         for (nsIContent* child = element->GetFirstChild();
              child;
--- a/dom/xslt/xslt/txStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txStylesheetCompiler.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Move.h"
+#include "mozilla/UniquePtr.h"
 
 #include "txStylesheetCompiler.h"
 #include "txStylesheetCompileHandlers.h"
 #include "nsGkAtoms.h"
 #include "txURIUtils.h"
 #include "nsWhitespaceTokenizer.h"
 #include "txStylesheet.h"
 #include "txInstructions.h"
@@ -119,19 +120,19 @@ txStylesheetCompiler::startElement(const
         // ignore content after failure
         // XXX reevaluate once expat stops on failure
         return NS_OK;
     }
 
     nsresult rv = flushCharacters();
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsAutoArrayPtr<txStylesheetAttr> atts;
+    UniquePtr<txStylesheetAttr[]> atts;
     if (aAttrCount > 0) {
-        atts = new txStylesheetAttr[aAttrCount];
+        atts = MakeUnique<txStylesheetAttr[]>(aAttrCount);
     }
 
     bool hasOwnNamespaceMap = false;
     int32_t i;
     for (i = 0; i < aAttrCount; ++i) {
         rv = XMLUtils::splitExpatName(aAttrs[i * 2],
                                       getter_AddRefs(atts[i].mPrefix),
                                       getter_AddRefs(atts[i].mLocalName),
@@ -164,17 +165,17 @@ txStylesheetCompiler::startElement(const
     }
 
     nsCOMPtr<nsIAtom> prefix, localname;
     int32_t namespaceID;
     rv = XMLUtils::splitExpatName(aName, getter_AddRefs(prefix),
                                   getter_AddRefs(localname), &namespaceID);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    return startElementInternal(namespaceID, localname, prefix, atts,
+    return startElementInternal(namespaceID, localname, prefix, atts.get(),
                                 aAttrCount);
 }
 
 nsresult
 txStylesheetCompiler::startElementInternal(int32_t aNamespaceID,
                                            nsIAtom* aLocalName,
                                            nsIAtom* aPrefix,
                                            txStylesheetAttr* aAttributes,
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -1768,24 +1768,16 @@ nsPermissionManager::AddInternal(nsIPrin
       entry->GetPermissions()[index].mID = id;
       entry->GetPermissions()[index].mPermission = aPermission;
       entry->GetPermissions()[index].mExpireType = aExpireType;
       entry->GetPermissions()[index].mExpireTime = aExpireTime;
       entry->GetPermissions()[index].mModificationTime = aModificationTime;
 
       // If requested, create the entry in the DB.
       if (aDBOperation == eWriteToDB) {
-        uint32_t appId;
-        rv = aPrincipal->GetAppId(&appId);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        bool isInBrowserElement;
-        rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
-        NS_ENSURE_SUCCESS(rv, rv);
-
         UpdateDB(eOperationAdding, mStmtInsert, id, origin, aType, aPermission,
                  aExpireType, aExpireTime, aModificationTime);
       }
 
       if (aNotifyOperation == eNotify) {
         NotifyObserversWithPermission(aPrincipal,
                                       mTypeArray[typeIndex],
                                       aPermission,
@@ -2943,9 +2935,8 @@ nsPermissionManager::FetchPermissions() 
     // will end up as now()) is fine.
     uint64_t modificationTime = 0;
     AddInternal(principal, perm.type, perm.capability, 0, perm.expireType,
                 perm.expireTime, modificationTime, eNotify, eNoDBOperation,
                 true /* ignoreSessionPermissions */);
   }
   return NS_OK;
 }
-
--- a/gfx/2d/Rect.h
+++ b/gfx/2d/Rect.h
@@ -179,18 +179,18 @@ struct RectTyped :
       NudgeToInteger(&(this->width));
       NudgeToInteger(&(this->height));
     }
 
     bool ToIntRect(IntRectTyped<units> *aOut) const
     {
       *aOut = IntRectTyped<units>(int32_t(this->X()), int32_t(this->Y()),
                                   int32_t(this->Width()), int32_t(this->Height()));
-      return RectTyped<units>(F(aOut->x), F(aOut->y),
-                              F(aOut->width), F(aOut->height))
+      return RectTyped<units, F>(F(aOut->x), F(aOut->y),
+                                 F(aOut->width), F(aOut->height))
              .IsEqualEdges(*this);
     }
 
     // XXX When all of the code is ported, the following functions to convert to and from
     // unknown types should be removed.
 
     static RectTyped<units, F> FromUnknownRect(const RectTyped<UnknownUnits, F>& rect) {
         return RectTyped<units, F>(rect.x, rect.y, rect.width, rect.height);
--- a/gfx/gl/SharedSurfaceEGL.cpp
+++ b/gfx/gl/SharedSurfaceEGL.cpp
@@ -135,16 +135,25 @@ SharedSurface_EGLImage::ProducerReleaseI
             return;
         }
     }
 
     MOZ_ASSERT(!mSync);
     mGL->fFinish();
 }
 
+void
+SharedSurface_EGLImage::ProducerReadAcquireImpl()
+{
+    // Wait on the fence, because presumably we're going to want to read this surface
+    if (mSync) {
+        mEGL->fClientWaitSync(Display(), mSync, 0, LOCAL_EGL_FOREVER);
+    }
+}
+
 EGLDisplay
 SharedSurface_EGLImage::Display() const
 {
     return mEGL->Display();
 }
 
 void
 SharedSurface_EGLImage::AcquireConsumerTexture(GLContext* consGL, GLuint* out_texture, GLuint* out_target)
--- a/gfx/gl/SharedSurfaceEGL.h
+++ b/gfx/gl/SharedSurfaceEGL.h
@@ -66,16 +66,19 @@ public:
     virtual layers::TextureFlags GetTextureFlags() const override;
 
     virtual void LockProdImpl() override {}
     virtual void UnlockProdImpl() override {}
 
     virtual void ProducerAcquireImpl() override {}
     virtual void ProducerReleaseImpl() override;
 
+    virtual void ProducerReadAcquireImpl() override;
+    virtual void ProducerReadReleaseImpl() override {};
+
     virtual GLuint ProdTexture() override {
       return mProdTex;
     }
 
     // Implementation-specific functions below:
     // Returns texture and target
     void AcquireConsumerTexture(GLContext* consGL, GLuint* out_texture, GLuint* out_target);
 
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -352,33 +352,54 @@ DecomposeIntoNoRepeatRects(const gfx::Re
            0.0f, 0.0f, br.x, br.y,
            flipped);
   return 4;
 }
 
 gfx::IntRect
 Compositor::ComputeBackdropCopyRect(const gfx::Rect& aRect,
                                     const gfx::Rect& aClipRect,
-                                    const gfx::Matrix4x4& aTransform)
+                                    const gfx::Matrix4x4& aTransform,
+                                    gfx::Matrix4x4* aOutTransform,
+                                    gfx::Rect* aOutLayerQuad)
 {
-  gfx::Rect renderBounds = mRenderBounds;
+  // Compute the clip.
+  gfx::IntPoint rtOffset = GetCurrentRenderTarget()->GetOrigin();
+  gfx::IntSize rtSize = GetCurrentRenderTarget()->GetSize();
 
-  // Compute the clip.
-  gfx::IntPoint offset = GetCurrentRenderTarget()->GetOrigin();
+  gfx::Rect renderBounds(0, 0, rtSize.width, rtSize.height);
   renderBounds.IntersectRect(renderBounds, aClipRect);
-  renderBounds.MoveBy(offset);
+  renderBounds.MoveBy(rtOffset);
 
   // Apply the layer transform.
-  gfx::Rect dest = aTransform.TransformAndClipBounds(aRect, renderBounds);
-  dest -= offset;
+  gfx::RectDouble dest = aTransform.TransformAndClipBounds(
+    gfx::RectDouble(aRect.x, aRect.y, aRect.width, aRect.height),
+    gfx::RectDouble(renderBounds.x, renderBounds.y, renderBounds.width, renderBounds.height));
+  dest -= rtOffset;
+
+  // Ensure we don't round out to -1, which trips up Direct3D.
+  dest.IntersectRect(dest, gfx::RectDouble(0, 0, rtSize.width, rtSize.height));
+
+  if (aOutLayerQuad) {
+    *aOutLayerQuad = gfx::Rect(dest.x, dest.y, dest.width, dest.height);
+  }
 
   // Round out to integer.
   gfx::IntRect result;
   dest.RoundOut();
   dest.ToIntRect(&result);
+
+  // Create a transform from adjusted clip space to render target space,
+  // translate it for the backdrop rect, then transform it into the backdrop's
+  // uv-space.
+  gfx::Matrix4x4 transform;
+  transform.PostScale(rtSize.width, rtSize.height, 1.0);
+  transform.PostTranslate(-result.x, -result.y, 0.0);
+  transform.PostScale(1 / float(result.width), 1 / float(result.height), 1.0);
+  *aOutTransform = transform;
   return result;
 }
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 void
 Compositor::SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget)
 {
   // OpenGL does not provide ReleaseFence for rendering.
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -513,21 +513,26 @@ protected:
                                uint32_t aFlashCounter);
 
   bool ShouldDrawDiagnostics(DiagnosticFlags);
 
   /**
    * Given a layer rect, clip, and transform, compute the area of the backdrop that
    * needs to be copied for mix-blending. The output transform translates from 0..1
    * space into the backdrop rect space.
+   *
+   * The transformed layer quad is also optionally returned - this is the same as
+   * the result rect, before rounding.
    */
   gfx::IntRect ComputeBackdropCopyRect(
     const gfx::Rect& aRect,
     const gfx::Rect& aClipRect,
-    const gfx::Matrix4x4& aTransform);
+    const gfx::Matrix4x4& aTransform,
+    gfx::Matrix4x4* aOutTransform,
+    gfx::Rect* aOutLayerQuad = nullptr);
 
   /**
    * Render time for the current composition.
    */
   TimeStamp mCompositionTime;
   /**
    * When nonnull, during rendering, some compositable indicated that it will
    * change its rendering at this time. In order not to miss it, we composite
@@ -547,18 +552,16 @@ protected:
   size_t mPixelsPerFrame;
   size_t mPixelsFilled;
 
   ScreenRotation mScreenRotation;
 
   RefPtr<gfx::DrawTarget> mTarget;
   gfx::IntRect mTargetBounds;
 
-  gfx::Rect mRenderBounds;
-
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   FenceHandle mReleaseFenceHandle;
 #endif
 
 private:
   static LayersBackend sBackend;
 
 };
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3144,16 +3144,17 @@ AsyncPanZoomController::ReportCheckerboa
   bool recordTrace = gfxPrefs::APZRecordCheckerboarding();
   bool forTelemetry = Telemetry::CanRecordExtended();
   uint32_t magnitude = GetCheckerboardMagnitude();
 
   MutexAutoLock lock(mCheckerboardEventLock);
   if (!mCheckerboardEvent && (recordTrace || forTelemetry)) {
     mCheckerboardEvent = MakeUnique<CheckerboardEvent>(recordTrace);
   }
+  mPotentialCheckerboardTracker.InTransform(IsTransformingState(mState));
   if (magnitude) {
     mPotentialCheckerboardTracker.CheckerboardSeen();
   }
   if (mCheckerboardEvent && mCheckerboardEvent->RecordFrameInfo(magnitude)) {
     // This checkerboard event is done. Report some metrics to telemetry.
     mozilla::Telemetry::Accumulate(mozilla::Telemetry::CHECKERBOARD_SEVERITY,
       mCheckerboardEvent->GetSeverity());
     mozilla::Telemetry::Accumulate(mozilla::Telemetry::CHECKERBOARD_PEAK,
@@ -3629,28 +3630,26 @@ void AsyncPanZoomController::DispatchSta
     ReentrantMonitorAutoEnter lock(mMonitor);
     if (mNotificationBlockers > 0) {
       return;
     }
   }
 
   if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
     if (!IsTransformingState(aOldState) && IsTransformingState(aNewState)) {
-      mPotentialCheckerboardTracker.TransformStarted();
       controller->NotifyAPZStateChange(
           GetGuid(), APZStateChange::TransformBegin);
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
       // Let the compositor know about scroll state changes so it can manage
       // windowed plugins.
       if (mCompositorParent) {
         mCompositorParent->ScheduleHideAllPluginWindows();
       }
 #endif
     } else if (IsTransformingState(aOldState) && !IsTransformingState(aNewState)) {
-      mPotentialCheckerboardTracker.TransformStopped();
       controller->NotifyAPZStateChange(
           GetGuid(), APZStateChange::TransformEnd);
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
       if (mCompositorParent) {
         mCompositorParent->ScheduleShowAllPluginWindows();
       }
 #endif
     }
--- a/gfx/layers/apz/src/PotentialCheckerboardDurationTracker.cpp
+++ b/gfx/layers/apz/src/PotentialCheckerboardDurationTracker.cpp
@@ -35,31 +35,39 @@ PotentialCheckerboardDurationTracker::Ch
   if (!Tracking()) {
     mozilla::Telemetry::AccumulateTimeDelta(
         mozilla::Telemetry::CHECKERBOARD_POTENTIAL_DURATION,
         mCurrentPeriodStart);
   }
 }
 
 void
-PotentialCheckerboardDurationTracker::TransformStarted()
+PotentialCheckerboardDurationTracker::InTransform(bool aInTransform)
 {
-  MOZ_ASSERT(!mInTransform);
-  if (!Tracking()) {
-    mCurrentPeriodStart = TimeStamp::Now();
+  if (aInTransform == mInTransform) {
+    // no-op
+    return;
   }
-  mInTransform = true;
-}
 
-void
-PotentialCheckerboardDurationTracker::TransformStopped()
-{
-  MOZ_ASSERT(mInTransform);
-  mInTransform = false;
   if (!Tracking()) {
+    // Because !Tracking(), mInTransform must be false, and so aInTransform
+    // must be true (or we would have early-exited this function already).
+    // Therefore, we are starting a potential checkerboard period.
+    mInTransform = aInTransform;
+    mCurrentPeriodStart = TimeStamp::Now();
+    return;
+  }
+
+  mInTransform = aInTransform;
+
+  if (!Tracking()) {
+    // Tracking() must have been true at the start of this function, or we
+    // would have taken the other !Tracking branch above. If it's false now,
+    // it means we just stopped tracking, so we are ending a potential
+    // checkerboard period.
     mozilla::Telemetry::AccumulateTimeDelta(
         mozilla::Telemetry::CHECKERBOARD_POTENTIAL_DURATION,
         mCurrentPeriodStart);
   }
 }
 
 bool
 PotentialCheckerboardDurationTracker::Tracking() const
--- a/gfx/layers/apz/src/PotentialCheckerboardDurationTracker.h
+++ b/gfx/layers/apz/src/PotentialCheckerboardDurationTracker.h
@@ -34,25 +34,20 @@ public:
   void CheckerboardSeen();
   /**
    * This should be called when checkerboarding is done. It must have been
    * preceded by one or more calls to CheckerboardSeen().
    */
   void CheckerboardDone();
 
   /**
-   * This should be called when a transform is started. Calls to this must be
-   * interleaved with calls to TransformStopped().
+   * This should be called at composition time, to indicate if the APZC is in
+   * a transforming state or not.
    */
-  void TransformStarted();
-  /**
-   * This should be called when a transform is stopped. Calls to this must be
-   * interleaved with calls to TransformStarted().
-   */
-  void TransformStopped();
+  void InTransform(bool aInTransform);
 
 private:
   bool Tracking() const;
 
 private:
   bool mInCheckerboard;
   bool mInTransform;
 
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -113,16 +113,17 @@ public:
 
   virtual gfxSharedReadLockType GetType() override { return TYPE_SHMEM; }
 
   mozilla::layers::ShmemSection& GetShmemSection() { return mShmemSection; }
 
   static already_AddRefed<gfxShmSharedReadLock>
   Open(mozilla::layers::ISurfaceAllocator* aAllocator, const mozilla::layers::ShmemSection& aShmemSection)
   {
+    MOZ_RELEASE_ASSERT(aShmemSection.shmem().IsReadable());
     RefPtr<gfxShmSharedReadLock> readLock = new gfxShmSharedReadLock(aAllocator, aShmemSection);
     return readLock.forget();
   }
 
 private:
   gfxShmSharedReadLock(ISurfaceAllocator* aAllocator, const mozilla::layers::ShmemSection& aShmemSection)
     : mAllocator(aAllocator)
     , mShmemSection(aShmemSection)
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -517,16 +517,18 @@ BufferTextureHost::MaybeUpload(nsIntRegi
 bool
 BufferTextureHost::Upload(nsIntRegion *aRegion)
 {
   uint8_t* buf = GetBuffer();
   if (!buf) {
     // We don't have a buffer; a possible cause is that the IPDL actor
     // is already dead. This inevitably happens as IPDL actors can die
     // at any time, so we want to silently return in this case.
+    // another possible cause is that IPDL failed to map the shmem when
+    // deserializing it.
     return false;
   }
   if (!mCompositor) {
     // This can happen if we send textures to a compositable that isn't yet
     // attached to a layer.
     return false;
   }
   if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
@@ -646,19 +648,29 @@ BufferTextureHost::GetAsSurface()
   return result.forget();
 }
 
 ShmemTextureHost::ShmemTextureHost(const ipc::Shmem& aShmem,
                                    const BufferDescriptor& aDesc,
                                    ISurfaceAllocator* aDeallocator,
                                    TextureFlags aFlags)
 : BufferTextureHost(aDesc, aFlags)
-, mShmem(MakeUnique<ipc::Shmem>(aShmem))
 , mDeallocator(aDeallocator)
 {
+  if (aShmem.IsReadable()) {
+    mShmem = MakeUnique<ipc::Shmem>(aShmem);
+  } else {
+    // This can happen if we failed to map the shmem on this process, perhaps
+    // because it was big and we didn't have enough contiguous address space
+    // available, even though we did on the child process.
+    // As a result this texture will be in an invalid state and Lock will
+    // always fail.
+    gfxCriticalError() << "Failed to create a valid ShmemTextureHost";
+  }
+
   MOZ_COUNT_CTOR(ShmemTextureHost);
 }
 
 ShmemTextureHost::~ShmemTextureHost()
 {
   MOZ_ASSERT(!mShmem || (mFlags & TextureFlags::DEALLOCATE_CLIENT),
              "Leaking our buffer");
   DeallocateDeviceData();
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -68,16 +68,21 @@ CompositorD3D9::Initialize()
 
 TextureFactoryIdentifier
 CompositorD3D9::GetTextureFactoryIdentifier()
 {
   TextureFactoryIdentifier ident;
   ident.mMaxTextureSize = GetMaxTextureSize();
   ident.mParentBackend = LayersBackend::LAYERS_D3D9;
   ident.mParentProcessId = XRE_GetProcessType();
+  for (uint8_t op = 0; op < uint8_t(gfx::CompositionOp::OP_COUNT); op++) {
+    if (BlendOpIsMixBlendMode(gfx::CompositionOp(op))) {
+      ident.mSupportedBlendModes += gfx::CompositionOp(op);
+    }
+  }
   return ident;
 }
 
 bool
 CompositorD3D9::CanUseCanvasLayerForSize(const IntSize &aSize)
 {
   int32_t maxTextureSize = GetMaxTextureSize();
 
@@ -123,20 +128,20 @@ CompositorD3D9::CreateRenderTarget(const
     ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTarget: Failed to create texture"),
                   hr);
     return nullptr;
   }
 
   return MakeAndAddRef<CompositingRenderTargetD3D9>(texture, aInit, aRect);
 }
 
-already_AddRefed<CompositingRenderTarget>
-CompositorD3D9::CreateRenderTargetFromSource(const gfx::IntRect &aRect,
-                                             const CompositingRenderTarget *aSource,
-                                             const gfx::IntPoint &aSourcePoint)
+already_AddRefed<IDirect3DTexture9>
+CompositorD3D9::CreateTexture(const gfx::IntRect& aRect,
+                              const CompositingRenderTarget* aSource,
+                              const gfx::IntPoint& aSourcePoint)
 {
   MOZ_ASSERT(aRect.width != 0 && aRect.height != 0, "Trying to create a render target of invalid size");
 
   if (aRect.width * aRect.height == 0) {
     return nullptr;
   }
 
   if (!mDeviceManager) {
@@ -184,16 +189,26 @@ CompositorD3D9::CreateRenderTargetFromSo
                                  D3DTEXF_NONE);
       if (FAILED(hr)) {
         ReportFailure(NS_LITERAL_CSTRING("CompositorD3D9::CreateRenderTargetFromSource: Failed to update texture"),
                       hr);
       }
     }
   }
 
+  return texture.forget();
+}
+
+already_AddRefed<CompositingRenderTarget>
+CompositorD3D9::CreateRenderTargetFromSource(const gfx::IntRect &aRect,
+                                             const CompositingRenderTarget *aSource,
+                                             const gfx::IntPoint &aSourcePoint)
+{
+  RefPtr<IDirect3DTexture9> texture = CreateTexture(aRect, aSource, aSourcePoint);
+
   return MakeAndAddRef<CompositingRenderTargetD3D9>(texture,
                                                     INIT_MODE_NONE,
                                                     aRect);
 }
 
 void
 CompositorD3D9::SetRenderTarget(CompositingRenderTarget *aRenderTarget)
 {
@@ -283,16 +298,50 @@ CompositorD3D9::DrawQuad(const gfx::Rect
   if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
     if (aTransform.Is2D()) {
       maskType = MaskType::Mask2d;
     } else {
       maskType = MaskType::Mask3d;
     }
   }
 
+  gfx::Rect backdropDest;
+  gfx::IntRect backdropRect;
+  gfx::Matrix4x4 backdropTransform;
+  RefPtr<IDirect3DTexture9> backdropTexture;
+  gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER;
+
+  if (aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE]) {
+    EffectBlendMode *blendEffect =
+      static_cast<EffectBlendMode*>(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get());
+    blendMode = blendEffect->mBlendMode;
+
+    // Pixel Shader Model 2.0 is too limited to perform blending in the same way
+    // as Direct3D 11 - there are too many instructions, and we don't have
+    // configurable shaders (as we do with OGL) that would avoid a huge shader
+    // matrix.
+    //
+    // Instead, we use a multi-step process for blending on D3D9:
+    //  (1) Capture the backdrop into a temporary surface.
+    //  (2) Render the effect chain onto the backdrop, with OP_SOURCE.
+    //  (3) Capture the backdrop again into another surface - these are our source pixels.
+    //  (4) Perform a final blend step using software.
+    //  (5) Blit the blended result back to the render target.
+    if (BlendOpIsMixBlendMode(blendMode)) {
+      backdropRect = ComputeBackdropCopyRect(
+        aRect, aClipRect, aTransform, &backdropTransform, &backdropDest);
+
+      // If this fails, don't set a blend op.
+      backdropTexture = CreateTexture(backdropRect, mCurrentRT, backdropRect.TopLeft());
+      if (!backdropTexture) {
+        blendMode = gfx::CompositionOp::OP_OVER;
+      }
+    }
+  }
+
   RECT scissor;
   scissor.left = aClipRect.x;
   scissor.right = aClipRect.XMost();
   scissor.top = aClipRect.y;
   scissor.bottom = aClipRect.YMost();
   d3d9Device->SetScissorRect(&scissor);
 
   uint32_t maskTexture = 0;
@@ -469,25 +518,45 @@ CompositorD3D9::DrawQuad(const gfx::Rect
     return;
   default:
     NS_WARNING("Unknown shader type");
     return;
   }
 
   SetMask(aEffectChain, maskTexture);
 
+  if (BlendOpIsMixBlendMode(blendMode)) {
+    // Use SOURCE instead of OVER to get the original source pixels without
+    // having to render to another intermediate target.
+    d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
+  }
   if (!isPremultiplied) {
     d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
   }
 
   d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
 
+  // Restore defaults.
+  if (BlendOpIsMixBlendMode(blendMode)) {
+    d3d9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+  }
   if (!isPremultiplied) {
     d3d9Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
   }
+
+  // Final pass - if mix-blending, do it now that we have the backdrop and
+  // source textures.
+  if (BlendOpIsMixBlendMode(blendMode)) {
+    FinishMixBlend(
+      backdropRect,
+      backdropDest,
+      backdropTransform,
+      backdropTexture,
+      blendMode);
+  }
 }
 
 void
 CompositorD3D9::SetMask(const EffectChain &aEffectChain, uint32_t aMaskTexture)
 {
   EffectMask *maskEffect =
     static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
   if (!maskEffect) {
@@ -772,10 +841,192 @@ CompositorD3D9::ReportFailure(const nsAC
   msg.Append(aMsg);
   msg.AppendLiteral(" Error code: ");
   msg.AppendInt(uint32_t(aCode));
   NS_WARNING(msg.BeginReading());
 
   gfx::LogFailure(msg);
 }
 
+static inline already_AddRefed<IDirect3DSurface9>
+GetSurfaceOfTexture(IDirect3DTexture9* aTexture)
+{
+  RefPtr<IDirect3DSurface9> surface;
+  HRESULT hr = aTexture->GetSurfaceLevel(0, getter_AddRefs(surface));
+  if (FAILED(hr)) {
+    gfxCriticalNote << "Failed to grab texture surface " << hexa(hr);
+    return nullptr;
+  }
+  return surface.forget();
+}
+
+static inline already_AddRefed<IDirect3DSurface9>
+CreateDataSurfaceForTexture(IDirect3DDevice9* aDevice,
+                            IDirect3DSurface9* aSource,
+                            const D3DSURFACE_DESC& aDesc)
+{
+  RefPtr<IDirect3DSurface9> dest;
+  HRESULT hr = aDevice->CreateOffscreenPlainSurface(
+    aDesc.Width, aDesc.Height,
+    aDesc.Format, D3DPOOL_SYSTEMMEM,
+    getter_AddRefs(dest), nullptr);
+  if (FAILED(hr) || !dest) {
+    gfxCriticalNote << "Failed to create offscreen plain surface " << hexa(hr);
+    return nullptr;
+  }
+
+  hr = aDevice->GetRenderTargetData(aSource, dest);
+  if (FAILED(hr)) {
+    gfxCriticalNote << "Failed to get render target data " << hexa(hr);
+    return nullptr;
+  }
+
+  return dest.forget();
+}
+
+class AutoSurfaceLock
+{
+ public:
+  AutoSurfaceLock(IDirect3DSurface9* aSurface, DWORD aFlags = 0) {
+    PodZero(&mRect);
+
+    HRESULT hr = aSurface->LockRect(&mRect, nullptr, aFlags);
+    if (FAILED(hr)) {
+      gfxCriticalNote << "Failed to lock surface rect " << hexa(hr);
+      return;
+    }
+    mSurface = aSurface;
+  }
+  ~AutoSurfaceLock() {
+    if (mSurface) {
+      mSurface->UnlockRect();
+    }
+  }
+
+  bool Okay() const {
+    return !!mSurface;
+  }
+  int Pitch() const {
+    MOZ_ASSERT(Okay());
+    return mRect.Pitch;
+  }
+  uint8_t* Bits() const {
+    MOZ_ASSERT(Okay());
+    return reinterpret_cast<uint8_t*>(mRect.pBits);
+  }
+
+ private:
+  RefPtr<IDirect3DSurface9> mSurface;
+  D3DLOCKED_RECT mRect;
+};
+
+void
+CompositorD3D9::FinishMixBlend(const gfx::IntRect& aBackdropRect,
+                               const gfx::Rect& aBackdropDest,
+                               const gfx::Matrix4x4& aBackdropTransform,
+                               RefPtr<IDirect3DTexture9> aBackdrop,
+                               gfx::CompositionOp aBlendMode)
+{
+  HRESULT hr;
+
+  RefPtr<IDirect3DTexture9> source =
+    CreateTexture(aBackdropRect, mCurrentRT, aBackdropRect.TopLeft());
+  if (!source) {
+    return;
+  }
+
+  // Slow path - do everything in software. Unfortunately this requires
+  // a lot of copying, since we have to readback the source and backdrop,
+  // then upload the blended result, then blit it back.
+
+  IDirect3DDevice9* d3d9Device = device();
+
+  // Query geometry/format of the two surfaces.
+  D3DSURFACE_DESC backdropDesc, sourceDesc;
+  if (FAILED(aBackdrop->GetLevelDesc(0, &backdropDesc)) ||
+      FAILED(source->GetLevelDesc(0, &sourceDesc)))
+  {
+    gfxCriticalNote << "Failed to query mix-blend texture descriptor";
+    return;
+  }
+
+  MOZ_ASSERT(backdropDesc.Format == D3DFMT_A8R8G8B8);
+  MOZ_ASSERT(sourceDesc.Format == D3DFMT_A8R8G8B8);
+
+  // Acquire a temporary data surface for the backdrop texture.
+  RefPtr<IDirect3DSurface9> backdropSurface = GetSurfaceOfTexture(aBackdrop);
+  if (!backdropSurface) {
+    return;
+  }
+  RefPtr<IDirect3DSurface9> tmpBackdrop =
+    CreateDataSurfaceForTexture(d3d9Device, backdropSurface, backdropDesc);
+  if (!tmpBackdrop) {
+    return;
+  }
+
+  // New scope for locks and temporary surfaces.
+  {
+    // Acquire a temporary data surface for the source texture.
+    RefPtr<IDirect3DSurface9> sourceSurface = GetSurfaceOfTexture(source);
+    if (!sourceSurface) {
+      return;
+    }
+    RefPtr<IDirect3DSurface9> tmpSource =
+      CreateDataSurfaceForTexture(d3d9Device, sourceSurface, sourceDesc);
+    if (!tmpSource) {
+      return;
+    }
+
+    // Perform the readback and blend in software.
+    AutoSurfaceLock backdropLock(tmpBackdrop);
+    AutoSurfaceLock sourceLock(tmpSource, D3DLOCK_READONLY);
+    if (!backdropLock.Okay() || !sourceLock.Okay()) {
+      return;
+    }
+
+    RefPtr<DataSourceSurface> source = Factory::CreateWrappingDataSourceSurface(
+      sourceLock.Bits(), sourceLock.Pitch(),
+      gfx::IntSize(sourceDesc.Width, sourceDesc.Height),
+      SurfaceFormat::B8G8R8A8);
+
+    RefPtr<DrawTarget> dest = Factory::CreateDrawTargetForData(
+      BackendType::CAIRO,
+      backdropLock.Bits(),
+      gfx::IntSize(backdropDesc.Width, backdropDesc.Height),
+      backdropLock.Pitch(),
+      SurfaceFormat::B8G8R8A8);
+
+    // The backdrop rect is rounded out - account for any difference between
+    // it and the actual destination.
+    gfx::Rect destRect(
+      aBackdropDest.x - aBackdropRect.x,
+      aBackdropDest.y - aBackdropRect.y,
+      aBackdropDest.width,
+      aBackdropDest.height);
+
+    dest->DrawSurface(
+      source, destRect, destRect,
+      gfx::DrawSurfaceOptions(),
+      gfx::DrawOptions(1.0f, aBlendMode));
+  }
+
+  // Upload the new blended surface to the backdrop texture.
+  d3d9Device->UpdateSurface(tmpBackdrop, nullptr, backdropSurface, nullptr);
+
+  // Finally, drop in the new backdrop. We don't need to do another
+  // DrawPrimitive() since the software blend will have included the
+  // final OP_OVER step for us.
+  RECT destRect = {
+    aBackdropRect.x, aBackdropRect.y,
+    aBackdropRect.XMost(), aBackdropRect.YMost()
+  };
+  hr = d3d9Device->StretchRect(backdropSurface,
+                               nullptr,
+                               mCurrentRT->GetD3D9Surface(),
+                               &destRect,
+                               D3DTEXF_NONE);
+  if (FAILED(hr)) {
+    gfxCriticalNote << "StretcRect with mix-blend failed " << hexa(hr);
+  }
+}
+
 }
 }
--- a/gfx/layers/d3d9/CompositorD3D9.h
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -132,16 +132,30 @@ private:
    * Returns true if we have a working swap chain; false otherwise.
    * If we cannot create or validate the swap chain due to a bad device manager,
    * then the device will be destroyed and set mDeviceManager to null. We will
    * schedule another composite if it is a good idea to try again or we need to
    * recreate the device.
    */
   bool EnsureSwapChain();
 
+  already_AddRefed<IDirect3DTexture9>
+  CreateTexture(const gfx::IntRect& aRect,
+                const CompositingRenderTarget* aSource,
+                const gfx::IntPoint& aSourcePoint);
+
+  /**
+   * Complete a mix-blend step at the end of DrawQuad().
+   */
+  void FinishMixBlend(const gfx::IntRect& aBackdropRect,
+                      const gfx::Rect& aBackdropDest,
+                      const gfx::Matrix4x4& aBackdropTransform,
+                      RefPtr<IDirect3DTexture9> aBackdrop,
+                      gfx::CompositionOp aBlendMode);
+
   /**
    * DeviceManagerD3D9 keeps a count of the number of times its device is
    * reset or recreated. We keep a parallel count (mDeviceResetCount). It
    * is possible that we miss a reset if it is 'caused' by another
    * compositor (for another window). In which case we need to invalidate
    * everything and render it all. This method checks the reset counts
    * match and if not invalidates everything (a long comment on that in
    * the cpp file).
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -108,53 +108,58 @@ SurfaceFormatToD3D9Format(SurfaceFormat 
   return D3DFMT_A8R8G8B8;
 }
 
 CompositingRenderTargetD3D9::CompositingRenderTargetD3D9(IDirect3DTexture9* aTexture,
                                                          SurfaceInitMode aInit,
                                                          const gfx::IntRect& aRect)
   : CompositingRenderTarget(aRect.TopLeft())
   , mInitMode(aInit)
-  , mInitialized(false)
 {
   MOZ_COUNT_CTOR(CompositingRenderTargetD3D9);
   MOZ_ASSERT(aTexture);
 
   mTexture = aTexture;
   mTexture->GetSurfaceLevel(0, getter_AddRefs(mSurface));
   NS_ASSERTION(mSurface, "Couldn't create surface for texture");
   TextureSourceD3D9::SetSize(aRect.Size());
+
+  if (aInit == INIT_MODE_CLEAR) {
+    ClearOnBind();
+  }
 }
 
 CompositingRenderTargetD3D9::CompositingRenderTargetD3D9(IDirect3DSurface9* aSurface,
                                                          SurfaceInitMode aInit,
                                                          const gfx::IntRect& aRect)
   : CompositingRenderTarget(aRect.TopLeft())
   , mSurface(aSurface)
   , mInitMode(aInit)
-  , mInitialized(false)
 {
   MOZ_COUNT_CTOR(CompositingRenderTargetD3D9);
   MOZ_ASSERT(mSurface);
   TextureSourceD3D9::SetSize(aRect.Size());
+
+  if (aInit == INIT_MODE_CLEAR) {
+    ClearOnBind();
+  }
 }
 
 CompositingRenderTargetD3D9::~CompositingRenderTargetD3D9()
 {
   MOZ_COUNT_DTOR(CompositingRenderTargetD3D9);
 }
 
 void
 CompositingRenderTargetD3D9::BindRenderTarget(IDirect3DDevice9* aDevice)
 {
   aDevice->SetRenderTarget(0, mSurface);
-  if (!mInitialized &&
-      mInitMode == INIT_MODE_CLEAR) {
-    mInitialized = true;
+  if (mClearOnBind) {
     aDevice->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0);
+    mClearOnBind = false;
   }
 }
 
 IntSize
 CompositingRenderTargetD3D9::GetSize() const
 {
   return TextureSourceD3D9::GetSize();
 }
--- a/gfx/layers/d3d9/TextureD3D9.h
+++ b/gfx/layers/d3d9/TextureD3D9.h
@@ -411,15 +411,14 @@ public:
 
   IDirect3DSurface9* GetD3D9Surface() const { return mSurface; }
 
 private:
   friend class CompositorD3D9;
 
   RefPtr<IDirect3DSurface9> mSurface;
   SurfaceInitMode mInitMode;
-  bool mInitialized;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_TEXTURED3D9_H */
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -481,18 +481,16 @@ void
 CompositorOGL::PrepareViewport(CompositingRenderTargetOGL* aRenderTarget)
 {
   MOZ_ASSERT(aRenderTarget);
   const gfx::IntSize& size = aRenderTarget->mInitParams.mSize;
 
   // Set the viewport correctly.
   mGLContext->fViewport(0, 0, size.width, size.height);
 
-  mRenderBounds = Rect(0, 0, size.width, size.height);
-
   mViewportSize = size;
 
   if (!aRenderTarget->HasComplexProjection()) {
     // We flip the view matrix around so that everything is right-side up; we're
     // drawing directly into the window's back buffer, so this keeps things
     // looking correct.
     // XXX: We keep track of whether the window size changed, so we could skip
     // this update if it hadn't changed since the last call.
@@ -1002,31 +1000,34 @@ CompositorOGL::DrawQuad(const Rect& aRec
   MOZ_ASSERT(mCurrentRenderTarget, "No destination");
 
   if (aEffectChain.mPrimaryEffect->mType == EffectTypes::VR_DISTORTION) {
     DrawVRDistortion(aRect, aClipRect, aEffectChain, aOpacity, aTransform);
     return;
   }
 
   IntPoint offset = mCurrentRenderTarget->GetOrigin();
-  Rect renderBound = mRenderBounds;
+  IntSize size = mCurrentRenderTarget->GetSize();
+
+  Rect renderBound(0, 0, size.width, size.height);
   renderBound.IntersectRect(renderBound, aClipRect);
   renderBound.MoveBy(offset);
 
   Rect destRect = aTransform.TransformAndClipBounds(aRect, renderBound);
 
   // XXX: This doesn't handle 3D transforms. It also doesn't handled rotated
   //      quads. Fix me.
   mPixelsFilled += destRect.width * destRect.height;
 
   // Do a simple culling if this rect is out of target buffer.
   // Inflate a small size to avoid some numerical imprecision issue.
   destRect.Inflate(1, 1);
   destRect.MoveBy(-offset);
-  if (!mRenderBounds.Intersects(destRect)) {
+  renderBound = Rect(0, 0, size.width, size.height);
+  if (!renderBound.Intersects(destRect)) {
     return;
   }
 
   LayerScope::DrawBegin();
 
   Rect clipRect = aClipRect;
   // aClipRect is in destination coordinate space (after all
   // transforms and offsets have been applied) so if our
@@ -1118,26 +1119,19 @@ CompositorOGL::DrawQuad(const Rect& aRec
   LayerScope::SetLayerTransform(aTransform);
   if (colorMatrix) {
       EffectColorMatrix* effectColorMatrix =
         static_cast<EffectColorMatrix*>(aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX].get());
       program->SetColorMatrix(effectColorMatrix->mColorMatrix);
   }
 
   if (BlendOpIsMixBlendMode(blendMode)) {
-    gfx::IntRect rect = ComputeBackdropCopyRect(aRect, aClipRect, aTransform);
+    gfx::Matrix4x4 transform;
+    gfx::IntRect rect = ComputeBackdropCopyRect(aRect, aClipRect, aTransform, &transform);
     mixBlendBackdrop = CreateTexture(rect, true, mCurrentRenderTarget->GetFBO());
-
-    // Create a transform from adjusted clip space to render target space,
-    // translate it for the backdrop rect, then transform it into the backdrop's
-    // uv-space.
-    gfx::Matrix4x4 transform;
-    transform.PostScale(mRenderBounds.width, mRenderBounds.height, 1.0);
-    transform.PostTranslate(-rect.x, -rect.y, 0.0);
-    transform.PostScale(1 / float(rect.width), 1 / float(rect.height), 1.0);
     program->SetBackdropTransform(transform);
   }
 
   program->SetRenderOffset(offset.x, offset.y);
   LayerScope::SetRenderOffset(offset.x, offset.y);
 
   if (aOpacity != 1.f)
     program->SetLayerOpacity(aOpacity);
--- a/gfx/skia/skia/include/core/SkPostConfig.h
+++ b/gfx/skia/skia/include/core/SkPostConfig.h
@@ -295,17 +295,17 @@
 #if !defined(SK_ALWAYS_INLINE)
 #  if defined(SK_BUILD_FOR_WIN)
 #    define SK_ALWAYS_INLINE __forceinline
 #  else
 #    define SK_ALWAYS_INLINE SK_ATTRIBUTE(always_inline) inline
 #  endif
 #endif
 
-#if defined(SK_BUILD_FOR_WIN) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
+#if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
     #define SK_VECTORCALL __vectorcall
 #elif defined(SK_CPU_ARM32)
     #define SK_VECTORCALL __attribute__((pcs("aapcs-vfp")))
 #else
     #define SK_VECTORCALL
 #endif
 
 //////////////////////////////////////////////////////////////////////
--- a/gfx/skia/skia/include/private/SkTLogic.h
+++ b/gfx/skia/skia/include/private/SkTLogic.h
@@ -114,25 +114,22 @@ template <typename T, size_t N> struct i
 // template<typename R, typename... Args> struct is_function<
 //     R [calling-convention] (Args...[, ...]) [const] [volatile] [&|&&]> : true_type {};
 // The cv and ref-qualified versions are strange types we're currently avoiding, so not supported.
 // On all platforms, variadic functions only exist in the c calling convention.
 template <typename> struct is_function : false_type { };
 #if !defined(SK_BUILD_FOR_WIN)
 template <typename R, typename... Args> struct is_function<R(Args...)> : true_type {};
 #else
+template <typename R, typename... Args> struct is_function<R __cdecl (Args...)> : true_type {};
 #if defined(_M_IX86)
-template <typename R, typename... Args> struct is_function<R __cdecl (Args...)> : true_type {};
 template <typename R, typename... Args> struct is_function<R __stdcall (Args...)> : true_type {};
 template <typename R, typename... Args> struct is_function<R __fastcall (Args...)> : true_type {};
-#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
-template <typename R, typename... Args> struct is_function<R __vectorcall (Args...)> : true_type {};
 #endif
-#else
-template <typename R, typename... Args> struct is_function<R __cdecl (Args...)> : true_type {};
+#if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
 template <typename R, typename... Args> struct is_function<R __vectorcall (Args...)> : true_type {};
 #endif
 #endif
 template <typename R, typename... Args> struct is_function<R(Args..., ...)> : true_type {};
 
 template <typename T> struct add_const { using type = const T; };
 template <typename T> using add_const_t = typename add_const<T>::type;
 
--- a/gfx/skia/skia/src/ports/SkOSLibrary_win.cpp
+++ b/gfx/skia/skia/src/ports/SkOSLibrary_win.cpp
@@ -11,12 +11,12 @@
 #include "SkOSLibrary.h"
 #include <windows.h>
 
 void* DynamicLoadLibrary(const char* libraryName) {
     return LoadLibraryA(libraryName);
 }
 
 void* GetProcedureAddress(void* library, const char* functionName) {
-    return ::GetProcAddress((HMODULE)library, functionName);
+    return reinterpret_cast<void*>(::GetProcAddress((HMODULE)library, functionName));
 }
 
 #endif//defined(SK_BUILD_FOR_WIN32)
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -632,22 +632,22 @@ AddContentSandboxAllowedFiles(int32_t aS
   }
 
   if (::GetDriveTypeW(volPath) != DRIVE_REMOTE) {
     return;
   }
 
   // Convert network share path to format for sandbox policy.
   if (Substring(binDirPath, 0, 2).Equals(L"\\\\")) {
-    binDirPath.InsertLiteral(L"??\\UNC", 1);
+    binDirPath.InsertLiteral(MOZ_UTF16("??\\UNC"), 1);
   }
 
-  binDirPath.AppendLiteral(L"\\*");
+  binDirPath.AppendLiteral(MOZ_UTF16("\\*"));
 
-  aAllowedFilesRead.push_back(binDirPath.get());
+  aAllowedFilesRead.push_back(std::wstring(binDirPath.get()));
 }
 #endif
 
 bool
 GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts, base::ProcessArchitecture arch)
 {
   // We rely on the fact that InitializeChannel() has already been processed
   // on the IO thread before this point is reached.
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -275,41 +275,16 @@ private:
     MessageChannel& mThat;
 
     // Disable harmful methods.
     CxxStackFrame() = delete;
     CxxStackFrame(const CxxStackFrame&) = delete;
     CxxStackFrame& operator=(const CxxStackFrame&) = delete;
 };
 
-namespace {
-
-class MOZ_RAII MaybeScriptBlocker {
-public:
-    explicit MaybeScriptBlocker(MessageChannel *aChannel, bool aBlock
-                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-        : mBlocked(aChannel->ShouldBlockScripts() && aBlock)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        if (mBlocked) {
-            nsContentUtils::AddScriptBlocker();
-        }
-    }
-    ~MaybeScriptBlocker() {
-        if (mBlocked) {
-            nsContentUtils::RemoveScriptBlocker();
-        }
-    }
-private:
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-    bool mBlocked;
-};
-
-} // namespace
-
 MessageChannel::MessageChannel(MessageListener *aListener)
   : mListener(aListener),
     mChannelState(ChannelClosed),
     mSide(UnknownSide),
     mLink(nullptr),
     mWorkerLoop(nullptr),
     mChannelErrorTask(nullptr),
     mWorkerLoopID(-1),
@@ -327,17 +302,16 @@ MessageChannel::MessageChannel(MessageLi
     mPendingSendPriorities(0),
     mTimedOutMessageSeqno(0),
     mTimedOutMessagePriority(0),
     mRecvdErrors(0),
     mRemoteStackDepthGuess(false),
     mSawInterruptOutMsg(false),
     mIsWaitingForIncoming(false),
     mAbortOnError(false),
-    mBlockScripts(false),
     mFlags(REQUIRE_DEFAULT),
     mPeerPidSet(false),
     mPeerPid(-1)
 {
     MOZ_COUNT_CTOR(ipc::MessageChannel);
 
 #ifdef OS_WIN
     mTopFrame = nullptr;
@@ -863,19 +837,16 @@ MessageChannel::WasTransactionCanceled(i
     return false;
 }
 
 bool
 MessageChannel::Send(Message* aMsg, Message* aReply)
 {
     nsAutoPtr<Message> msg(aMsg);
 
-    // See comment in DispatchSyncMessage.
-    MaybeScriptBlocker scriptBlocker(this, true);
-
     // Sanity checks.
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
 
 #ifdef OS_WIN
     SyncStackFrame frame(this, false);
     NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
 #endif
@@ -1425,25 +1396,20 @@ MessageChannel::DispatchMessage(const Me
 
 void
 MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply)
 {
     AssertWorkerThread();
 
     int prio = aMsg.priority();
 
-    // We don't want to run any code that might run a nested event loop here, so
-    // we avoid running event handlers. Once we've sent the response to the
-    // urgent message, it's okay to run event handlers again since the parent is
-    // no longer blocked.
     MOZ_ASSERT_IF(prio > IPC::Message::PRIORITY_NORMAL, NS_IsMainThread());
-    MaybeScriptBlocker scriptBlocker(this, prio > IPC::Message::PRIORITY_NORMAL);
 
     MessageChannel* dummy;
-    MessageChannel*& blockingVar = ShouldBlockScripts() ? gParentProcessBlocker : dummy;
+    MessageChannel*& blockingVar = mSide == ChildSide && NS_IsMainThread() ? gParentProcessBlocker : dummy;
 
     Result rv;
     {
         AutoSetValue<MessageChannel*> blocked(blockingVar, this);
         AutoSetValue<bool> sync(mDispatchingSyncMessage, true);
         AutoSetValue<int> prioSet(mDispatchingSyncMessagePriority, prio);
         rv = mListener->OnMessageReceived(aMsg, aReply);
     }
@@ -1974,23 +1940,16 @@ MessageChannel::CloseWithTimeout()
     if (ChannelConnected != mChannelState) {
         return;
     }
     SynchronouslyClose();
     mChannelState = ChannelTimeout;
 }
 
 void
-MessageChannel::BlockScripts()
-{
-    MOZ_ASSERT(NS_IsMainThread());
-    mBlockScripts = true;
-}
-
-void
 MessageChannel::Close()
 {
     AssertWorkerThread();
 
     {
         MonitorAutoLock lock(*mMonitor);
 
         if (ChannelError == mChannelState || ChannelTimeout == mChannelState) {
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -115,23 +115,16 @@ class MessageChannel : HasResultCodes
       // handling to prevent deadlocks. Should only be used for protocols
       // that manage child processes which might create native UI, like
       // plugins.
       REQUIRE_DEFERRED_MESSAGE_PROTECTION     = 1 << 0
     };
     void SetChannelFlags(ChannelFlags aFlags) { mFlags = aFlags; }
     ChannelFlags GetChannelFlags() { return mFlags; }
 
-    void BlockScripts();
-
-    bool ShouldBlockScripts() const
-    {
-        return mBlockScripts;
-    }
-
     // Asynchronously send a message to the other side of the channel
     bool Send(Message* aMsg);
 
     // Asynchronously deliver a message back to this side of the
     // channel
     bool Echo(Message* aMsg);
 
     // Synchronously send |msg| (i.e., wait for |reply|)
@@ -771,19 +764,16 @@ class MessageChannel : HasResultCodes
 #ifdef OS_WIN
     HANDLE mEvent;
 #endif
 
     // Should the channel abort the process from the I/O thread when
     // a channel error occurs?
     bool mAbortOnError;
 
-    // Should we prevent scripts from running while dispatching urgent messages?
-    bool mBlockScripts;
-
     // See SetChannelFlags
     ChannelFlags mFlags;
 
     // Task and state used to asynchronously notify channel has been connected
     // safely.  This is necessary to be able to cancel notification if we are
     // closed at the same time.
     RefPtr<RefCountedTask> mOnChannelConnectedTask;
     DebugOnly<bool> mPeerPidSet;
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -4292,23 +4292,26 @@ class _GenerateProtocolActorCode(ipdl.as
             failif,
             StmtExpr(ExprCall(ExprSelect(self.msgvar, '.', 'EndRead'),
                               args=[ itervar ])),
             Whitespace.NL,
             StmtDecl(Decl(_rawShmemType(ptr=1), rawvar.name),
                      init=ExprCall(p.lookupSharedMemory(), args=[ idvar ]))
         ])
 
-        failif = StmtIf(ExprNot(rawvar))
-        failif.addifstmt(StmtReturn(_Result.ValuError))
+        # Here we don't return an error if we failed to look the shmem up. This
+        # is because we don't have a way to know if it is because we failed to
+        # map the shmem or if the id is wrong. In the latter case it would be
+        # better to catch the error but the former case is legit...
+        lookupif = StmtIf(rawvar)
+        lookupif.addifstmt(StmtExpr(p.removeShmemId(idvar)))
+        lookupif.addifstmt(StmtExpr(_shmemDealloc(rawvar)))
 
         case.addstmts([
-            failif,
-            StmtExpr(p.removeShmemId(idvar)),
-            StmtExpr(_shmemDealloc(rawvar)),
+            lookupif,
             StmtReturn(_Result.Processed)
         ])
 
         return case
 
 
     def makeChannelOpenedHandlers(self, actors):
         handlers = StmtBlock()
@@ -4664,17 +4667,22 @@ class _GenerateProtocolActorCode(ipdl.as
             StmtDecl(Decl(_shmemType(), tmpvar.name)),
             ifread,
             Whitespace.NL,
             StmtDecl(Decl(_shmemIdType(), idvar.name),
                      init=_shmemId(tmpvar)),
             StmtDecl(Decl(_rawShmemType(ptr=1), rawvar.name),
                      init=_lookupShmem(idvar)),
             iffound,
-            StmtReturn.FALSE
+            # This is ugly: we failed to look the shmem up, most likely because
+            # we failed to map it the first time it was deserialized. we create
+            # an empty shmem and let the user of the shmem deal with it.
+            # if we returned false here we would crash.
+            StmtExpr(ExprAssn(ExprDeref(var), ExprCall(ExprVar('Shmem'), args=[]) )),
+            StmtReturn.TRUE
         ])
 
         self.cls.addstmts([ write, Whitespace.NL, read, Whitespace.NL ])
 
     def implementFDPickling(self, fdtype):
         msgvar = self.msgvar
         itervar = self.itervar
         var = self.var
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -504,33 +504,16 @@ class MOZ_STACK_CLASS MutableHandle : pu
 
     T* ptr;
 };
 
 } /* namespace JS */
 
 namespace js {
 
-/**
- * By default, things should use the inheritance hierarchy to find their
- * ThingRootKind. Some pointer types are explicitly set in jspubtd.h so that
- * Rooted<T> may be used without the class definition being available.
- */
-template <typename T>
-struct RootKind
-{
-    static ThingRootKind rootKind() { return T::rootKind(); }
-};
-
-template <typename T>
-struct RootKind<T*>
-{
-    static ThingRootKind rootKind() { return T::rootKind(); }
-};
-
 template <typename T>
 struct BarrierMethods<T*>
 {
     static T* initial() { return nullptr; }
     static void postBarrier(T** vp, T* prev, T* next) {
         if (next)
             JS::AssertGCThingIsNotAnObjectSubclass(reinterpret_cast<js::gc::Cell*>(next));
     }
@@ -602,18 +585,16 @@ namespace JS {
 
 // Non pointer types -- structs or classes that contain GC pointers, either as
 // a member or in a more complex container layout -- can also be stored in a
 // [Persistent]Rooted if it derives from JS::Traceable. A JS::Traceable stored
 // in a [Persistent]Rooted must implement the method:
 //     |static void trace(T*, JSTracer*)|
 class Traceable
 {
-  public:
-    static js::ThingRootKind rootKind() { return js::THING_ROOT_TRACEABLE; }
 };
 
 } /* namespace JS */
 
 namespace js {
 
 template <typename T>
 class DispatchWrapper
@@ -689,18 +670,17 @@ namespace JS {
 template <typename T>
 class MOZ_RAII Rooted : public js::RootedBase<T>
 {
     static_assert(!mozilla::IsConvertible<T, Traceable*>::value,
                   "Rooted takes pointer or Traceable types but not Traceable* type");
 
     /* Note: CX is a subclass of either ContextFriendFields or PerThreadDataFriendFields. */
     void registerWithRootLists(js::RootLists& roots) {
-        js::ThingRootKind kind = js::RootKind<T>::rootKind();
-        this->stack = &roots.stackRoots_[kind];
+        this->stack = &roots.stackRoots_[JS::MapTypeToRootKind<T>::kind];
         this->prev = *stack;
         *stack = reinterpret_cast<Rooted<void*>*>(this);
     }
 
   public:
     template <typename RootingContext>
     explicit Rooted(const RootingContext& cx)
       : ptr(js::GCPolicy<T>::initial())
@@ -1007,26 +987,26 @@ class PersistentRooted : public js::Pers
     friend class mozilla::LinkedListElement<PersistentRooted>;
 
     friend struct js::gc::PersistentRootedMarker<T>;
 
     friend void js::gc::FinishPersistentRootedChains(js::RootLists&);
 
     void registerWithRootLists(js::RootLists& roots) {
         MOZ_ASSERT(!initialized());
-        js::ThingRootKind kind = js::RootKind<T>::rootKind();
+        JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
         roots.heapRoots_[kind].insertBack(reinterpret_cast<JS::PersistentRooted<void*>*>(this));
         // Until marking and destruction support the full set, we assert that
         // we don't try to add any unsupported types.
-        MOZ_ASSERT(kind == js::THING_ROOT_OBJECT ||
-                   kind == js::THING_ROOT_SCRIPT ||
-                   kind == js::THING_ROOT_STRING ||
-                   kind == js::THING_ROOT_ID ||
-                   kind == js::THING_ROOT_VALUE ||
-                   kind == js::THING_ROOT_TRACEABLE);
+        MOZ_ASSERT(kind == JS::RootKind::Object ||
+                   kind == JS::RootKind::Script ||
+                   kind == JS::RootKind::String ||
+                   kind == JS::RootKind::Id ||
+                   kind == JS::RootKind::Value ||
+                   kind == JS::RootKind::Traceable);
     }
 
   public:
     PersistentRooted() : ptr(js::GCPolicy<T>::initial()) {}
 
     template <typename RootingContext>
     explicit PersistentRooted(const RootingContext& cx)
       : ptr(js::GCPolicy<T>::initial())
--- a/js/public/TraceKind.h
+++ b/js/public/TraceKind.h
@@ -55,37 +55,101 @@ enum class TraceKind
     JitCode = 0x1F,
     LazyScript = 0x2F
 };
 const static uintptr_t OutOfLineTraceKindMask = 0x07;
 static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set");
 static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set");
 static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set");
 
+// When this header is imported inside SpiderMonkey, the class definitions are
+// available and we can query those definitions to find the correct kind
+// directly from the class hierarchy.
+template <typename T>
+struct MapTypeToTraceKind {
+    static const JS::TraceKind kind = T::TraceKind;
+};
+
+// When this header is used outside SpiderMonkey, the class definitions are not
+// available, so the following table containing all public GC types is used.
 #define JS_FOR_EACH_TRACEKIND(D) \
  /* PrettyName       TypeName           AddToCCKind */ \
     D(BaseShape,     js::BaseShape,     true) \
     D(JitCode,       js::jit::JitCode,  true) \
     D(LazyScript,    js::LazyScript,    true) \
     D(Object,        JSObject,          true) \
     D(ObjectGroup,   js::ObjectGroup,   true) \
     D(Script,        JSScript,          true) \
     D(Shape,         js::Shape,         true) \
     D(String,        JSString,          false) \
     D(Symbol,        JS::Symbol,        false)
 
-// Map from base trace type to the trace kind.
-template <typename T> struct MapTypeToTraceKind {};
+// Map from all public types to their trace kind.
 #define JS_EXPAND_DEF(name, type, _) \
     template <> struct MapTypeToTraceKind<type> { \
         static const JS::TraceKind kind = JS::TraceKind::name; \
     };
 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
 #undef JS_EXPAND_DEF
 
+// RootKind is closely related to TraceKind. Whereas TraceKind's indices are
+// laid out for convenient embedding as a pointer tag, the indicies of RootKind
+// are designed for use as array keys via EnumeratedArray.
+enum class RootKind : int8_t
+{
+    // These map 1:1 with trace kinds.
+    BaseShape = 0,
+    JitCode,
+    LazyScript,
+    Object,
+    ObjectGroup,
+    Script,
+    Shape,
+    String,
+    Symbol,
+
+    // These tagged pointers are special-cased for performance.
+    Id,
+    Value,
+
+    // Everything else.
+    Traceable,
+
+    Limit
+};
+
+// Most RootKind correspond directly to a trace kind.
+template <TraceKind traceKind> struct MapTraceKindToRootKind {};
+#define JS_EXPAND_DEF(name, _0, _1) \
+    template <> struct MapTraceKindToRootKind<JS::TraceKind::name> { \
+        static const JS::RootKind kind = JS::RootKind::name; \
+    };
+JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF)
+#undef JS_EXPAND_DEF
+
+// Specify the RootKind for all types. Value and jsid map to special cases;
+// pointer types we can derive directly from the TraceKind; everything else
+// should go in the Traceable list and use GCPolicy<T>::trace for tracing.
+template <typename T>
+struct MapTypeToRootKind {
+    static const JS::RootKind kind = JS::RootKind::Traceable;
+};
+template <typename T>
+struct MapTypeToRootKind<T*> {
+    static const JS::RootKind kind = \
+        JS::MapTraceKindToRootKind<JS::MapTypeToTraceKind<T>::kind>::kind;
+};
+template <> struct MapTypeToRootKind<JS::Value> {
+    static const JS::RootKind kind = JS::RootKind::Value;
+};
+template <> struct MapTypeToRootKind<jsid> {
+    static const JS::RootKind kind = JS::RootKind::Id;
+};
+template <> struct MapTypeToRootKind<JSFunction*> : public MapTypeToRootKind<JSObject*> {};
+
 // Fortunately, few places in the system need to deal with fully abstract
 // cells. In those places that do, we generally want to move to a layout
 // templated function as soon as possible. This template wraps the upcast
 // for that dispatch.
 //
 // Given a call:
 //
 //    DispatchTraceKindTyped(f, thing, traceKind, ... args)
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -1782,17 +1782,24 @@ class MOZ_STACK_CLASS ModuleValidator
         if (!genData ||
             !genData->sigs.resize(MaxSigs) ||
             !genData->funcSigs.resize(MaxFuncs) ||
             !genData->imports.resize(MaxImports))
         {
             return false;
         }
 
-        return mg_.init(Move(genData), ModuleKind::AsmJS);
+        CacheableChars filename;
+        if (parser_.ss->filename()) {
+            filename = DuplicateString(parser_.ss->filename());
+            if (!filename)
+                return false;
+        }
+
+        return mg_.init(Move(genData), Move(filename), ModuleKind::AsmJS);
     }
 
     ExclusiveContext* cx() const             { return cx_; }
     PropertyName* moduleFunctionName() const { return moduleFunctionName_; }
     PropertyName* globalArgumentName() const { return module_->globalArgumentName; }
     PropertyName* importArgumentName() const { return module_->importArgumentName; }
     PropertyName* bufferArgumentName() const { return module_->bufferArgumentName; }
     ModuleGenerator& mg()                    { return mg_; }
@@ -2218,28 +2225,18 @@ class MOZ_STACK_CLASS ModuleValidator
 
     bool startFunctionBodies() {
         return mg_.startFuncDefs();
     }
     bool finishFunctionBodies() {
         return mg_.finishFuncDefs();
     }
     bool finish(MutableHandle<WasmModuleObject*> moduleObj, SlowFunctionVector* slowFuncs) {
-        HeapUsage heap = arrayViews_.empty()
-                              ? HeapUsage::None
-                              : atomicsPresent_
-                                ? HeapUsage::Shared
-                                : HeapUsage::Unshared;
-
-        CacheableChars filename;
-        if (parser_.ss->filename()) {
-            filename = DuplicateString(parser_.ss->filename());
-            if (!filename)
-                return false;
-        }
+        if (!arrayViews_.empty())
+            mg_.initHeapUsage(atomicsPresent_ ? HeapUsage::Shared : HeapUsage::Unshared);
 
         CacheableCharsVector funcNames;
         for (const Func* func : functions_) {
             CacheableChars funcName = StringToNewUTF8CharsZ(cx_, *func->name());
             if (!funcName || !funcNames.emplaceBack(Move(funcName)))
                 return false;
         }
 
@@ -2248,17 +2245,17 @@ class MOZ_STACK_CLASS ModuleValidator
 
         TokenPos pos;
         JS_ALWAYS_TRUE(tokenStream().peekTokenPos(&pos, TokenStream::Operand));
         uint32_t endAfterCurly = pos.end;
         module_->srcLengthWithRightBrace = endAfterCurly - module_->srcStart;
 
         UniqueModuleData base;
         UniqueStaticLinkData link;
-        if (!mg_.finish(heap, Move(filename), Move(funcNames), &base, &link, slowFuncs))
+        if (!mg_.finish(Move(funcNames), &base, &link, slowFuncs))
             return false;
 
         moduleObj.set(WasmModuleObject::create(cx_));
         if (!moduleObj)
             return false;
 
         return moduleObj->init(cx_->new_<AsmJSModule>(Move(base), Move(link), Move(module_)));
     }
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -345,16 +345,42 @@ DecodeFuncBody(JSContext* cx, Decoder& d
     if (!fg.bytecode().resize(bodyLength))
         return false;
 
     PodCopy(fg.bytecode().begin(), bodyBegin, bodyLength);
     return true;
 }
 
 /*****************************************************************************/
+// dynamic link data
+
+struct ImportName
+{
+    UniqueChars module;
+    UniqueChars func;
+
+    ImportName(UniqueChars module, UniqueChars func)
+      : module(Move(module)), func(Move(func))
+    {}
+    ImportName(ImportName&& rhs)
+      : module(Move(rhs.module)), func(Move(rhs.func))
+    {}
+};
+
+typedef Vector<ImportName, 0, SystemAllocPolicy> ImportNameVector;
+
+struct DynamicLinkData
+{
+    ImportNameVector importNames;
+    ExportMap exportMap;
+};
+
+typedef UniquePtr<DynamicLinkData> UniqueDynamicLinkData;
+
+/*****************************************************************************/
 // wasm decoding and generation
 
 static bool
 DecodeSignatureSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init)
 {
     if (!d.readCStringIf(SigSection))
         return true;
 
@@ -443,33 +469,18 @@ DecodeDeclarationSection(JSContext* cx, 
     }
 
     if (!d.finishSection(sectionStart))
         return Fail(cx, d, "decls section byte size mismatch");
 
     return true;
 }
 
-struct ImportName
-{
-    UniqueChars module;
-    UniqueChars func;
-
-    ImportName(UniqueChars module, UniqueChars func)
-      : module(Move(module)), func(Move(func))
-    {}
-    ImportName(ImportName&& rhs)
-      : module(Move(rhs.module)), func(Move(rhs.func))
-    {}
-};
-
-typedef Vector<ImportName, 0, SystemAllocPolicy> ImportNameVector;
-
 static bool
-DecodeImport(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* importNames)
+DecodeImport(JSContext* cx, Decoder& d, ModuleGeneratorData* init, DynamicLinkData* link)
 {
     if (!d.readCStringIf(FuncSubsection))
         return Fail(cx, d, "expected 'func' tag");
 
     const DeclaredSig* sig;
     if (!DecodeSignatureIndex(cx, d, *init, &sig))
         return false;
 
@@ -490,112 +501,114 @@ DecodeImport(JSContext* cx, Decoder& d, 
     const char* funcStr;
     if (!d.readCString(&funcStr))
         return Fail(cx, d, "expected import func name");
 
     UniqueChars funcName = DuplicateString(funcStr);
     if (!funcName)
         return false;
 
-    return importNames->emplaceBack(Move(moduleName), Move(funcName));
+    return link->importNames.emplaceBack(Move(moduleName), Move(funcName));
 }
 
 static bool
-DecodeImportSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init, ImportNameVector* imports)
+DecodeImportSection(JSContext* cx, Decoder& d, ModuleGeneratorData* init, DynamicLinkData* link)
 {
     if (!d.readCStringIf(ImportSection))
         return true;
 
     uint32_t sectionStart;
     if (!d.startSection(&sectionStart))
         return Fail(cx, d, "expected import section byte size");
 
     uint32_t numImports;
     if (!d.readVarU32(&numImports))
         return Fail(cx, d, "expected number of imports");
 
     if (numImports > MaxImports)
         return Fail(cx, d, "too many imports");
 
     for (uint32_t i = 0; i < numImports; i++) {
-        if (!DecodeImport(cx, d, init, imports))
+        if (!DecodeImport(cx, d, init, link))
             return false;
     }
 
     if (!d.finishSection(sectionStart))
         return Fail(cx, d, "import section byte size mismatch");
 
     return true;
 }
 
 static bool
-DecodeExport(JSContext* cx, Decoder& d, ModuleGenerator& mg, ExportMap* exportMap)
+DecodeExport(JSContext* cx, Decoder& d, ModuleGenerator& mg, DynamicLinkData* link)
 {
     if (!d.readCStringIf(FuncSubsection))
         return Fail(cx, d, "expected 'func' tag");
 
     uint32_t funcIndex;
     if (!d.readVarU32(&funcIndex))
         return Fail(cx, d, "expected export internal index");
 
     if (funcIndex >= mg.numFuncSigs())
         return Fail(cx, d, "export function index out of range");
 
     uint32_t exportIndex;
     if (!mg.declareExport(funcIndex, &exportIndex))
         return false;
 
-    MOZ_ASSERT(exportIndex <= exportMap->exportNames.length());
-    if (exportIndex == exportMap->exportNames.length()) {
+    ExportMap& exportMap = link->exportMap;
+
+    MOZ_ASSERT(exportIndex <= exportMap.exportNames.length());
+    if (exportIndex == exportMap.exportNames.length()) {
         UniqueChars funcName(JS_smprintf("%u", unsigned(funcIndex)));
-        if (!funcName || !exportMap->exportNames.emplaceBack(Move(funcName)))
+        if (!funcName || !exportMap.exportNames.emplaceBack(Move(funcName)))
             return false;
     }
 
-    if (!exportMap->fieldsToExports.append(exportIndex))
+    if (!exportMap.fieldsToExports.append(exportIndex))
         return false;
 
     const char* chars;
     if (!d.readCString(&chars))
         return Fail(cx, d, "expected export external name string");
 
-    return exportMap->fieldNames.emplaceBack(DuplicateString(chars));
+    return exportMap.fieldNames.emplaceBack(DuplicateString(chars));
 }
 
 typedef HashSet<const char*, CStringHasher> CStringSet;
 
 static bool
-DecodeExportsSection(JSContext* cx, Decoder& d, ModuleGenerator& mg, ExportMap* exportMap)
+DecodeExportsSection(JSContext* cx, Decoder& d, ModuleGenerator& mg, DynamicLinkData* link)
 {
     if (!d.readCStringIf(ExportSection))
         return true;
 
     uint32_t sectionStart;
     if (!d.startSection(&sectionStart))
         return Fail(cx, d, "expected export section byte size");
 
     uint32_t numExports;
     if (!d.readVarU32(&numExports))
         return Fail(cx, d, "expected number of exports");
 
     if (numExports > MaxExports)
         return Fail(cx, d, "too many exports");
 
     for (uint32_t i = 0; i < numExports; i++) {
-        if (!DecodeExport(cx, d, mg, exportMap))
+        if (!DecodeExport(cx, d, mg, link))
             return false;
     }
 
     if (!d.finishSection(sectionStart))
         return Fail(cx, d, "export section byte size mismatch");
 
     CStringSet dupSet(cx);
     if (!dupSet.init())
         return false;
-    for (const UniqueChars& prevName : exportMap->fieldNames) {
+    for (const UniqueChars& prevName : link->exportMap.fieldNames) {
         CStringSet::AddPtr p = dupSet.lookupForAdd(prevName.get());
         if (p)
             return Fail(cx, d, "duplicate export");
         if (!dupSet.add(p, prevName.get()))
             return false;
     }
 
     return true;
@@ -682,30 +695,38 @@ DecodeCodeSection(JSContext* cx, Decoder
         return false;
 
     return true;
 }
 
 static bool
 DecodeUnknownSection(JSContext* cx, Decoder& d)
 {
-    const char* unused;
-    if (!d.readCString(&unused))
+    const char* sectionName;
+    if (!d.readCString(&sectionName))
         return Fail(cx, d, "failed to read section name");
 
+    if (!strcmp(sectionName, SigSection) ||
+        !strcmp(sectionName, ImportSection) ||
+        !strcmp(sectionName, DeclSection) ||
+        !strcmp(sectionName, ExportSection) ||
+        !strcmp(sectionName, CodeSection))
+    {
+        return Fail(cx, d, "known section out of order");
+    }
+
     if (!d.skipSection())
         return Fail(cx, d, "unable to skip unknown section");
 
     return true;
 }
 
 static bool
 DecodeModule(JSContext* cx, UniqueChars filename, const uint8_t* bytes, uint32_t length,
-             ImportNameVector* importNames, ExportMap* exportMap,
-             MutableHandle<WasmModuleObject*> moduleObj)
+             UniqueDynamicLinkData* dynamicLink, MutableHandle<WasmModuleObject*> moduleObj)
 {
     Decoder d(bytes, bytes + length);
 
     uint32_t u32;
     if (!d.readU32(&u32) || u32 != MagicNumber)
         return Fail(cx, d, "failed to match magic number");
 
     if (!d.readU32(&u32) || u32 != EncodingVersion)
@@ -713,58 +734,60 @@ DecodeModule(JSContext* cx, UniqueChars 
 
     UniqueModuleGeneratorData init = MakeUnique<ModuleGeneratorData>();
     if (!init)
         return false;
 
     if (!DecodeSignatureSection(cx, d, init.get()))
         return false;
 
-    if (!DecodeDeclarationSection(cx, d, init.get()))
+    *dynamicLink = MakeUnique<DynamicLinkData>();
+    if (!*dynamicLink)
         return false;
 
-    if (!DecodeImportSection(cx, d, init.get(), importNames))
+    if (!DecodeImportSection(cx, d, init.get(), dynamicLink->get()))
+        return false;
+
+    if (!DecodeDeclarationSection(cx, d, init.get()))
         return false;
 
     ModuleGenerator mg(cx);
-    if (!mg.init(Move(init)))
+    if (!mg.init(Move(init), Move(filename)))
         return false;
 
-    if (!DecodeExportsSection(cx, d, mg, exportMap))
+    if (!DecodeExportsSection(cx, d, mg, dynamicLink->get()))
         return false;
 
-    HeapUsage heapUsage = HeapUsage::None;
-
     if (!DecodeCodeSection(cx, d, mg))
         return false;
 
     CacheableCharsVector funcNames;
 
     while (!d.readCStringIf(EndSection)) {
         if (!DecodeUnknownSection(cx, d))
             return false;
     }
 
     if (!d.done())
         return Fail(cx, d, "failed to consume all bytes of module");
 
     UniqueModuleData module;
-    UniqueStaticLinkData link;
+    UniqueStaticLinkData staticLink;
     SlowFunctionVector slowFuncs(cx);
-    if (!mg.finish(heapUsage, Move(filename), Move(funcNames), &module, &link, &slowFuncs))
+    if (!mg.finish(Move(funcNames), &module, &staticLink, &slowFuncs))
         return false;
 
     moduleObj.set(WasmModuleObject::create(cx));
     if (!moduleObj)
         return false;
 
     if (!moduleObj->init(cx->new_<Module>(Move(module))))
         return false;
 
-    return moduleObj->module().staticallyLink(cx, *link);
+    return moduleObj->module().staticallyLink(cx, *staticLink);
 }
 
 /*****************************************************************************/
 // JS entry points
 
 static bool
 GetProperty(JSContext* cx, HandleObject obj, const char* utf8Chars, MutableHandleValue v)
 {
@@ -882,37 +905,36 @@ WasmEval(JSContext* cx, unsigned argc, V
         }
         importObj = &args[1].toObject();
     }
 
     UniqueChars filename;
     if (!DescribeScriptedCaller(cx, &filename))
         return false;
 
-    ImportNameVector importNames;
-    ExportMap exportMap;
+    UniqueDynamicLinkData link;
     Rooted<WasmModuleObject*> moduleObj(cx);
-    if (!DecodeModule(cx, Move(filename), bytes, length, &importNames, &exportMap, &moduleObj)) {
+    if (!DecodeModule(cx, Move(filename), bytes, length, &link, &moduleObj)) {
         if (!cx->isExceptionPending())
             ReportOutOfMemory(cx);
         return false;
     }
 
     Module& module = moduleObj->module();
 
     Rooted<ArrayBufferObject*> heap(cx);
     if (module.usesHeap())
         return Fail(cx, "Heap not implemented yet");
 
     Rooted<FunctionVector> imports(cx, FunctionVector(cx));
-    if (!ImportFunctions(cx, importObj, importNames, &imports))
+    if (!ImportFunctions(cx, importObj, link->importNames, &imports))
         return false;
 
     RootedObject exportObj(cx);
-    if (!module.dynamicallyLink(cx, moduleObj, heap, imports, exportMap, &exportObj))
+    if (!module.dynamicallyLink(cx, moduleObj, heap, imports, link->exportMap, &exportObj))
         return false;
 
     args.rval().setObject(*exportObj);
     return true;
 }
 
 static bool
 WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp)
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -36,18 +36,18 @@ static const unsigned MaxExports     =  
 static const unsigned MaxArgsPerFunc =   4 * 1024;
 
 // Module header constants
 static const uint32_t MagicNumber = 0x6d736100; // "\0asm"
 static const uint32_t EncodingVersion = -1;     // experimental
 
 // Module section names:
 static const char SigSection[] =     "sig";
+static const char ImportSection[] =  "import";
 static const char DeclSection[] =    "decl";
-static const char ImportSection[] =  "import";
 static const char ExportSection[] =  "export";
 static const char CodeSection[] =    "code";
 static const char EndSection[] =     "";
 
 // Subsection names:
 static const char FuncSubsection[] = "func";
 
 enum class Expr : uint16_t
--- a/js/src/asmjs/WasmGenerator.cpp
+++ b/js/src/asmjs/WasmGenerator.cpp
@@ -98,28 +98,30 @@ ParallelCompilationEnabled(ExclusiveCont
         return false;
 
     // If 'cx' isn't a JSContext, then we are already off the main thread so
     // off-thread compilation must be enabled.
     return !cx->isJSContext() || cx->asJSContext()->runtime()->canUseOffthreadIonCompilation();
 }
 
 bool
-ModuleGenerator::init(UniqueModuleGeneratorData shared, ModuleKind kind)
+ModuleGenerator::init(UniqueModuleGeneratorData shared, UniqueChars filename, ModuleKind kind)
 {
     if (!funcIndexToExport_.init())
         return false;
 
     module_ = MakeUnique<ModuleData>();
     if (!module_)
         return false;
 
     module_->globalBytes = InitialGlobalDataBytes;
     module_->compileArgs = CompileArgs(cx_);
     module_->kind = kind;
+    module_->heapUsage = HeapUsage::None;
+    module_->filename = Move(filename);
 
     link_ = MakeUnique<StaticLinkData>();
     if (!link_)
         return false;
 
     // For asm.js, the Vectors in ModuleGeneratorData are max-sized reservations
     // and will be initialized in a linear order via init* functions as the
     // module is generated. For wasm, the Vectors are correctly-sized and
@@ -264,16 +266,23 @@ ModuleGenerator::allocateGlobalVar(ValTy
     if (!allocateGlobalBytes(width, width, &offset))
         return false;
 
     *index = shared_->globals.length();
     return shared_->globals.append(AsmJSGlobalVariable(ToExprType(type), offset, isConst));
 }
 
 void
+ModuleGenerator::initHeapUsage(HeapUsage heapUsage)
+{
+    MOZ_ASSERT(module_->heapUsage == HeapUsage::None);
+    module_->heapUsage = heapUsage;
+}
+
+void
 ModuleGenerator::initSig(uint32_t sigIndex, Sig&& sig)
 {
     MOZ_ASSERT(isAsmJS());
     MOZ_ASSERT(sigIndex == numSigs_);
     numSigs_++;
 
     MOZ_ASSERT(shared_->sigs[sigIndex] == Sig());
     shared_->sigs[sigIndex] = Move(sig);
@@ -367,16 +376,22 @@ ModuleGenerator::declareExport(uint32_t 
 }
 
 uint32_t
 ModuleGenerator::exportFuncIndex(uint32_t index) const
 {
     return exportFuncIndices_[index];
 }
 
+uint32_t
+ModuleGenerator::exportEntryOffset(uint32_t index) const
+{
+    return funcEntryOffsets_[exportFuncIndices_[index]];
+}
+
 const Sig&
 ModuleGenerator::exportSig(uint32_t index) const
 {
     return module_->exports[index].sig();
 }
 
 uint32_t
 ModuleGenerator::numExports() const
@@ -599,31 +614,27 @@ bool
 ModuleGenerator::defineOutOfBoundsStub(Offsets offsets)
 {
     MOZ_ASSERT(finishedFuncs_);
     link_->pod.outOfBoundsOffset = offsets.begin;
     return module_->codeRanges.emplaceBack(CodeRange::Inline, offsets);
 }
 
 bool
-ModuleGenerator::finish(HeapUsage heapUsage,
-                        CacheableChars filename,
-                        CacheableCharsVector&& prettyFuncNames,
+ModuleGenerator::finish(CacheableCharsVector&& prettyFuncNames,
                         UniqueModuleData* module,
                         UniqueStaticLinkData* linkData,
                         SlowFunctionVector* slowFuncs)
 {
     MOZ_ASSERT(!activeFunc_);
     MOZ_ASSERT(finishedFuncs_);
 
-    module_->heapUsage = heapUsage;
-    module_->filename = Move(filename);
     module_->prettyFuncNames = Move(prettyFuncNames);
 
-    if (!GenerateStubs(*this, UsesHeap(heapUsage)))
+    if (!GenerateStubs(*this, UsesHeap(module_->heapUsage)))
         return false;
 
     masm_.finish();
     if (masm_.oom())
         return false;
 
     // Start global data on a new page so JIT code may be given independent
     // protection flags. Note assumption that global data starts right after
--- a/js/src/asmjs/WasmGenerator.h
+++ b/js/src/asmjs/WasmGenerator.h
@@ -161,27 +161,29 @@ class MOZ_STACK_CLASS ModuleGenerator
     bool addImport(const Sig& sig, uint32_t globalDataOffset);
     bool startedFuncDefs() const { return !!threadView_; }
     bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset);
 
   public:
     explicit ModuleGenerator(ExclusiveContext* cx);
     ~ModuleGenerator();
 
-    bool init(UniqueModuleGeneratorData shared, ModuleKind = ModuleKind::Wasm);
+    bool init(UniqueModuleGeneratorData shared, UniqueChars filename, ModuleKind = ModuleKind::Wasm);
 
     bool isAsmJS() const { return module_->kind == ModuleKind::AsmJS; }
     CompileArgs args() const { return module_->compileArgs; }
     jit::MacroAssembler& masm() { return masm_; }
-    const Uint32Vector& funcEntryOffsets() const { return funcEntryOffsets_; }
 
     // asm.js global variables:
     bool allocateGlobalVar(ValType type, bool isConst, uint32_t* index);
     const AsmJSGlobalVariable& globalVar(unsigned index) const { return shared_->globals[index]; }
 
+    // Heap usage:
+    void initHeapUsage(HeapUsage heapUsage);
+
     // Signatures:
     void initSig(uint32_t sigIndex, Sig&& sig);
     uint32_t numSigs() const { return numSigs_; }
     const DeclaredSig& sig(uint32_t sigIndex) const;
 
     // Function declarations:
     bool initFuncSig(uint32_t funcIndex, uint32_t sigIndex);
     uint32_t numFuncSigs() const { return module_->numFuncs; }
@@ -192,16 +194,17 @@ class MOZ_STACK_CLASS ModuleGenerator
     uint32_t numImports() const;
     const ModuleImportGeneratorData& import(uint32_t index) const;
     bool defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit);
 
     // Exports:
     bool declareExport(uint32_t funcIndex, uint32_t* exportIndex);
     uint32_t numExports() const;
     uint32_t exportFuncIndex(uint32_t index) const;
+    uint32_t exportEntryOffset(uint32_t index) const;
     const Sig& exportSig(uint32_t index) const;
     bool defineExport(uint32_t index, Offsets offsets);
 
     // Function definitions:
     bool startFuncDefs();
     bool startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg);
     bool finishFuncDef(uint32_t funcIndex, unsigned generateTime, FunctionGenerator* fg);
     bool finishFuncDefs();
@@ -215,19 +218,17 @@ class MOZ_STACK_CLASS ModuleGenerator
     bool defineInlineStub(Offsets offsets);
     bool defineSyncInterruptStub(ProfilingOffsets offsets);
     bool defineAsyncInterruptStub(Offsets offsets);
     bool defineOutOfBoundsStub(Offsets offsets);
 
     // Return a ModuleData object which may be used to construct a Module, the
     // StaticLinkData required to call Module::staticallyLink, and the list of
     // functions that took a long time to compile.
-    bool finish(HeapUsage heapUsage,
-                CacheableChars filename,
-                CacheableCharsVector&& prettyFuncNames,
+    bool finish(CacheableCharsVector&& prettyFuncNames,
                 UniqueModuleData* module,
                 UniqueStaticLinkData* staticLinkData,
                 SlowFunctionVector* slowFuncs);
 };
 
 // A FunctionGenerator encapsulates the generation of a single function body.
 // ModuleGenerator::startFunc must be called after construction and before doing
 // anything else. After the body is complete, ModuleGenerator::finishFunc must
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -231,17 +231,17 @@ GenerateEntry(ModuleGenerator& mg, unsig
             }
             break;
         }
     }
 
     // Call into the real function.
     masm.assertStackAlignment(AsmJSStackAlignment);
     Label target;
-    target.bind(mg.funcEntryOffsets()[mg.exportFuncIndex(exportIndex)]);
+    target.bind(mg.exportEntryOffset(exportIndex));
     masm.call(CallSiteDesc(CallSiteDesc::Relative), &target);
 
     // Recover the stack pointer value before dynamic alignment.
     masm.loadWasmActivation(scratch);
     masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
     masm.setFramePushed(FramePushedForEntrySP);
 
     // Recover the 'argv' pointer which was saved before aligning the stack.
--- a/js/src/asmjs/WasmText.cpp
+++ b/js/src/asmjs/WasmText.cpp
@@ -83,99 +83,91 @@ class WasmAstSig : public WasmAstBase
     static HashNumber hash(Lookup sig) {
         return AddContainerToHash(sig.args(), HashNumber(sig.ret()));
     }
     static bool match(const WasmAstSig* lhs, Lookup rhs) {
         return lhs->ret() == rhs.ret() && EqualContainers(lhs->args(), rhs.args());
     }
 };
 
-enum class WasmAstKind
+class WasmAstNode : public WasmAstBase
+{};
+
+enum class WasmAstExprKind
 {
     BinaryOperator,
     Block,
     Call,
     Const,
-    Export,
-    Func,
     GetLocal,
-    Import,
-    Module,
     Nop,
     SetLocal
 };
 
-class WasmAstNode : public WasmAstBase
-{
-    const WasmAstKind kind_;
-
-  public:
-    explicit WasmAstNode(WasmAstKind kind)
-      : kind_(kind)
-    {}
-    WasmAstKind kind() const { return kind_; }
-};
-
 class WasmAstExpr : public WasmAstNode
 {
+    const WasmAstExprKind kind_;
+
   protected:
-    explicit WasmAstExpr(WasmAstKind kind)
-      : WasmAstNode(kind)
+    explicit WasmAstExpr(WasmAstExprKind kind)
+      : kind_(kind)
     {}
 
   public:
+    WasmAstExprKind kind() const { return kind_; }
+
     template <class T>
     T& as() {
         MOZ_ASSERT(kind() == T::Kind);
         return static_cast<T&>(*this);
     }
 };
 
 struct WasmAstNop : WasmAstExpr
 {
     WasmAstNop()
-      : WasmAstExpr(WasmAstKind::Nop)
+      : WasmAstExpr(WasmAstExprKind::Nop)
     {}
 };
 
 class WasmAstConst : public WasmAstExpr
 {
     const Val val_;
 
   public:
-    static const WasmAstKind Kind = WasmAstKind::Const;
+    static const WasmAstExprKind Kind = WasmAstExprKind::Const;
     explicit WasmAstConst(Val val)
       : WasmAstExpr(Kind),
         val_(val)
     {}
     Val val() const { return val_; }
 };
 
 class WasmAstGetLocal : public WasmAstExpr
 {
     uint32_t localIndex_;
 
   public:
-    static const WasmAstKind Kind = WasmAstKind::GetLocal;
+    static const WasmAstExprKind Kind = WasmAstExprKind::GetLocal;
     explicit WasmAstGetLocal(uint32_t localIndex)
       : WasmAstExpr(Kind),
         localIndex_(localIndex)
     {}
     uint32_t localIndex() const {
         return localIndex_;
     }
 };
 
 class WasmAstSetLocal : public WasmAstExpr
 {
     uint32_t localIndex_;
     WasmAstExpr& value_;
 
   public:
-    static const WasmAstKind Kind = WasmAstKind::SetLocal;
+    static const WasmAstExprKind Kind = WasmAstExprKind::SetLocal;
     WasmAstSetLocal(uint32_t localIndex, WasmAstExpr& value)
       : WasmAstExpr(Kind),
         localIndex_(localIndex),
         value_(value)
     {}
     uint32_t localIndex() const {
         return localIndex_;
     }
@@ -184,33 +176,33 @@ class WasmAstSetLocal : public WasmAstEx
     }
 };
 
 class WasmAstBlock : public WasmAstExpr
 {
     WasmAstExprVector exprs_;
 
   public:
-    static const WasmAstKind Kind = WasmAstKind::Block;
+    static const WasmAstExprKind Kind = WasmAstExprKind::Block;
     explicit WasmAstBlock(WasmAstExprVector&& exprs)
       : WasmAstExpr(Kind),
         exprs_(Move(exprs))
     {}
 
     const WasmAstExprVector& exprs() const { return exprs_; }
 };
 
 class WasmAstCall : public WasmAstExpr
 {
     Expr expr_;
     uint32_t index_;
     WasmAstExprVector args_;
 
   public:
-    static const WasmAstKind Kind = WasmAstKind::Call;
+    static const WasmAstExprKind Kind = WasmAstExprKind::Call;
     WasmAstCall(Expr expr, uint32_t index, WasmAstExprVector&& args)
       : WasmAstExpr(Kind), expr_(expr), index_(index), args_(Move(args))
     {}
 
     Expr expr() const { return expr_; }
     uint32_t index() const { return index_; }
     const WasmAstExprVector& args() const { return args_; }
 };
@@ -218,49 +210,48 @@ class WasmAstCall : public WasmAstExpr
 class WasmAstFunc : public WasmAstNode
 {
     const uint32_t sigIndex_;
     WasmAstValTypeVector varTypes_;
     WasmAstExpr* const maybeBody_;
 
   public:
     WasmAstFunc(uint32_t sigIndex, WasmAstValTypeVector&& varTypes, WasmAstExpr* maybeBody)
-      : WasmAstNode(WasmAstKind::Func),
-        sigIndex_(sigIndex),
+      : sigIndex_(sigIndex),
         varTypes_(Move(varTypes)),
         maybeBody_(maybeBody)
     {}
     uint32_t sigIndex() const { return sigIndex_; }
     const WasmAstValTypeVector& varTypes() const { return varTypes_; }
     WasmAstExpr* maybeBody() const { return maybeBody_; }
 };
 
 class WasmAstImport : public WasmAstNode
 {
     TwoByteChars module_;
     TwoByteChars func_;
     uint32_t sigIndex_;
 
   public:
     WasmAstImport(TwoByteChars module, TwoByteChars func, uint32_t sigIndex)
-      : WasmAstNode(WasmAstKind::Import), module_(module), func_(func), sigIndex_(sigIndex)
+      : module_(module), func_(func), sigIndex_(sigIndex)
     {}
     TwoByteChars module() const { return module_; }
     TwoByteChars func() const { return func_; }
     uint32_t sigIndex() const { return sigIndex_; }
 };
 
 class WasmAstExport : public WasmAstNode
 {
     TwoByteChars name_;
     uint32_t funcIndex_;
 
   public:
     WasmAstExport(TwoByteChars name, uint32_t funcIndex)
-      : WasmAstNode(WasmAstKind::Export), name_(name), funcIndex_(funcIndex)
+      : name_(name), funcIndex_(funcIndex)
     {}
     TwoByteChars name() const { return name_; }
     size_t funcIndex() const { return funcIndex_; }
 };
 
 class WasmAstModule : public WasmAstNode
 {
     typedef WasmAstVector<WasmAstFunc*> FuncVector;
@@ -273,18 +264,17 @@ class WasmAstModule : public WasmAstNode
     FuncVector funcs_;
     ImportVector imports_;
     ExportVector exports_;
     SigVector sigs_;
     SigMap sigMap_;
 
   public:
     explicit WasmAstModule(LifoAlloc& lifo)
-      : WasmAstNode(WasmAstKind::Module),
-        lifo_(lifo),
+      : lifo_(lifo),
         funcs_(lifo),
         imports_(lifo),
         exports_(lifo),
         sigs_(lifo),
         sigMap_(lifo)
     {}
     bool init() {
         return sigMap_.init();
@@ -324,17 +314,17 @@ class WasmAstModule : public WasmAstNode
 
 class WasmAstBinaryOperator final : public WasmAstExpr
 {
     Expr expr_;
     WasmAstExpr* lhs_;
     WasmAstExpr* rhs_;
 
   public:
-    static const WasmAstKind Kind = WasmAstKind::BinaryOperator;
+    static const WasmAstExprKind Kind = WasmAstExprKind::BinaryOperator;
     explicit WasmAstBinaryOperator(Expr expr, WasmAstExpr* lhs, WasmAstExpr* rhs)
       : WasmAstExpr(Kind),
         expr_(expr), lhs_(lhs), rhs_(rhs)
     {}
 
     Expr expr() const { return expr_; }
     WasmAstExpr* lhs() const { return lhs_; }
     WasmAstExpr* rhs() const { return rhs_; }
@@ -499,20 +489,20 @@ class WasmTokenStream
     const char16_t* cur_;
     const char16_t* const end_;
     const char16_t* lineStart_;
     unsigned line_;
     uint32_t lookaheadIndex_;
     uint32_t lookaheadDepth_;
     WasmToken lookahead_[LookaheadSize];
 
-    bool consume(const char16_t* end, const char16_t* match) {
+    bool consume(const char16_t* match) {
         const char16_t* p = cur_;
         for (; *match; p++, match++) {
-            if (p == end || *p != *match)
+            if (p == end_ || *p != *match)
                 return false;
         }
         cur_ = p;
         return true;
     }
     WasmToken fail(const char16_t* begin) const {
         return WasmToken(begin);
     }
@@ -556,207 +546,207 @@ class WasmTokenStream
                 if (!u32.isValid())
                     return fail(begin);
                 cur_++;
             }
             return WasmToken(u32.value(), begin, cur_);
           }
 
           case 'b':
-            if (consume(end_, MOZ_UTF16("lock")))
+            if (consume(MOZ_UTF16("lock")))
                 return WasmToken(WasmToken::Block, begin, cur_);
             break;
 
           case 'c':
-            if (consume(end_, MOZ_UTF16("all"))) {
-                if (consume(end_, MOZ_UTF16("_import")))
+            if (consume(MOZ_UTF16("all"))) {
+                if (consume(MOZ_UTF16("_import")))
                     return WasmToken(WasmToken::CallImport, begin, cur_);
                 return WasmToken(WasmToken::Call, begin, cur_);
             }
             break;
 
           case 'e':
-            if (consume(end_, MOZ_UTF16("xport")))
+            if (consume(MOZ_UTF16("xport")))
                 return WasmToken(WasmToken::Export, begin, cur_);
             break;
 
           case 'f':
-            if (consume(end_, MOZ_UTF16("unc")))
+            if (consume(MOZ_UTF16("unc")))
                 return WasmToken(WasmToken::Func, begin, cur_);
 
-            if (consume(end_, MOZ_UTF16("32"))) {
-                if (!consume(end_, MOZ_UTF16(".")))
+            if (consume(MOZ_UTF16("32"))) {
+                if (!consume(MOZ_UTF16(".")))
                     return WasmToken(WasmToken::ValueType, ValType::F32, begin, cur_);
 
                 switch (*cur_) {
                   case 'a':
-                    if (consume(end_, MOZ_UTF16("add")))
+                    if (consume(MOZ_UTF16("add")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F32Add, begin, cur_);
                     break;
                   case 'c':
-                    if (consume(end_, MOZ_UTF16("const")))
+                    if (consume(MOZ_UTF16("const")))
                         return WasmToken(WasmToken::Const, ValType::F32, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("copysign")))
+                    if (consume(MOZ_UTF16("copysign")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F32CopySign, begin, cur_);
                     break;
                   case 'd':
-                    if (consume(end_, MOZ_UTF16("div")))
+                    if (consume(MOZ_UTF16("div")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F32Div, begin, cur_);
                     break;
                   case 'm':
-                    if (consume(end_, MOZ_UTF16("max")))
+                    if (consume(MOZ_UTF16("max")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F32Max, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("min")))
+                    if (consume(MOZ_UTF16("min")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F32Min, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("mul")))
+                    if (consume(MOZ_UTF16("mul")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F32Mul, begin, cur_);
                     break;
                   case 's':
-                    if (consume(end_, MOZ_UTF16("sub")))
+                    if (consume(MOZ_UTF16("sub")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F32Sub, begin, cur_);
                     break;
                 }
                 break;
             }
-            if (consume(end_, MOZ_UTF16("64"))) {
-                if (!consume(end_, MOZ_UTF16(".")))
+            if (consume(MOZ_UTF16("64"))) {
+                if (!consume(MOZ_UTF16(".")))
                     return WasmToken(WasmToken::ValueType, ValType::F64, begin, cur_);
 
                 switch (*cur_) {
                   case 'a':
-                    if (consume(end_, MOZ_UTF16("add")))
+                    if (consume(MOZ_UTF16("add")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F64Add, begin, cur_);
                     break;
                   case 'c':
-                    if (consume(end_, MOZ_UTF16("const")))
+                    if (consume(MOZ_UTF16("const")))
                         return WasmToken(WasmToken::Const, ValType::F64, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("copysign")))
+                    if (consume(MOZ_UTF16("copysign")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F64CopySign, begin, cur_);
                     break;
                   case 'd':
-                    if (consume(end_, MOZ_UTF16("div")))
+                    if (consume(MOZ_UTF16("div")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F64Div, begin, cur_);
                     break;
                   case 'm':
-                    if (consume(end_, MOZ_UTF16("max")))
+                    if (consume(MOZ_UTF16("max")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F64Max, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("min")))
+                    if (consume(MOZ_UTF16("min")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F64Min, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("mul")))
+                    if (consume(MOZ_UTF16("mul")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F64Mul, begin, cur_);
                     break;
                   case 's':
-                    if (consume(end_, MOZ_UTF16("sub")))
+                    if (consume(MOZ_UTF16("sub")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::F64Sub, begin, cur_);
                     break;
                 }
             }
             break;
 
           case 'g':
-            if (consume(end_, MOZ_UTF16("et_local")))
+            if (consume(MOZ_UTF16("et_local")))
                 return WasmToken(WasmToken::GetLocal, begin, cur_);
             break;
 
           case 'i':
-            if (consume(end_, MOZ_UTF16("32"))) {
-                if (!consume(end_, MOZ_UTF16(".")))
+            if (consume(MOZ_UTF16("32"))) {
+                if (!consume(MOZ_UTF16(".")))
                     return WasmToken(WasmToken::ValueType, ValType::I32, begin, cur_);
 
                 switch (*cur_) {
                   case 'a':
-                    if (consume(end_, MOZ_UTF16("add")))
+                    if (consume(MOZ_UTF16("add")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32Add, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("and")))
+                    if (consume(MOZ_UTF16("and")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32And, begin, cur_);
                     break;
                   case 'c':
-                    if (consume(end_, MOZ_UTF16("const")))
+                    if (consume(MOZ_UTF16("const")))
                         return WasmToken(WasmToken::Const, ValType::I32, begin, cur_);
                     break;
                   case 'd':
-                    if (consume(end_, MOZ_UTF16("div_s")))
+                    if (consume(MOZ_UTF16("div_s")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32DivS, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("div_u")))
+                    if (consume(MOZ_UTF16("div_u")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32DivU, begin, cur_);
                     break;
                   case 'm':
-                    if (consume(end_, MOZ_UTF16("mul")))
+                    if (consume(MOZ_UTF16("mul")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32Mul, begin, cur_);
                     break;
                   case 'o':
-                    if (consume(end_, MOZ_UTF16("or")))
+                    if (consume(MOZ_UTF16("or")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32Or, begin, cur_);
                     break;
                   case 'r':
-                    if (consume(end_, MOZ_UTF16("rem_s")))
+                    if (consume(MOZ_UTF16("rem_s")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32RemS, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("rem_u")))
+                    if (consume(MOZ_UTF16("rem_u")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32RemU, begin, cur_);
                     break;
                   case 's':
-                    if (consume(end_, MOZ_UTF16("sub")))
+                    if (consume(MOZ_UTF16("sub")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32Sub, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("shl")))
+                    if (consume(MOZ_UTF16("shl")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32Shl, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("shr_s")))
+                    if (consume(MOZ_UTF16("shr_s")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32ShrS, begin, cur_);
-                    if (consume(end_, MOZ_UTF16("shr_u")))
+                    if (consume(MOZ_UTF16("shr_u")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32ShrU, begin, cur_);
                     break;
                   case 'x':
-                    if (consume(end_, MOZ_UTF16("xor")))
+                    if (consume(MOZ_UTF16("xor")))
                         return WasmToken(WasmToken::BinaryOpcode, Expr::I32Xor, begin, cur_);
                     break;
                 }
                 break;
             }
-            if (consume(end_, MOZ_UTF16("64"))) {
-                if (!consume(end_, MOZ_UTF16(".")))
+            if (consume(MOZ_UTF16("64"))) {
+                if (!consume(MOZ_UTF16(".")))
                     return WasmToken(WasmToken::ValueType, ValType::I64, begin, cur_);
 
                 switch (*cur_) {
                   case 'c':
-                    if (consume(end_, MOZ_UTF16("const")))
+                    if (consume(MOZ_UTF16("const")))
                         return WasmToken(WasmToken::Const, ValType::I64, begin, cur_);
                     break;
                 }
                 break;
             }
-            if (consume(end_, MOZ_UTF16("mport")))
+            if (consume(MOZ_UTF16("mport")))
                 return WasmToken(WasmToken::Import, begin, cur_);
             break;
 
           case 'l':
-            if (consume(end_, MOZ_UTF16("ocal")))
+            if (consume(MOZ_UTF16("ocal")))
                 return WasmToken(WasmToken::Local, begin, cur_);
             break;
 
           case 'm':
-            if (consume(end_, MOZ_UTF16("odule")))
+            if (consume(MOZ_UTF16("odule")))
                 return WasmToken(WasmToken::Module, begin, cur_);
             break;
 
           case 'n':
-            if (consume(end_, MOZ_UTF16("op")))
+            if (consume(MOZ_UTF16("op")))
                 return WasmToken(WasmToken::Nop, begin, cur_);
             break;
 
           case 'p':
-            if (consume(end_, MOZ_UTF16("aram")))
+            if (consume(MOZ_UTF16("aram")))
                 return WasmToken(WasmToken::Param, begin, cur_);
             break;
 
           case 'r':
-            if (consume(end_, MOZ_UTF16("esult")))
+            if (consume(MOZ_UTF16("esult")))
                 return WasmToken(WasmToken::Result, begin, cur_);
             break;
 
           case 's':
-            if (consume(end_, MOZ_UTF16("et_local")))
+            if (consume(MOZ_UTF16("et_local")))
                 return WasmToken(WasmToken::SetLocal, begin, cur_);
             break;
 
           default:
             break;
         }
 
         return fail(begin);
@@ -1222,29 +1212,29 @@ EncodeBinaryOperator(Encoder& e, WasmAst
            EncodeExpr(e, *b.lhs()) &&
            EncodeExpr(e, *b.rhs());
 }
 
 static bool
 EncodeExpr(Encoder& e, WasmAstExpr& expr)
 {
     switch (expr.kind()) {
-      case WasmAstKind::Nop:
+      case WasmAstExprKind::Nop:
         return e.writeExpr(Expr::Nop);
-      case WasmAstKind::BinaryOperator:
+      case WasmAstExprKind::BinaryOperator:
         return EncodeBinaryOperator(e, expr.as<WasmAstBinaryOperator>());
-      case WasmAstKind::Block:
+      case WasmAstExprKind::Block:
         return EncodeBlock(e, expr.as<WasmAstBlock>());
-      case WasmAstKind::Call:
+      case WasmAstExprKind::Call:
         return EncodeCall(e, expr.as<WasmAstCall>());
-      case WasmAstKind::Const:
+      case WasmAstExprKind::Const:
         return EncodeConst(e, expr.as<WasmAstConst>());
-      case WasmAstKind::GetLocal:
+      case WasmAstExprKind::GetLocal:
         return EncodeGetLocal(e, expr.as<WasmAstGetLocal>());
-      case WasmAstKind::SetLocal:
+      case WasmAstExprKind::SetLocal:
         return EncodeSetLocal(e, expr.as<WasmAstSetLocal>());
       default:;
     }
     MOZ_CRASH("Bad expr kind");
 }
 
 /*****************************************************************************/
 // wasm AST binary serialization
@@ -1471,20 +1461,20 @@ AstToBinary(WasmAstModule& module)
         return nullptr;
 
     if (!e.writeU32(EncodingVersion))
         return nullptr;
 
     if (!EncodeSignatureSection(e, module))
         return nullptr;
 
-    if (!EncodeDeclarationSection(e, module))
+    if (!EncodeImportSection(e, module))
         return nullptr;
 
-    if (!EncodeImportSection(e, module))
+    if (!EncodeDeclarationSection(e, module))
         return nullptr;
 
     if (!EncodeExportSection(e, module))
         return nullptr;
 
     if (!EncodeCodeSection(e, module))
         return nullptr;
 
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -34,31 +34,16 @@ using mozilla::IsNaN;
 using mozilla::FloorLog2;
 using mozilla::NumberIsInt32;
 
 ///////////////////////////////////////////////////////////////////////////
 // SIMD
 
 static_assert(unsigned(SimdType::Count) == 12, "sync with TypedObjectConstants.h");
 
-bool
-js::IsSignedIntSimdType(SimdType type)
-{
-    switch (type) {
-      case SimdType::Int32x4:
-        return true;
-      case SimdType::Float32x4:
-      case SimdType::Bool32x4:
-        return false;
-      default:
-        break;
-   }
-    MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unknown SIMD type");
-}
-
 PropertyName*
 js::SimdTypeToName(JSContext* cx, SimdType type)
 {
     switch (type) {
       case SimdType::Int32x4:   return cx->names().Int32x4;
       case SimdType::Float32x4: return cx->names().Float32x4;
       case SimdType::Bool32x4:  return cx->names().Bool32x4;
       default:                  break;
@@ -135,17 +120,17 @@ ErrorWrongTypeArg(JSContext* cx, size_t 
     return false;
 }
 
 template<typename T>
 static SimdTypeDescr*
 GetTypeDescr(JSContext* cx)
 {
     RootedGlobalObject global(cx, cx->global());
-    return GlobalObject::getOrCreateSimdTypeDescr<T>(cx, global);
+    return GlobalObject::getOrCreateSimdTypeDescr(cx, global, T::type);
 }
 
 template<typename V>
 bool
 js::ToSimdConstant(JSContext* cx, HandleValue v, jit::SimdConstant* out)
 {
     typedef typename V::Elem Elem;
     Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx));
@@ -247,16 +232,20 @@ namespace jit {
 #define TDEFN(Name, Func, Operands) DEFN(Float32x4, Name)
 FLOAT32X4_FUNCTION_LIST(TDEFN)
 #undef TDEFN
 
 #define TDEFN(Name, Func, Operands) DEFN(Int32x4, Name)
 INT32X4_FUNCTION_LIST(TDEFN)
 #undef TDEFN
 
+#define TDEFN(Name, Func, Operands) DEFN(Uint32x4, Name)
+UINT32X4_FUNCTION_LIST(TDEFN)
+#undef TDEFN
+
 #define TDEFN(Name, Func, Operands) DEFN(Bool32x4, Name)
 BOOL32X4_FUNCTION_LIST(TDEFN)
 #undef TDEFN
 
 } // namespace jit
 } // namespace js
 
 const JSFunctionSpec Float32x4Defn::Methods[] = {
@@ -312,17 +301,17 @@ const JSFunctionSpec Uint16x8Defn::Metho
     JS_FN(#Name, js::simd_uint16x8_##Name, Operands, 0),
     UINT16X8_FUNCTION_LIST(SIMD_UINT16X8_FUNCTION_ITEM)
 #undef SIMD_UINT16X8_FUNCTION_ITEM
     JS_FS_END
 };
 
 const JSFunctionSpec Uint32x4Defn::Methods[] = {
 #define SIMD_UINT32X4_FUNCTION_ITEM(Name, Func, Operands) \
-    JS_FN(#Name, js::simd_uint32x4_##Name, Operands, 0),
+    JS_INLINABLE_FN(#Name, js::simd_uint32x4_##Name, Operands, 0, SimdUint32x4_##Name),
     UINT32X4_FUNCTION_LIST(SIMD_UINT32X4_FUNCTION_ITEM)
 #undef SIMD_UINT32X4_FUNCTION_ITEM
     JS_FS_END
 };
 
 const JSFunctionSpec Bool8x16Defn::Methods[] = {
 #define SIMD_BOOL8X16_FUNCTION_ITEM(Name, Func, Operands) \
     JS_FN(#Name, js::simd_bool8x16_##Name, Operands, 0),
@@ -436,31 +425,30 @@ GlobalObject::initSimdObject(JSContext* 
     {
         return false;
     }
 
     global->setConstructor(JSProto_SIMD, globalSimdValue);
     return true;
 }
 
-template<typename /* TypeDefn */ T>
 static bool
-CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName stringRepr)
+CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName stringRepr,
+               SimdType simdType, const JSFunctionSpec* methods)
 {
     RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
     if (!funcProto)
         return false;
 
     // Create type constructor itself and initialize its reserved slots.
     Rooted<SimdTypeDescr*> typeDescr(cx);
     typeDescr = NewObjectWithGivenProto<SimdTypeDescr>(cx, funcProto, SingletonObject);
     if (!typeDescr)
         return false;
 
-    const SimdType simdType = T::type;
     typeDescr->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(type::Simd));
     typeDescr->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
     typeDescr->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(SimdTypeDescr::alignment(simdType)));
     typeDescr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(SimdTypeDescr::size(simdType)));
     typeDescr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false));
     typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(uint8_t(simdType)));
 
     if (!CreateUserSizeAndAlignmentProperties(cx, typeDescr))
@@ -486,55 +474,79 @@ CreateSimdType(JSContext* cx, Handle<Glo
         return false;
     }
 
     // Bind type descriptor to the global SIMD object
     RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx));
     MOZ_ASSERT(globalSimdObject);
 
     RootedValue typeValue(cx, ObjectValue(*typeDescr));
-    if (!JS_DefineFunctions(cx, typeDescr, T::Methods) ||
+    if (!JS_DefineFunctions(cx, typeDescr, methods) ||
         !DefineProperty(cx, globalSimdObject, stringRepr, typeValue, nullptr, nullptr,
                         JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_RESOLVING))
     {
         return false;
     }
 
     uint32_t slot = uint32_t(typeDescr->type());
     MOZ_ASSERT(globalSimdObject->as<NativeObject>().getReservedSlot(slot).isUndefined());
     globalSimdObject->as<NativeObject>().setReservedSlot(slot, ObjectValue(*typeDescr));
     return !!typeDescr;
 }
 
 bool
-GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, uint32_t simdTypeDescrType)
+GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType)
 {
 #define CREATE_(Type) \
-    case SimdType::Type: return CreateSimdType<Type##Defn>(cx, global, cx->names().Type);
+    case SimdType::Type: \
+      return CreateSimdType(cx, global, cx->names().Type, simdType, Type##Defn::Methods);
 
-    switch (SimdType(simdTypeDescrType)) {
+    switch (simdType) {
       FOR_EACH_SIMD(CREATE_)
       case SimdType::Count: break;
     }
     MOZ_CRASH("unexpected simd type");
 
 #undef CREATE_
 }
 
+SimdTypeDescr*
+GlobalObject::getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global,
+                                       SimdType simdType)
+{
+    MOZ_ASSERT(unsigned(simdType) < unsigned(SimdType::Count), "Invalid SIMD type");
+
+    RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx));
+    if (!globalSimdObject)
+       return nullptr;
+
+    uint32_t typeSlotIndex = uint32_t(simdType);
+    if (globalSimdObject->as<NativeObject>().getReservedSlot(typeSlotIndex).isUndefined() &&
+        !GlobalObject::initSimdType(cx, global, simdType))
+    {
+        return nullptr;
+    }
+
+    const Value& slot = globalSimdObject->as<NativeObject>().getReservedSlot(typeSlotIndex);
+    MOZ_ASSERT(slot.isObject());
+    return &slot.toObject().as<SimdTypeDescr>();
+}
+
 bool
 SimdObject::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolved)
 {
     *resolved = false;
     if (!JSID_IS_ATOM(id))
         return true;
     JSAtom* str = JSID_TO_ATOM(id);
     Rooted<GlobalObject*> global(cx, cx->global());
 #define TRY_RESOLVE_(Type)                                                    \
     if (str == cx->names().Type) {                                            \
-        *resolved = CreateSimdType<Type##Defn>(cx, global, cx->names().Type); \
+        *resolved = CreateSimdType(cx, global, cx->names().Type,              \
+                                   SimdType::Type, Type##Defn::Methods);      \
         return *resolved;                                                     \
     }
     FOR_EACH_SIMD(TRY_RESOLVE_)
 #undef TRY_RESOLVE_
     return true;
 }
 
 JSObject*
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -794,16 +794,89 @@ enum class SimdType : uint8_t {
     Float64x2 = JS_SIMDTYPEREPR_FLOAT64X2,
     Bool8x16  = JS_SIMDTYPEREPR_BOOL8X16,
     Bool16x8  = JS_SIMDTYPEREPR_BOOL16X8,
     Bool32x4  = JS_SIMDTYPEREPR_BOOL32X4,
     Bool64x2  = JS_SIMDTYPEREPR_BOOL64X2,
     Count
 };
 
+// The integer SIMD types have a lot of operations that do the exact same thing
+// for signed and unsigned integer types. Sometimes it is simpler to treat
+// signed and unsigned integer SIMD types as the same type, using a SimdSign to
+// distinguish the few cases where there is a difference.
+enum class SimdSign {
+    // Signedness is not applicable to this type. (i.e., Float or Bool).
+    NotApplicable,
+    // Treat as an unsigned integer with a range 0 .. 2^N-1.
+    Unsigned,
+    // Treat as a signed integer in two's complement encoding.
+    Signed,
+};
+
+// Get the signedness of a SIMD type.
+inline SimdSign
+GetSimdSign(SimdType t)
+{
+    switch(t) {
+      case SimdType::Int8x16:
+      case SimdType::Int16x8:
+      case SimdType::Int32x4:
+        return SimdSign::Signed;
+
+      case SimdType::Uint8x16:
+      case SimdType::Uint16x8:
+      case SimdType::Uint32x4:
+        return SimdSign::Unsigned;
+
+      default:
+        return SimdSign::NotApplicable;
+    }
+}
+
+inline bool
+IsSignedIntSimdType(SimdType type)
+{
+    return GetSimdSign(type) == SimdSign::Signed;
+}
+
+// Get the boolean SIMD type with the same shape as t.
+//
+// This is the result type of a comparison operation, and it can also be used to
+// identify the geometry of a SIMD type.
+inline SimdType
+GetBooleanSimdType(SimdType t)
+{
+    switch(t) {
+      case SimdType::Int8x16:
+      case SimdType::Uint8x16:
+      case SimdType::Bool8x16:
+        return SimdType::Bool8x16;
+
+      case SimdType::Int16x8:
+      case SimdType::Uint16x8:
+      case SimdType::Bool16x8:
+        return SimdType::Bool16x8;
+
+      case SimdType::Int32x4:
+      case SimdType::Uint32x4:
+      case SimdType::Float32x4:
+      case SimdType::Bool32x4:
+        return SimdType::Bool32x4;
+
+      case SimdType::Float64x2:
+      case SimdType::Bool64x2:
+        return SimdType::Bool64x2;
+
+      case SimdType::Count:
+        break;
+    }
+    MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad SIMD type");
+}
+
 // Complete set of SIMD operations.
 //
 // No SIMD types implement all of these operations.
 //
 // C++ defines keywords and/or/xor/not, so prepend Fn_ to all named functions to
 // avoid clashes.
 enum class SimdOperation : uint8_t {
     // The constructor call. No Fn_ prefix here.
@@ -1002,18 +1075,16 @@ struct Bool64x2 {
         *out = ToBoolean(v) ? -1 : 0;
         return true;
     }
     static Value ToValue(Elem value) {
         return BooleanValue(value);
     }
 };
 
-bool IsSignedIntSimdType(SimdType type);
-
 PropertyName* SimdTypeToName(JSContext* cx, SimdType type);
 
 template<typename V>
 JSObject* CreateSimd(JSContext* cx, const typename V::Elem* data);
 
 template<typename V>
 bool IsVectorObject(HandleValue v);
 
--- a/js/src/builtin/Sorting.js
+++ b/js/src/builtin/Sorting.js
@@ -1,16 +1,53 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // We use varying sorts across the self-hosted codebase. All sorts are
 // consolidated here to avoid confusion and re-implementation of existing
 // algorithms.
 
+// For sorting values with limited range; uint8 and int8.
+function CountingSort(array, len, signed) {
+    var buffer = new List();
+    var min = 0;
+
+    // Map int8 values onto the uint8 range when storing in buffer.
+    if (signed)  {
+        min = -128;
+    }
+
+    for (var i = 0; i  < 256; i++) {
+        buffer[i] = 0;
+    }
+
+    // Populate the buffer
+    for (var i = 0; i < len; i++) {
+        var val = array[i];
+        buffer[val - min]++
+    }
+
+    // Traverse the buffer in order and write back elements to array
+    var val = 0;
+    for (var i = 0; i < len; i++) {
+        // Invariant: sum(buffer[val:]) == len-i
+        while (true) {
+            if (buffer[val] > 0) {
+                array[i] = val + min;
+                buffer[val]--;
+                break;
+            } else {
+                val++;
+            }
+        }
+    }
+    return array;
+}
+
 // For sorting small arrays.
 function InsertionSort(array, from, to, comparefn) {
     var item, swap;
     for (var i = from + 1; i <= to; i++) {
         item = array[i];
         for (var j = i - 1; j >= from; j--) {
             swap = array[j];
             if (comparefn(swap, item) <= 0)
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -982,16 +982,23 @@ function TypedArraySort(comparefn) {
 
     // Step 2.
     var buffer = GetAttachedArrayBuffer(obj);
 
     // Step 3.
     var len = TypedArrayLength(obj);
 
     if (comparefn === undefined) {
+        // CountingSort doesn't invoke the comparefn
+        if (IsUint8TypedArray(obj)) {
+            return CountingSort(obj, len, false /* signed */);
+        } else if (IsInt8TypedArray(obj)) {
+            return CountingSort(obj, len, true /* signed */);
+        }
+
         comparefn = TypedArrayCompare;
     } else {
         // To satisfy step 2 from TypedArray SortCompare described in 22.2.3.26
         // the user supplied comparefn is wrapped.
         var wrappedCompareFn = comparefn;
         comparefn = function(x, y) {
             // Step a.
             var v = wrappedCompareFn(x, y);
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2594,132 +2594,28 @@ js::GetTypedObjectModule(JSContext* cx, 
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
     args.rval().setObject(global->getTypedObjectModule());
     return true;
 }
 
 bool
-js::GetFloat32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Float32x4>(cx, global));
-    return true;
-}
-
-bool
-js::GetFloat64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Float64x2>(cx, global));
-    return true;
-}
-
-bool
-js::GetInt8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp)
+js::GetSimdTypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Int8x16>(cx, global));
-    return true;
-}
-
-bool
-js::GetInt16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Int16x8>(cx, global));
-    return true;
-}
-
-bool
-js::GetInt32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Int32x4>(cx, global));
-    return true;
-}
-
-bool
-js::GetUint8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 1);
+    MOZ_ASSERT(args[0].isInt32());
+    // One of the JS_SIMDTYPEREPR_* constants / a SimdType enum value.
+    // getOrCreateSimdTypeDescr() will do the range check.
+    int32_t simdTypeRepr = args[0].toInt32();
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Uint8x16>(cx, global));
-    return true;
-}
-
-bool
-js::GetUint16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Uint16x8>(cx, global));
-    return true;
-}
-
-bool
-js::GetUint32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Uint32x4>(cx, global));
-    return true;
-}
-
-bool
-js::GetBool8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool8x16>(cx, global));
-    return true;
-}
-
-bool
-js::GetBool16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool16x8>(cx, global));
-    return true;
-}
-
-bool
-js::GetBool32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool32x4>(cx, global));
-    return true;
-}
-
-bool
-js::GetBool64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<GlobalObject*> global(cx, cx->global());
-    MOZ_ASSERT(global);
-    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool64x2>(cx, global));
+    auto* obj = GlobalObject::getOrCreateSimdTypeDescr(cx, global, SimdType(simdTypeRepr));
+    args.rval().setObject(*obj);
     return true;
 }
 
 #define JS_STORE_SCALAR_CLASS_IMPL(_constant, T, _name)                         \
 bool                                                                            \
 js::StoreScalar##T::Func(JSContext*, unsigned argc, Value* vp)         \
 {                                                                               \
     CallArgs args = CallArgsFromVp(argc, vp);                                   \
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -812,110 +812,24 @@ bool ClampToUint8(JSContext* cx, unsigne
  * to the various builtin type descriptors. These are currently
  * exported as immutable properties so it is safe for self-hosted code
  * to access them; eventually this should be linked into the module
  * system.
  */
 bool GetTypedObjectModule(JSContext* cx, unsigned argc, Value* vp);
 
 /*
- * Usage: GetFloat32x4TypeDescr()
- *
- * Returns the Float32x4 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
- */
-bool GetFloat32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Usage: GetFloat64x2TypeDescr()
- *
- * Returns the Float64x2 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
- */
-bool GetFloat64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Usage: GetBool8x16TypeDescr()
+ * Usage: GetSimdTypeDescr(simdTypeRepr)
  *
- * Returns the Bool8x16 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
- */
-bool GetBool8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Usage: GetBool16x8TypeDescr()
+ * Returns one of the SIMD type objects, identified by `simdTypeRepr` which must
+ * be one of the JS_SIMDTYPEREPR_* constants.
  *
- * Returns the Bool16x8 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
- */
-bool GetBool16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Usage: GetBool32x4TypeDescr()
- *
- * Returns the Bool32x4 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
- */
-bool GetBool32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Usage: GetBool64x2TypeDescr()
- *
- * Returns the Bool64x2 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
+ * The SIMD pseudo-module must have been initialized for this to be safe.
  */
-bool GetBool64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Usage: GetInt8x16TypeDescr()
- *
- * Returns the Int8x16 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
- */
-bool GetInt8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Usage: GetInt16x8TypeDescr()
- *
- * Returns the Int16x8 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
- */
-bool GetInt16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Usage: GetInt32x4TypeDescr()
- *
- * Returns the Int32x4 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
- */
-bool GetInt32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Usage: GetUint8x16TypeDescr()
- *
- * Returns the Uint8x16 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
- */
-bool GetUint8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Usage: GetUint16x8TypeDescr()
- *
- * Returns the Uint16x8 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
- */
-bool GetUint16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp);
-
-/*
- * Usage: GetUint32x4TypeDescr()
- *
- * Returns the Uint32x4 type object. SIMD pseudo-module must have
- * been initialized for this to be safe.
- */
-bool GetUint32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp);
+bool GetSimdTypeDescr(JSContext* cx, unsigned argc, Value* vp);
 
 /*
  * Usage: Store_int8(targetDatum, targetOffset, value)
  *        ...
  *        Store_uint8(targetDatum, targetOffset, value)
  *        ...
  *        Store_float32(targetDatum, targetOffset, value)
  *        Store_float64(targetDatum, targetOffset, value)
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -139,28 +139,29 @@ function TypedObjectGetReference(descr, 
   }
 
   assert(false, "Unhandled scalar type: " + type);
   return undefined;
 }
 
 function TypedObjectGetSimd(descr, typedObj, offset) {
   var type = DESCR_TYPE(descr);
+  var simdTypeDescr = GetSimdTypeDescr(type);
   switch (type) {
   case JS_SIMDTYPEREPR_FLOAT32X4:
     var x = Load_float32(typedObj, offset + 0);
     var y = Load_float32(typedObj, offset + 4);
     var z = Load_float32(typedObj, offset + 8);
     var w = Load_float32(typedObj, offset + 12);
-    return GetFloat32x4TypeDescr()(x, y, z, w);
+    return simdTypeDescr(x, y, z, w);
 
   case JS_SIMDTYPEREPR_FLOAT64X2:
     var x = Load_float64(typedObj, offset + 0);
     var y = Load_float64(typedObj, offset + 8);
-    return GetFloat64x2TypeDescr()(x, y);
+    return simdTypeDescr(x, y);
 
   case JS_SIMDTYPEREPR_INT8X16:
     var s0 = Load_int8(typedObj, offset + 0);
     var s1 = Load_int8(typedObj, offset + 1);
     var s2 = Load_int8(typedObj, offset + 2);
     var s3 = Load_int8(typedObj, offset + 3);
     var s4 = Load_int8(typedObj, offset + 4);
     var s5 = Load_int8(typedObj, offset + 5);
@@ -169,36 +170,35 @@ function TypedObjectGetSimd(descr, typed
     var s8 = Load_int8(typedObj, offset + 8);
     var s9 = Load_int8(typedObj, offset + 9);
     var s10 = Load_int8(typedObj, offset + 10);
     var s11 = Load_int8(typedObj, offset + 11);
     var s12 = Load_int8(typedObj, offset + 12);
     var s13 = Load_int8(typedObj, offset + 13);
     var s14 = Load_int8(typedObj, offset + 14);
     var s15 = Load_int8(typedObj, offset + 15);
-    return GetInt8x16TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7,
-                                 s8, s9, s10, s11, s12, s13, s14, s15);
+    return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15);
 
   case JS_SIMDTYPEREPR_INT16X8:
     var s0 = Load_int16(typedObj, offset + 0);
     var s1 = Load_int16(typedObj, offset + 2);
     var s2 = Load_int16(typedObj, offset + 4);
     var s3 = Load_int16(typedObj, offset + 6);
     var s4 = Load_int16(typedObj, offset + 8);
     var s5 = Load_int16(typedObj, offset + 10);
     var s6 = Load_int16(typedObj, offset + 12);
     var s7 = Load_int16(typedObj, offset + 14);
-    return GetInt16x8TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7);
+    return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7);
 
   case JS_SIMDTYPEREPR_INT32X4:
     var x = Load_int32(typedObj, offset + 0);
     var y = Load_int32(typedObj, offset + 4);
     var z = Load_int32(typedObj, offset + 8);
     var w = Load_int32(typedObj, offset + 12);
-    return GetInt32x4TypeDescr()(x, y, z, w);
+    return simdTypeDescr(x, y, z, w);
 
   case JS_SIMDTYPEREPR_UINT8X16:
     var s0 = Load_uint8(typedObj, offset + 0);
     var s1 = Load_uint8(typedObj, offset + 1);
     var s2 = Load_uint8(typedObj, offset + 2);
     var s3 = Load_uint8(typedObj, offset + 3);
     var s4 = Load_uint8(typedObj, offset + 4);
     var s5 = Load_uint8(typedObj, offset + 5);
@@ -207,36 +207,35 @@ function TypedObjectGetSimd(descr, typed
     var s8 = Load_uint8(typedObj, offset + 8);
     var s9 = Load_uint8(typedObj, offset + 9);
     var s10 = Load_uint8(typedObj, offset + 10);
     var s11 = Load_uint8(typedObj, offset + 11);
     var s12 = Load_uint8(typedObj, offset + 12);
     var s13 = Load_uint8(typedObj, offset + 13);
     var s14 = Load_uint8(typedObj, offset + 14);
     var s15 = Load_uint8(typedObj, offset + 15);
-    return GetUint8x16TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7,
-                                 s8, s9, s10, s11, s12, s13, s14, s15);
+    return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15);
 
   case JS_SIMDTYPEREPR_UINT16X8:
     var s0 = Load_uint16(typedObj, offset + 0);
     var s1 = Load_uint16(typedObj, offset + 2);
     var s2 = Load_uint16(typedObj, offset + 4);
     var s3 = Load_uint16(typedObj, offset + 6);
     var s4 = Load_uint16(typedObj, offset + 8);
     var s5 = Load_uint16(typedObj, offset + 10);
     var s6 = Load_uint16(typedObj, offset + 12);
     var s7 = Load_uint16(typedObj, offset + 14);
-    return GetUint16x8TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7);
+    return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7);
 
   case JS_SIMDTYPEREPR_UINT32X4:
     var x = Load_uint32(typedObj, offset + 0);
     var y = Load_uint32(typedObj, offset + 4);
     var z = Load_uint32(typedObj, offset + 8);
     var w = Load_uint32(typedObj, offset + 12);
-    return GetUint32x4TypeDescr()(x, y, z, w);
+    return simdTypeDescr(x, y, z, w);
 
   case JS_SIMDTYPEREPR_BOOL8X16:
     var s0 = Load_int8(typedObj, offset + 0);
     var s1 = Load_int8(typedObj, offset + 1);
     var s2 = Load_int8(typedObj, offset + 2);
     var s3 = Load_int8(typedObj, offset + 3);
     var s4 = Load_int8(typedObj, offset + 4);
     var s5 = Load_int8(typedObj, offset + 5);
@@ -245,41 +244,40 @@ function TypedObjectGetSimd(descr, typed
     var s8 = Load_int8(typedObj, offset + 8);
     var s9 = Load_int8(typedObj, offset + 9);
     var s10 = Load_int8(typedObj, offset + 10);
     var s11 = Load_int8(typedObj, offset + 11);
     var s12 = Load_int8(typedObj, offset + 12);
     var s13 = Load_int8(typedObj, offset + 13);
     var s14 = Load_int8(typedObj, offset + 14);
     var s15 = Load_int8(typedObj, offset + 15);
-    return GetBool8x16TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7,
-                                  s8, s9, s10, s11, s12, s13, s14, s15);
+    return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15);
 
   case JS_SIMDTYPEREPR_BOOL16X8:
     var s0 = Load_int16(typedObj, offset + 0);
     var s1 = Load_int16(typedObj, offset + 2);
     var s2 = Load_int16(typedObj, offset + 4);
     var s3 = Load_int16(typedObj, offset + 6);
     var s4 = Load_int16(typedObj, offset + 8);
     var s5 = Load_int16(typedObj, offset + 10);
     var s6 = Load_int16(typedObj, offset + 12);
     var s7 = Load_int16(typedObj, offset + 14);
-    return GetBool16x8TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7);
+    return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7);
 
   case JS_SIMDTYPEREPR_BOOL32X4:
     var x = Load_int32(typedObj, offset + 0);
     var y = Load_int32(typedObj, offset + 4);
     var z = Load_int32(typedObj, offset + 8);
     var w = Load_int32(typedObj, offset + 12);
-    return GetBool32x4TypeDescr()(x, y, z, w);
+    return simdTypeDescr(x, y, z, w);
 
   case JS_SIMDTYPEREPR_BOOL64X2:
     var x = Load_int32(typedObj, offset + 0);
     var y = Load_int32(typedObj, offset + 8);
-    return GetBool64x2TypeDescr()(x, y);
+    return simdTypeDescr(x, y);
 
   }
 
   assert(false, "Unhandled SIMD type: " + type);
   return undefined;
 }
 
 ///////////////////////////////////////////////////////////////////////////
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -37,53 +37,46 @@ using JS::AutoGCRooter;
 
 typedef RootedValueMap::Range RootRange;
 typedef RootedValueMap::Entry RootEntry;
 typedef RootedValueMap::Enum RootEnum;
 
 template <typename T>
 using TraceFunction = void (*)(JSTracer* trc, T* ref, const char* name);
 
-template <class T, TraceFunction<T> TraceFn = TraceNullableRoot, class Source>
+template <class T, TraceFunction<T> TraceFn = TraceNullableRoot>
 static inline void
-MarkExactStackRootList(JSTracer* trc, Source* s, const char* name)
+MarkExactStackRootList(JSTracer* trc, JS::Rooted<void*>* rooter, const char* name)
 {
-    Rooted<T>* rooter = s->roots.template gcRooters<T>();
     while (rooter) {
-        T* addr = rooter->address();
+        T* addr = reinterpret_cast<JS::Rooted<T>*>(rooter)->address();
         TraceFn(trc, addr, name);
         rooter = rooter->previous();
     }
 }
 
-template<class T>
-static void
-MarkExactStackRootsAcrossTypes(T context, JSTracer* trc)
+void
+js::RootLists::traceStackRoots(JSTracer* trc)
 {
-    MarkExactStackRootList<JSObject*>(trc, context, "exact-object");
-    MarkExactStackRootList<Shape*>(trc, context, "exact-shape");
-    MarkExactStackRootList<BaseShape*>(trc, context, "exact-baseshape");
-    MarkExactStackRootList<ObjectGroup*>(trc, context, "exact-objectgroup");
-    MarkExactStackRootList<JSString*>(trc, context, "exact-string");
-    MarkExactStackRootList<JS::Symbol*>(trc, context, "exact-symbol");
-    MarkExactStackRootList<jit::JitCode*>(trc, context, "exact-jitcode");
-    MarkExactStackRootList<JSScript*>(trc, context, "exact-script");
-    MarkExactStackRootList<LazyScript*>(trc, context, "exact-lazy-script");
-    MarkExactStackRootList<jsid>(trc, context, "exact-id");
-    MarkExactStackRootList<Value>(trc, context, "exact-value");
+#define MARK_ROOTS(name, type, _) \
+    MarkExactStackRootList<type*>(trc, stackRoots_[JS::RootKind::name], "exact-" #name);
+JS_FOR_EACH_TRACEKIND(MARK_ROOTS)
+#undef MARK_ROOTS
+    MarkExactStackRootList<jsid>(trc, stackRoots_[JS::RootKind::Id], "exact-id");
+    MarkExactStackRootList<Value>(trc, stackRoots_[JS::RootKind::Value], "exact-value");
     MarkExactStackRootList<JS::Traceable, js::DispatchWrapper<JS::Traceable>::TraceWrapped>(
-        trc, context, "Traceable");
+        trc, stackRoots_[JS::RootKind::Traceable], "Traceable");
 }
 
 static void
 MarkExactStackRoots(JSRuntime* rt, JSTracer* trc)
 {
     for (ContextIter cx(rt); !cx.done(); cx.next())
-        MarkExactStackRootsAcrossTypes<JSContext*>(cx.get(), trc);
-    MarkExactStackRootsAcrossTypes<PerThreadData*>(&rt->mainThread, trc);
+        cx->roots.traceStackRoots(trc);
+    rt->mainThread.roots.traceStackRoots(trc);
 }
 
 inline void
 AutoGCRooter::trace(JSTracer* trc)
 {
     switch (tag_) {
       case PARSER:
         frontend::MarkParser(trc, this);
@@ -241,17 +234,17 @@ js::gc::MarkPersistentRootedChainsInList
     PersistentRootedMarker<jsid>::markChain(trc, roots.getPersistentRootedList<jsid>(),
                                             "PersistentRooted<jsid>");
     PersistentRootedMarker<Value>::markChain(trc, roots.getPersistentRootedList<Value>(),
                                              "PersistentRooted<Value>");
 
     PersistentRootedMarker<JS::Traceable>::markChain<
         js::DispatchWrapper<JS::Traceable>::TraceWrapped>(trc,
             reinterpret_cast<mozilla::LinkedList<JS::PersistentRooted<JS::Traceable>>&>(
-                roots.heapRoots_[THING_ROOT_TRACEABLE]),
+                roots.heapRoots_[JS::RootKind::Traceable]),
             "PersistentRooted<Traceable>");
 }
 
 void
 js::gc::MarkPersistentRootedChains(JSTracer* trc)
 {
     for (ContextIter cx(trc->runtime()); !cx.done(); cx.next())
         MarkPersistentRootedChainsInLists(cx->roots, trc);
--- a/js/src/jit-test/lib/simd.js
+++ b/js/src/jit-test/lib/simd.js
@@ -29,16 +29,17 @@ function unaryX4(op, v, coerceFunc) {
 function assertNear(a, b) {
     assertEq((a != a && b != b) || Math.abs(a - b) < 0.001, true);
 }
 
 function GetType(v) {
     var pt = Object.getPrototypeOf(v);
     switch (pt) {
         case SIMD.Int32x4.prototype: return SIMD.Int32x4;
+        case SIMD.Uint32x4.prototype: return SIMD.Uint32x4;
         case SIMD.Float32x4.prototype: return SIMD.Float32x4;
         case SIMD.Bool32x4.prototype: return SIMD.Bool32x4;
     }
     throw "unexpected SIMD type";
 }
 
 function assertEqVec(v, w) {
     var typeV = GetType(v);
@@ -55,24 +56,33 @@ function assertEqX4(vec, arr, ...opts) {
     var assertFunc;
     if (opts.length == 1 && typeof opts[0] !== 'undefined') {
         assertFunc = opts[0];
     } else {
         assertFunc = assertEq;
     }
 
     var Type = GetType(vec);
+
     if (Type === SIMD.Int32x4) {
         assertFunc(SIMD.Int32x4.extractLane(vec, 0), arr[0]);
         assertFunc(SIMD.Int32x4.extractLane(vec, 1), arr[1]);
         assertFunc(SIMD.Int32x4.extractLane(vec, 2), arr[2]);
         assertFunc(SIMD.Int32x4.extractLane(vec, 3), arr[3]);
         return;
     }
 
+    if (Type === SIMD.Uint32x4) {
+        assertFunc(SIMD.Uint32x4.extractLane(vec, 0), arr[0]);
+        assertFunc(SIMD.Uint32x4.extractLane(vec, 1), arr[1]);
+        assertFunc(SIMD.Uint32x4.extractLane(vec, 2), arr[2]);
+        assertFunc(SIMD.Uint32x4.extractLane(vec, 3), arr[3]);
+        return;
+    }
+
     if (Type === SIMD.Float32x4) {
         assertFunc(SIMD.Float32x4.extractLane(vec, 0), arr[0]);
         assertFunc(SIMD.Float32x4.extractLane(vec, 1), arr[1]);
         assertFunc(SIMD.Float32x4.extractLane(vec, 2), arr[2]);
         assertFunc(SIMD.Float32x4.extractLane(vec, 3), arr[3]);
         return;
     }
 
@@ -94,16 +104,25 @@ function simdToArray(vec) {
         return [
             SIMD.Int32x4.extractLane(vec, 0),
             SIMD.Int32x4.extractLane(vec, 1),
             SIMD.Int32x4.extractLane(vec, 2),
             SIMD.Int32x4.extractLane(vec, 3),
         ];
     }
 
+    if (Type === SIMD.Uint32x4) {
+        return [
+            SIMD.Uint32x4.extractLane(vec, 0),
+            SIMD.Uint32x4.extractLane(vec, 1),
+            SIMD.Uint32x4.extractLane(vec, 2),
+            SIMD.Uint32x4.extractLane(vec, 3),
+        ];
+    }
+
     if (Type === SIMD.Float32x4) {
         return [
             SIMD.Float32x4.extractLane(vec, 0),
             SIMD.Float32x4.extractLane(vec, 1),
             SIMD.Float32x4.extractLane(vec, 2),
             SIMD.Float32x4.extractLane(vec, 3),
         ];
     }
--- a/js/src/jit-test/tests/SIMD/compare.js
+++ b/js/src/jit-test/tests/SIMD/compare.js
@@ -4,24 +4,34 @@ setJitCompilerOption("ion.warmup.trigger
 
 function f() {
     var f1 = SIMD.Float32x4(1, 2, 3, 4);
     var f2 = SIMD.Float32x4(NaN, Infinity, 3.14, -0);
 
     var i1 = SIMD.Int32x4(1, 2, -3, 4);
     var i2 = SIMD.Int32x4(1, -2, 3, 0);
 
+    var u1 = SIMD.Uint32x4(1, 2, -3, 4);
+    var u2 = SIMD.Uint32x4(1, -2, 3, 0x80000000);
+
     for (var i = 0; i < 150; i++) {
         assertEqX4(SIMD.Int32x4.lessThan(i1, i2),             [false, false, true, false]);
         assertEqX4(SIMD.Int32x4.lessThanOrEqual(i1, i2),      [true, false, true, false]);
         assertEqX4(SIMD.Int32x4.equal(i1, i2),                [true, false, false, false]);
         assertEqX4(SIMD.Int32x4.notEqual(i1, i2),             [false, true, true, true]);
         assertEqX4(SIMD.Int32x4.greaterThan(i1, i2),          [false, true, false, true]);
         assertEqX4(SIMD.Int32x4.greaterThanOrEqual(i1, i2),   [true, true, false, true]);
 
+        assertEqX4(SIMD.Uint32x4.lessThan(u1, u2),             [false, true, false, true]);
+        assertEqX4(SIMD.Uint32x4.lessThanOrEqual(u1, u2),      [true,  true, false, true]);
+        assertEqX4(SIMD.Uint32x4.equal(u1, u2),                [true, false, false, false]);
+        assertEqX4(SIMD.Uint32x4.notEqual(u1, u2),             [false, true, true, true]);
+        assertEqX4(SIMD.Uint32x4.greaterThan(u1, u2),          [false, false, true, false]);
+        assertEqX4(SIMD.Uint32x4.greaterThanOrEqual(u1, u2),   [true, false, true, false]);
+
         assertEqX4(SIMD.Float32x4.lessThan(f1, f2),             [false, true, true, false]);
         assertEqX4(SIMD.Float32x4.lessThanOrEqual(f1, f2),      [false, true, true, false]);
         assertEqX4(SIMD.Float32x4.equal(f1, f2),                [false, false, false, false]);
         assertEqX4(SIMD.Float32x4.notEqual(f1, f2),             [true, true, true, true]);
         assertEqX4(SIMD.Float32x4.greaterThan(f1, f2),          [false, false, false, true]);
         assertEqX4(SIMD.Float32x4.greaterThanOrEqual(f1, f2),   [false, false, false, true]);
     }
 }
--- a/js/src/jit-test/tests/SIMD/getters.js
+++ b/js/src/jit-test/tests/SIMD/getters.js
@@ -1,29 +1,35 @@
 load(libdir + 'simd.js');
 
 setJitCompilerOption("ion.warmup.trigger", 50);
 
 function f() {
     var i4 = SIMD.Int32x4(1, -2, 3, -4);
+    var u4 = SIMD.Uint32x4(1, -2, 3, 0x88000000);
     var b4 = SIMD.Bool32x4(true, true, false, true);
 
 
     var bt4 = SIMD.Bool32x4(true, true, true, true);
     var bf4 = SIMD.Bool32x4(false, false, false, false);
 
     var v = Math.fround(13.37);
     var f4 = SIMD.Float32x4(13.37, NaN, Infinity, -0);
 
     for (var i = 0; i < 150; i++) {
         assertEq(SIMD.Int32x4.extractLane(i4, 0), 1);
         assertEq(SIMD.Int32x4.extractLane(i4, 1), -2);
         assertEq(SIMD.Int32x4.extractLane(i4, 2), 3);
         assertEq(SIMD.Int32x4.extractLane(i4, 3), -4);
 
+        assertEq(SIMD.Uint32x4.extractLane(u4, 0), 1);
+        assertEq(SIMD.Uint32x4.extractLane(u4, 1), -2 >>> 0);
+        assertEq(SIMD.Uint32x4.extractLane(u4, 2), 3);
+        assertEq(SIMD.Uint32x4.extractLane(u4, 3), 0x88000000);
+
         assertEq(SIMD.Float32x4.extractLane(f4, 0), v);
         assertEq(SIMD.Float32x4.extractLane(f4, 1), NaN);
         assertEq(SIMD.Float32x4.extractLane(f4, 2), Infinity);
         assertEq(SIMD.Float32x4.extractLane(f4, 3), -0);
 
         assertEq(SIMD.Bool32x4.extractLane(b4, 0), true);
         assertEq(SIMD.Bool32x4.extractLane(b4, 1), true);
         assertEq(SIMD.Bool32x4.extractLane(b4, 2), false);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/SIMD/uconvert.js
@@ -0,0 +1,81 @@
+load(libdir + 'simd.js');
+
+setJitCompilerOption("ion.warmup.trigger", 30);
+
+// Testing Uint32 <-> Float32 conversions.
+// These conversions deserve special attention because SSE doesn't provide
+// simple conversion instructions.
+
+// Convert an Uint32Array to a Float32Array using scalar conversions.
+function cvt_utof_scalar(u32s, f32s) {
+    assertEq(u32s.length, f32s.length);
+    for (var i = 0; i < u32s.length; i++) {
+        f32s[i] = u32s[i];
+    }
+}
+
+// Convert an Uint32Array to a Float32Array using simd conversions.
+function cvt_utof_simd(u32s, f32s) {
+    assertEq(u32s.length, f32s.length);
+    for (var i = 0; i < u32s.length; i += 4) {
+        SIMD.Float32x4.store(f32s, i, SIMD.Float32x4.fromUint32x4(SIMD.Uint32x4.load(u32s, i)));
+    }
+}
+
+// Convert a Float32Array to an Uint32Array using scalar conversions.
+function cvt_ftou_scalar(f32s, u32s) {
+    assertEq(f32s.length, u32s.length);
+    for (var i = 0; i < f32s.length; i++) {
+        u32s[i] = f32s[i];
+    }
+}
+
+// Convert a Float32Array to an Uint32Array using simd conversions.
+function cvt_ftou_simd(f32s, u32s) {
+    assertEq(f32s.length, u32s.length);
+    for (var i = 0; i < f32s.length; i += 4) {
+        SIMD.Uint32x4.store(u32s, i, SIMD.Uint32x4.fromFloat32x4(SIMD.Float32x4.load(f32s, i)));
+    }
+}
+
+function check(a, b) {
+    assertEq(a.length, b.length);
+    for (var i = 0; i < a.length; i++) {
+        assertEq(a[i], b[i]);
+    }
+}
+
+// Uint32x4 --> Float32x4 tests.
+var src = new Uint32Array(8000);
+var dst1 = new Float32Array(8000);
+var dst2 = new Float32Array(8000);
+
+for (var i = 0; i < 2000; i++) {
+    src[i] = i;
+    src[i + 2000] = 0x7fffffff - i;
+    src[i + 4000] = 0x80000000 + i;
+    src[i + 6000] = 0xffffffff - i;
+}
+
+for (var n = 0; n < 10; n++) {
+    cvt_utof_scalar(src, dst1);
+    cvt_utof_simd(src, dst2);
+    check(dst1, dst2);
+}
+
+// Float32x4 --> Uint32x4 tests.
+var fsrc = dst1;
+var fdst1 = new Uint32Array(8000);
+var fdst2 = new Uint32Array(8000);
+
+// The 0xffffffff entries in fsrc round to 0x1.0p32f which throws.
+// Go as high as 0x0.ffffffp32f.
+for (var i = 0; i < 2000; i++) {
+    fsrc[i + 6000] = 0xffffff7f - i;
+}
+
+for (var n = 0; n < 10; n++) {
+    cvt_ftou_scalar(fsrc, fdst1);
+    cvt_ftou_simd(fsrc, fdst2);
+    check(fdst1, fdst2);
+}
--- a/js/src/jit-test/tests/wasm/binary.js
+++ b/js/src/jit-test/tests/wasm/binary.js
@@ -162,8 +162,15 @@ assertThrowsInstanceOf(() => wasmEval(to
 assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([trivialSigSection, declSection([0])]))), TypeError, /fewer function definitions than declarations/);
 wasmEval(toBuf(moduleWithSections([trivialSigSection, trivialDeclSection, trivialCodeSection])));
 
 assertThrowsInstanceOf(() => wasmEval(toBuf(moduleWithSections([trivialSigSection, {name: importSectionStr, body:[]}]))), TypeError);
 assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([importSection([{sigIndex:0, module:"a", func:"b"}])]))), TypeError, /signature index out of range/);
 assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([trivialSigSection, importSection([{sigIndex:1, module:"a", func:"b"}])]))), TypeError, /signature index out of range/);
 wasmEval(toBuf(moduleWithSections([trivialSigSection, importSection([])])));
 wasmEval(toBuf(moduleWithSections([trivialSigSection, importSection([{sigIndex:0, module:"a", func:""}])])), {a:()=>{}});
+
+Math.sin();
+wasmEval(toBuf(moduleWithSections([
+    trivialSigSection,
+    importSection([{sigIndex:0, module:"a", func:""}]),
+    trivialDeclSection,
+    trivialCodeSection])), {a:()=>{}});
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -13,16 +13,17 @@
 #include "jslibmath.h"
 #include "jstypes.h"
 
 #include "builtin/Eval.h"
 #include "builtin/SIMD.h"
 #include "gc/Policy.h"
 #include "jit/BaselineDebugModeOSR.h"
 #include "jit/BaselineJIT.h"
+#include "jit/InlinableNatives.h"
 #include "jit/JitSpewer.h"
 #include "jit/Linker.h"
 #include "jit/Lowering.h"
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
 #endif
 #include "jit/SharedICHelpers.h"
 #include "jit/VMFunctions.h"
@@ -5544,20 +5545,78 @@ TryAttachFunCallStub(JSContext* cx, ICCa
         *attached = true;
         stub->addNewStub(newStub);
         return true;
     }
 
     return true;
 }
 
+// Check if target is a native SIMD operation which returns a SIMD type.
+// If so, set res to a template object matching the SIMD type produced and return true.
 static bool
-GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args,
+GetTemplateObjectForSimd(JSContext* cx, JSFunction* target, MutableHandleObject res)
+{
+    const JSJitInfo* jitInfo = target->jitInfo();
+    if (!jitInfo || jitInfo->type() != JSJitInfo::InlinableNative)
+        return false;
+
+    // Check if this is a native inlinable SIMD operation.
+    SimdType ctrlType;
+    switch (jitInfo->inlinableNative) {
+      case InlinableNative::SimdInt32x4:   ctrlType = SimdType::Int32x4;   break;
+      case InlinableNative::SimdUint32x4:  ctrlType = SimdType::Uint32x4;  break;
+      case InlinableNative::SimdFloat32x4: ctrlType = SimdType::Float32x4; break;
+      case InlinableNative::SimdBool32x4:  ctrlType = SimdType::Bool32x4;  break;
+      // This is not an inlinable SIMD operation.
+      default: return false;
+    }
+
+    // The controlling type is not necessarily the return type.
+    // Check the actual operation.
+    SimdOperation simdOp = SimdOperation(jitInfo->nativeOp);
+    SimdType retType;
+
+    switch(simdOp) {
+      case SimdOperation::Fn_allTrue:
+      case SimdOperation::Fn_anyTrue:
+      case SimdOperation::Fn_extractLane:
+        // These operations return a scalar. No template object needed.
+        return false;
+
+      case SimdOperation::Fn_lessThan:
+      case SimdOperation::Fn_lessThanOrEqual:
+      case SimdOperation::Fn_equal:
+      case SimdOperation::Fn_notEqual:
+      case SimdOperation::Fn_greaterThan:
+      case SimdOperation::Fn_greaterThanOrEqual:
+        // These operations return a boolean vector with the same shape as the
+        // controlling type.
+        retType = GetBooleanSimdType(ctrlType);
+        break;
+
+      default:
+        // All other operations return the controlling type.
+        retType = ctrlType;
+        break;
+    }
+
+    // Create a template object based on retType.
+    RootedGlobalObject global(cx, cx->global());
+    Rooted<SimdTypeDescr*> descr(cx, GlobalObject::getOrCreateSimdTypeDescr(cx, global, retType));
+    res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
+    return true;
+}
+
+static bool
+GetTemplateObjectForNative(JSContext* cx, JSFunction* target, const CallArgs& args,
                            MutableHandleObject res, bool* skipAttach)
 {
+    Native native = target->native();
+
     // Check for natives to which template objects can be attached. This is
     // done to provide templates to Ion for inlining these natives later on.
 
     if (native == ArrayConstructor) {
         // Note: the template array won't be used if its length is inaccurately
         // computed here.  (We allocate here because compilation may occur on a
         // separate thread where allocation is impossible.)
         size_t count = 0;
@@ -5621,61 +5680,18 @@ GetTemplateObjectForNative(JSContext* cx
     }
 
     if (native == obj_create && args.length() == 1 && args[0].isObjectOrNull()) {
         RootedObject proto(cx, args[0].toObjectOrNull());
         res.set(ObjectCreateImpl(cx, proto, TenuredObject));
         return !!res;
     }
 
-    if (JitSupportsSimd()) {
-        RootedGlobalObject global(cx, cx->global());
-#define ADD_INT32X4_SIMD_OP_NAME_(OP) || native == js::simd_int32x4_##OP
-#define ADD_BOOL32X4_SIMD_OP_NAME_(OP) || native == js::simd_bool32x4_##OP
-#define ADD_FLOAT32X4_SIMD_OP_NAME_(OP) || native == js::simd_float32x4_##OP
-        // Operations producing an int32x4.
-        if (false
-            ION_COMMONX4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
-            FOREACH_BITWISE_SIMD_UNOP(ADD_INT32X4_SIMD_OP_NAME_)
-            FOREACH_BITWISE_SIMD_BINOP(ADD_INT32X4_SIMD_OP_NAME_)
-            FOREACH_SHIFT_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
-            ADD_INT32X4_SIMD_OP_NAME_(fromFloat32x4)
-            ADD_INT32X4_SIMD_OP_NAME_(fromFloat32x4Bits))
-        {
-            Rooted<SimdTypeDescr*> descr(cx, GlobalObject::getOrCreateSimdTypeDescr<Int32x4>(cx, global));
-            res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
-            return !!res;
-        }
-        // Operations producing a bool32x4.
-        if (false
-            FOREACH_BITWISE_SIMD_UNOP(ADD_BOOL32X4_SIMD_OP_NAME_)
-            FOREACH_BITWISE_SIMD_BINOP(ADD_BOOL32X4_SIMD_OP_NAME_)
-            FOREACH_COMP_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
-            FOREACH_COMP_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
-        {
-            Rooted<SimdTypeDescr*> descr(cx, GlobalObject::getOrCreateSimdTypeDescr<Bool32x4>(cx, global));
-            res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
-            return !!res;
-        }
-        // Operations producing a float32x4.
-        if (false
-            FOREACH_FLOAT_SIMD_UNOP(ADD_FLOAT32X4_SIMD_OP_NAME_)
-            FOREACH_FLOAT_SIMD_BINOP(ADD_FLOAT32X4_SIMD_OP_NAME_)
-            ADD_FLOAT32X4_SIMD_OP_NAME_(fromInt32x4)
-            ADD_FLOAT32X4_SIMD_OP_NAME_(fromInt32x4Bits)
-            ION_COMMONX4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
-        {
-            Rooted<SimdTypeDescr*> descr(cx, GlobalObject::getOrCreateSimdTypeDescr<Float32x4>(cx, global));
-            res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
-            return !!res;
-        }
-#undef ADD_BOOL32X4_SIMD_OP_NAME_
-#undef ADD_INT32X4_SIMD_OP_NAME_
-#undef ADD_FLOAT32X4_SIMD_OP_NAME_
-    }
+    if (JitSupportsSimd() && GetTemplateObjectForSimd(cx, target, res))
+       return !!res;
 
     return true;
 }
 
 static bool
 GetTemplateObjectForClassHook(JSContext* cx, JSNative hook, CallArgs& args,
                               MutableHandleObject templateObject)
 {
@@ -5929,17 +5945,17 @@ TryAttachCallStub(JSContext* cx, ICCall_
             *handled = true;
             return true;
         }
 
         RootedObject templateObject(cx);
         if (MOZ_LIKELY(!isSpread && !isSuper)) {
             bool skipAttach = false;
             CallArgs args = CallArgsFromVp(argc, vp);
-            if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject, &skipAttach))
+            if (!GetTemplateObjectForNative(cx, fun, args, &templateObject, &skipAttach))
                 return false;
             if (skipAttach) {
                 *handled = true;
                 return true;
             }
             MOZ_ASSERT_IF(templateObject, !templateObject->group()->maybePreliminaryObjects());
         }
 
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -75,16 +75,17 @@
     _(StringCharCodeAt)             \
     _(StringFromCharCode)           \
     _(StringCharAt)                 \
     _(StringReplace)                \
                                     \
     _(ObjectCreate)                 \
                                     \
     _(SimdInt32x4)                  \
+    _(SimdUint32x4)                 \
     _(SimdFloat32x4)                \
     _(SimdBool32x4)                 \
                                     \
     _(TestBailout)                  \
     _(TestAssertFloat32)            \
     _(TestAssertRecoveredOnBailout) \
                                     \
     _(IntrinsicUnsafeSetReservedSlot) \
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -855,33 +855,37 @@ class IonBuilder
 
     // SIMD helpers.
     bool canInlineSimd(CallInfo& callInfo, JSNative native, unsigned numArgs,
                        InlineTypedObject** templateObj);
     IonBuilder::InliningStatus boxSimd(CallInfo& callInfo, MInstruction* ins,
                                        InlineTypedObject* templateObj);
     MDefinition* convertToBooleanSimdLane(MDefinition* scalar);
 
-    InliningStatus inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType);
+    InliningStatus inlineSimd(CallInfo& callInfo, JSFunction* target,
+                              MIRType simdType, SimdSign sign = SimdSign::NotApplicable);
 
     template <typename T>
     InliningStatus inlineSimdBinary(CallInfo& callInfo, JSNative native,
                                     typename T::Operation op, MIRType mirType);
     InliningStatus inlineSimdComp(CallInfo& callInfo, JSNative native,
-                                  MSimdBinaryComp::Operation op, MIRType compType);
+                                  MSimdBinaryComp::Operation op,
+                                  MIRType compType, SimdSign sign);
     InliningStatus inlineSimdUnary(CallInfo& callInfo, JSNative native,
                                    MSimdUnaryArith::Operation op, MIRType mirType);
-    InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native, MIRType vecType);
+    InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native,
+                                         MIRType vecType, SimdSign sign);
     InliningStatus inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, MIRType mirType);
     InliningStatus inlineSimdSplat(CallInfo& callInfo, JSNative native, MIRType mirType);
     InliningStatus inlineSimdShuffle(CallInfo& callInfo, JSNative native, MIRType type,
                                      unsigned numVectors, unsigned numLanes);
     InliningStatus inlineSimdCheck(CallInfo& callInfo, JSNative native, MIRType type);
     InliningStatus inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
-                                     MIRType from, MIRType to);
+                                     MIRType from, MIRType to,
+                                     SimdSign sign = SimdSign::NotApplicable);
     InliningStatus inlineSimdSelect(CallInfo& callInfo, JSNative native, MIRType type);
 
     bool prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements,
                                  MDefinition** index, Scalar::Type* arrayType);
     InliningStatus inlineSimdLoad(CallInfo& callInfo, JSNative native, MIRType type,
                                   unsigned numElems);
     InliningStatus inlineSimdStore(CallInfo& callInfo, JSNative native, MIRType type,
                                    unsigned numElems);
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -155,17 +155,17 @@ class JitCode : public gc::TenuredCell
     // Allocates a new JitCode object which will be managed by the GC. If no
     // object can be allocated, nullptr is returned. On failure, |pool| is
     // automatically released, so the code may be freed.
     template <AllowGC allowGC>
     static JitCode* New(JSContext* cx, uint8_t* code, uint32_t bufferSize, uint32_t headerSize,
                         ExecutablePool* pool, CodeKind kind);
 
   public:
-    static inline ThingRootKind rootKind() { return THING_ROOT_JIT_CODE; }
+    static const JS::TraceKind TraceKind = JS::TraceKind::JitCode;
 };
 
 class SnapshotWriter;
 class RecoverWriter;
 class SafepointWriter;
 class SafepointIndex;
 class OsiIndex;
 class IonCache;
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -415,16 +415,17 @@ enum MIRType
     MIRType_None,                      // Invalid, used as a placeholder.
     MIRType_Slots,                     // A slots vector
     MIRType_Elements,                  // An elements vector
     MIRType_Pointer,                   // An opaque pointer that receives no special treatment
     MIRType_Shape,                     // A Shape pointer.
     MIRType_ObjectGroup,               // An ObjectGroup pointer.
     MIRType_Last = MIRType_ObjectGroup,
     MIRType_Float32x4 = MIRType_Float32 | (2 << VECTOR_SCALE_SHIFT),
+    // Representing both SIMD.Int32x4 and SIMD.Uint32x4.
     MIRType_Int32x4   = MIRType_Int32   | (2 << VECTOR_SCALE_SHIFT),
     MIRType_Bool32x4  = MIRType_Boolean | (2 << VECTOR_SCALE_SHIFT),
     MIRType_Doublex2  = MIRType_Double  | (1 << VECTOR_SCALE_SHIFT)
 };
 
 static inline MIRType
 MIRTypeFromValueType(JSValueType type)
 {
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4096,22 +4096,38 @@ LIRGenerator::visitSimdConstant(MSimdCon
 void
 LIRGenerator::visitSimdConvert(MSimdConvert* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->type()));
     MDefinition* input = ins->input();
     LUse use = useRegister(input);
     if (ins->type() == MIRType_Int32x4) {
         MOZ_ASSERT(input->type() == MIRType_Float32x4);
-        LFloat32x4ToInt32x4* lir = new(alloc()) LFloat32x4ToInt32x4(use, temp());
-        if (!gen->compilingAsmJS())
-            assignSnapshot(lir, Bailout_BoundsCheck);
-        define(lir, ins);
+        switch (ins->signedness()) {
+          case SimdSign::Signed: {
+              LFloat32x4ToInt32x4* lir = new(alloc()) LFloat32x4ToInt32x4(use, temp());
+              if (!gen->compilingAsmJS())
+                  assignSnapshot(lir, Bailout_BoundsCheck);
+              define(lir, ins);
+              break;
+          }
+          case SimdSign::Unsigned: {
+              LFloat32x4ToUint32x4* lir =
+                new (alloc()) LFloat32x4ToUint32x4(use, temp(), temp(LDefinition::INT32X4));
+              if (!gen->compilingAsmJS())
+                  assignSnapshot(lir, Bailout_BoundsCheck);
+              define(lir, ins);
+              break;
+          }
+          default:
+            MOZ_CRASH("Unexpected SimdConvert sign");
+        }
     } else if (ins->type() == MIRType_Float32x4) {
         MOZ_ASSERT(input->type() == MIRType_Int32x4);
+        MOZ_ASSERT(ins->signedness() == SimdSign::Signed, "Unexpected SimdConvert sign");
         define(new(alloc()) LInt32x4ToFloat32x4(use), ins);
     } else {
         MOZ_CRASH("Unknown SIMD kind when generating constant");
     }
 }
 
 void
 LIRGenerator::visitSimdReinterpretCast(MSimdReinterpretCast* ins)
@@ -4128,28 +4144,37 @@ LIRGenerator::visitSimdReinterpretCast(M
 void
 LIRGenerator::visitSimdExtractElement(MSimdExtractElement* ins)
 {
     MOZ_ASSERT(IsSimdType(ins->input()->type()));
     MOZ_ASSERT(!IsSimdType(ins->type()));
 
     switch (ins->input()->type()) {
       case MIRType_Int32x4: {
+        MOZ_ASSERT(ins->signedness() != SimdSign::NotApplicable);
         // Note: there could be int16x8 in the future, which doesn't use the
         // same instruction. We either need to pass the arity or create new LIns.
         LUse use = useRegisterAtStart(ins->input());
-        define(new(alloc()) LSimdExtractElementI(use), ins);
+        if (ins->type() == MIRType_Double) {
+            // Extract an Uint32 lane into a double.
+            MOZ_ASSERT(ins->signedness() == SimdSign::Unsigned);
+            define(new (alloc()) LSimdExtractElementU2D(use, temp()), ins);
+        } else {
+            define(new (alloc()) LSimdExtractElementI(use), ins);
+        }
         break;
       }
       case MIRType_Float32x4: {
+        MOZ_ASSERT(ins->signedness() == SimdSign::NotApplicable);
         LUse use = useRegisterAtStart(ins->input());
         define(new(alloc()) LSimdExtractElementF(use), ins);
         break;
       }
       case MIRType_Bool32x4: {
+        MOZ_ASSERT(ins->signedness() == SimdSign::NotApplicable);
         LUse use = useRegisterAtStart(ins->input());
         define(new(alloc()) LSimdExtractElementB(use), ins);
         break;
       }
       default:
         MOZ_CRASH("Unknown SIMD kind when extracting element");
     }
 }
@@ -4289,19 +4314,21 @@ LIRGenerator::visitSimdBinaryComp(MSimdB
     MOZ_ASSERT(IsSimdType(ins->lhs()->type()));
     MOZ_ASSERT(IsSimdType(ins->rhs()->type()));
     MOZ_ASSERT(IsBooleanSimdType(ins->type()));
 
     if (ShouldReorderCommutative(ins->lhs(), ins->rhs(), ins))
         ins->reverse();
 
     if (ins->specialization() == MIRType_Int32x4) {
+        MOZ_ASSERT(ins->signedness() == SimdSign::Signed);
         LSimdBinaryCompIx4* add = new(alloc()) LSimdBinaryCompIx4();
         lowerForCompIx4(add, ins, ins->lhs(), ins->rhs());
     } else if (ins->specialization() == MIRType_Float32x4) {
+        MOZ_ASSERT(ins->signedness() == SimdSign::NotApplicable);
         LSimdBinaryCompFx4* add = new(alloc()) LSimdBinaryCompFx4();
         lowerForCompFx4(add, ins, ins->lhs(), ins->rhs());
     } else {
         MOZ_CRASH("Unknown compare type when comparing values");
     }
 }
 
 void
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -198,17 +198,19 @@ IonBuilder::inlineNativeCall(CallInfo& c
         return inlineStrReplace(callInfo);
 
       // Object natives.
       case InlinableNative::ObjectCreate:
         return inlineObjectCreate(callInfo);
 
       // SIMD natives.
       case InlinableNative::SimdInt32x4:
-        return inlineSimd(callInfo, target, MIRType_Int32x4);
+        return inlineSimd(callInfo, target, MIRType_Int32x4, SimdSign::Signed);
+      case InlinableNative::SimdUint32x4:
+        return inlineSimd(callInfo, target, MIRType_Int32x4, SimdSign::Unsigned);
       case InlinableNative::SimdFloat32x4:
         return inlineSimd(callInfo, target, MIRType_Float32x4);
       case InlinableNative::SimdBool32x4:
         return inlineSimd(callInfo, target, MIRType_Bool32x4);
 
       // Testing functions.
       case InlinableNative::TestBailout:
         return inlineBailout(callInfo);
@@ -3052,37 +3054,47 @@ IonBuilder::inlineConstructTypedObject(C
                                                 templateObject->group()->initialHeap(constraints()));
     current->add(ins);
     current->push(ins);
 
     return InliningStatus_Inlined;
 }
 
 // Main entry point for SIMD inlining.
+// When the controlling simdType is an integer type, sign indicates whether the lanes should
+// be treated as signed or unsigned integers.
 IonBuilder::InliningStatus
-IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType)
+IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType, SimdSign sign)
 {
+    if (!JitSupportsSimd()) {
+        trackOptimizationOutcome(TrackedOutcome::NoSimdJitSupport);
+        return InliningStatus_NotInlined;
+    }
+
     JSNative native = target->native();
     const JSJitInfo* jitInfo = target->jitInfo();
     MOZ_ASSERT(jitInfo && jitInfo->type() == JSJitInfo::InlinableNative);
     SimdOperation simdOp = SimdOperation(jitInfo->nativeOp);
+
     MOZ_ASSERT(IsSimdType(simdType));
+    MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(simdType),
+               "Signedness must be specified for ints, and only for ints");
 
     switch(simdOp) {
       case SimdOperation::Constructor:
         // SIMD constructor calls are handled via inlineNonFunctionCall(), so
         // they won't show up here where target is required to be a JSFunction.
         // See also inlineConstructSimdObject().
         MOZ_CRASH("SIMD constructor call not expected.");
       case SimdOperation::Fn_check:
         return inlineSimdCheck(callInfo, native, simdType);
       case SimdOperation::Fn_splat:
         return inlineSimdSplat(callInfo, native, simdType);
       case SimdOperation::Fn_extractLane:
-        return inlineSimdExtractLane(callInfo, native, simdType);
+        return inlineSimdExtractLane(callInfo, native, simdType, sign);
       case SimdOperation::Fn_replaceLane:
         return inlineSimdReplaceLane(callInfo, native, simdType);
       case SimdOperation::Fn_select:
         return inlineSimdSelect(callInfo, native, simdType);
       case SimdOperation::Fn_swizzle:
         return inlineSimdShuffle(callInfo, native, simdType, 1, SimdTypeToLength(simdType));
       case SimdOperation::Fn_shuffle:
         return inlineSimdShuffle(callInfo, native, simdType, 2, SimdTypeToLength(simdType));
@@ -3139,51 +3151,58 @@ IonBuilder::inlineSimd(CallInfo& callInf
       case SimdOperation::Fn_xor:
         return inlineSimdBinary<MSimdBinaryBitwise>(callInfo, native, MSimdBinaryBitwise::xor_,
                                                     simdType);
 
         // Shifts.
       case SimdOperation::Fn_shiftLeftByScalar:
         return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::lsh, simdType);
       case SimdOperation::Fn_shiftRightByScalar:
-        // TODO: select opcode from simdType signedness.
-        MOZ_ASSERT(simdType == MIRType_Int32x4);
-        return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::rsh, simdType);
+        return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::rshForSign(sign),
+                                            simdType);
       case SimdOperation::Fn_shiftRightArithmeticByScalar:
         return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::rsh, simdType);
       case SimdOperation::Fn_shiftRightLogicalByScalar:
         return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::ursh, simdType);
 
         // Boolean unary.
       case SimdOperation::Fn_allTrue:
         return inlineSimdAnyAllTrue(callInfo, /* IsAllTrue= */true, native);
       case SimdOperation::Fn_anyTrue:
         return inlineSimdAnyAllTrue(callInfo, /* IsAllTrue= */false, native);
 
         // Comparisons.
       case SimdOperation::Fn_lessThan:
-        return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThan, simdType);
+        return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThan,
+                              simdType, sign);
       case SimdOperation::Fn_lessThanOrEqual:
-        return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThanOrEqual, simdType);
+        return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThanOrEqual,
+                              simdType, sign);
       case SimdOperation::Fn_equal:
-        return inlineSimdComp(callInfo, native, MSimdBinaryComp::equal, simdType);
+        return inlineSimdComp(callInfo, native, MSimdBinaryComp::equal,
+                              simdType, sign);
       case SimdOperation::Fn_notEqual:
-        return inlineSimdComp(callInfo, native, MSimdBinaryComp::notEqual, simdType);
+        return inlineSimdComp(callInfo, native, MSimdBinaryComp::notEqual,
+                              simdType, sign);
       case SimdOperation::Fn_greaterThan:
-        return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThan, simdType);
+        return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThan,
+                              simdType, sign);
       case SimdOperation::Fn_greaterThanOrEqual:
-        return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThanOrEqual, simdType);
+        return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThanOrEqual,
+                              simdType, sign);
 
         // Int <-> Float conversions.
       case SimdOperation::Fn_fromInt32x4:
-        return inlineSimdConvert(callInfo, native, false, MIRType_Int32x4, simdType);
+        return inlineSimdConvert(callInfo, native, false, MIRType_Int32x4,
+                                 simdType, SimdSign::Signed);
       case SimdOperation::Fn_fromUint32x4:
-        return InliningStatus_NotInlined;
+        return inlineSimdConvert(callInfo, native, false, MIRType_Int32x4,
+                                 simdType, SimdSign::Unsigned);
       case SimdOperation::Fn_fromFloat32x4:
-        return inlineSimdConvert(callInfo, native, false, MIRType_Float32x4, simdType);
+        return inlineSimdConvert(callInfo, native, false, MIRType_Float32x4, simdType, sign);
 
         // Load/store.
       case SimdOperation::Fn_load:
         return inlineSimdLoad(callInfo, native, simdType, SimdTypeToLength(simdType));
       case SimdOperation::Fn_load1:
         return inlineSimdLoad(callInfo, native, simdType, 1);
       case SimdOperation::Fn_load2:
         return inlineSimdLoad(callInfo, native, simdType, 2);
@@ -3198,20 +3217,20 @@ IonBuilder::inlineSimd(CallInfo& callInf
       case SimdOperation::Fn_store3:
         return inlineSimdStore(callInfo, native, simdType, 3);
 
         // Bitcasts. One for each type with a memory representation.
       case SimdOperation::Fn_fromInt8x16Bits:
       case SimdOperation::Fn_fromInt16x8Bits:
         return InliningStatus_NotInlined;
       case SimdOperation::Fn_fromInt32x4Bits:
+      case SimdOperation::Fn_fromUint32x4Bits:
         return inlineSimdConvert(callInfo, native, true, MIRType_Int32x4, simdType);
       case SimdOperation::Fn_fromUint8x16Bits:
       case SimdOperation::Fn_fromUint16x8Bits:
-      case SimdOperation::Fn_fromUint32x4Bits:
         return InliningStatus_NotInlined;
       case SimdOperation::Fn_fromFloat32x4Bits:
         return inlineSimdConvert(callInfo, native, true, MIRType_Float32x4, simdType);
       case SimdOperation::Fn_fromFloat64x2Bits:
         return InliningStatus_NotInlined;
     }
 
     MOZ_CRASH("Unexpected SIMD opcode");
@@ -3257,16 +3276,21 @@ bool SimdTypeToMIRType(SimdType type, MI
       case SimdType::Bool32x4:    *mirType = MIRType_Bool32x4;  return true;
       default:                    return false;
     }
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr)
 {
+    if (!JitSupportsSimd()) {
+        trackOptimizationOutcome(TrackedOutcome::NoSimdJitSupport);
+        return InliningStatus_NotInlined;
+    }
+
     // Generic constructor of SIMD valuesX4.
     MIRType simdType;
     if (!SimdTypeToMIRType(descr->type(), &simdType))
         return InliningStatus_NotInlined;
 
     // Take the templateObject out of Baseline ICs, such that we can box
     // SIMD value type in the same kind of objects.
     MOZ_ASSERT(size_t(descr->size(descr->type())) < InlineTypedObject::MaximumSize);
@@ -3348,17 +3372,20 @@ IonBuilder::inlineSimdCheck(CallInfo& ca
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::boxSimd(CallInfo& callInfo, MInstruction* ins, InlineTypedObject* templateObj)
 {
     MSimdBox* obj = MSimdBox::New(alloc(), constraints(), ins, templateObj,
                                   templateObj->group()->initialHeap(constraints()));
-    current->add(ins);
+
+    // In some cases, ins has already been added to current.
+    if (!ins->block())
+        current->add(ins);
     current->add(obj);
     current->push(obj);
 
     callInfo.setImplicitlyUsedUnchecked();
     return InliningStatus_Inlined;
 }
 
 template<typename T>
@@ -3376,30 +3403,31 @@ IonBuilder::inlineSimdBinary(CallInfo& c
     // instructions are supposed to produce a TypeError when they're called
     // with non SIMD-arguments.
     T* ins = T::New(alloc(), callInfo.getArg(0), callInfo.getArg(1), op, mirType);
     return boxSimd(callInfo, ins, templateObj);
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineSimdComp(CallInfo& callInfo, JSNative native, MSimdBinaryComp::Operation op,
-                           MIRType mirType)
+                           MIRType mirType, SimdSign sign)
 {
     InlineTypedObject* templateObj = nullptr;
     if (!canInlineSimd(callInfo, native, 2, &templateObj))
         return InliningStatus_NotInlined;
 
     // If the type of any of the arguments is neither a SIMD type, an Object
     // type, or a Value, then the applyTypes phase will add a fallible box &
     // unbox sequence.  This does not matter much as all binary SIMD
     // instructions are supposed to produce a TypeError when they're called
     // with non SIMD-arguments.
     MDefinition* lhs = callInfo.getArg(0);
     MDefinition* rhs = callInfo.getArg(1);
-    MSimdBinaryComp* ins = MSimdBinaryComp::New(alloc(), lhs, rhs, op, mirType);
+    MInstruction* ins =
+      MSimdBinaryComp::AddLegalized(alloc(), current, lhs, rhs, op, mirType, sign);
     return boxSimd(callInfo, ins, templateObj);
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineSimdUnary(CallInfo& callInfo, JSNative native, MSimdUnaryArith::Operation op,
                             MIRType mirType)
 {
     InlineTypedObject* templateObj = nullptr;
@@ -3425,33 +3453,42 @@ IonBuilder::inlineSimdSplat(CallInfo& ca
     if (SimdTypeToLaneType(mirType) == MIRType_Boolean)
         arg = convertToBooleanSimdLane(arg);
 
     MSimdSplatX4* ins = MSimdSplatX4::New(alloc(), arg, mirType);
     return boxSimd(callInfo, ins, templateObj);
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, MIRType vecType)
+IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native,
+                                  MIRType vecType, SimdSign sign)
 {
-    InlineTypedObject* templateObj = nullptr;
-    if (!canInlineSimd(callInfo, native, 2, &templateObj))
+    // extractLane() returns a scalar, so don't use canInlineSimd() which looks
+    // for a template object.
+    if (callInfo.argc() != 2 || callInfo.constructing()) {
+        trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
         return InliningStatus_NotInlined;
+    }
 
     MDefinition* arg = callInfo.getArg(1);
     if (!arg->isConstantValue() || arg->type() != MIRType_Int32)
         return InliningStatus_NotInlined;
     int32_t lane = callInfo.getArg(1)->constantValue().toInt32();
     if (lane < 0 || lane >= 4)
         return InliningStatus_NotInlined;
 
     // See comment in inlineSimdBinary
     MIRType laneType = SimdTypeToLaneType(vecType);
+
+    // An Uint32 lane can't be represented in MIRType_Int32. Get it as a double.
+    if (sign == SimdSign::Unsigned && vecType == MIRType_Int32x4)
+        laneType = MIRType_Double;
+
     MSimdExtractElement* ins = MSimdExtractElement::New(alloc(), callInfo.getArg(0),
-                                                        vecType, laneType, SimdLane(lane));
+                                                        vecType, laneType, SimdLane(lane), sign);
     current->add(ins);
     current->push(ins);
     callInfo.setImplicitlyUsedUnchecked();
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, MIRType mirType)
@@ -3473,30 +3510,36 @@ IonBuilder::inlineSimdReplaceLane(CallIn
     if (SimdTypeToLaneType(mirType) == MIRType_Boolean)
         value = convertToBooleanSimdLane(value);
 
     MSimdInsertElement* ins =
       MSimdInsertElement::New(alloc(), callInfo.getArg(0), value, mirType, SimdLane(lane));
     return boxSimd(callInfo, ins, templateObj);
 }
 
+// Inline a SIMD conversion or bitcast. When isCast==false, one of the types
+// must be floating point and the other integer. In this case, sign indicates if
+// the integer lanes should be treated as signed or unsigned integers.
 IonBuilder::InliningStatus
 IonBuilder::inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
-                              MIRType fromType, MIRType toType)
+                              MIRType fromType, MIRType toType, SimdSign sign)
 {
     InlineTypedObject* templateObj = nullptr;
     if (!canInlineSimd(callInfo, native, 1, &templateObj))
         return InliningStatus_NotInlined;
 
     // See comment in inlineSimdBinary
     MInstruction* ins;
     if (isCast)
+        // Signed/Unsigned doesn't matter for bitcasts.
         ins = MSimdReinterpretCast::New(alloc(), callInfo.getArg(0), fromType, toType);
     else
-        ins = MSimdConvert::New(alloc(), callInfo.getArg(0), fromType, toType);
+        // Possibly expand into multiple instructions.
+        ins = MSimdConvert::AddLegalized(alloc(), current, callInfo.getArg(0),
+                                         fromType, toType, sign);
 
     return boxSimd(callInfo, ins, templateObj);
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineSimdSelect(CallInfo& callInfo, JSNative native, MIRType mirType)
 {
     InlineTypedObject* templateObj = nullptr;
@@ -3528,19 +3571,22 @@ IonBuilder::inlineSimdShuffle(CallInfo& 
         ins->setLane(i, callInfo.getArg(numVectors + i));
 
     return boxSimd(callInfo, ins, templateObj);
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native)
 {
-    InlineTypedObject* templateObj = nullptr;
-    if (!canInlineSimd(callInfo, native, 1, &templateObj))
+    // anyTrue() / allTrue() return a scalar, so don't use canInlineSimd() which looks
+    // for a template object.
+    if (callInfo.argc() != 1 || callInfo.constructing()) {
+        trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
         return InliningStatus_NotInlined;
+    }
 
     MUnaryInstruction* ins;
     if (IsAllTrue)
         ins = MSimdAllTrue::New(alloc(), callInfo.getArg(0), MIRType_Bool32x4);
     else
         ins = MSimdAnyTrue::New(alloc(), callInfo.getArg(0), MIRType_Bool32x4);
 
     current->add(ins);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1032,16 +1032,158 @@ MSimdGeneralShuffle::foldsTo(TempAllocat
 
     if (numVectors() == 1)
         return MSimdSwizzle::New(alloc, vector(0), type(), lanes[0], lanes[1], lanes[2], lanes[3]);
 
     MOZ_ASSERT(numVectors() == 2);
     return MSimdShuffle::New(alloc, vector(0), vector(1), type(), lanes[0], lanes[1], lanes[2], lanes[3]);
 }
 
+MInstruction*
+MSimdConvert::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* obj,
+                           MIRType fromType, MIRType toType, SimdSign sign)
+{
+    if (SupportsUint32x4FloatConversions || sign != SimdSign::Unsigned) {
+        MInstruction* ins = New(alloc, obj, fromType, toType, sign);
+        addTo->add(ins);
+        return ins;
+    }
+
+    // This architecture can't do Uint32x4 <-> Float32x4 conversions (Hi SSE!)
+    MOZ_ASSERT(sign == SimdSign::Unsigned);
+    if (fromType == MIRType_Int32x4 && toType == MIRType_Float32x4) {
+        // Converting Uint32x4 -> Float32x4. This algorithm is from LLVM.
+        //
+        // Split the input number into high and low parts:
+        //
+        // uint32_t hi = x >> 16;
+        // uint32_t lo = x & 0xffff;
+        //
+        // Insert these parts as the low mantissa bits in a float32 number with
+        // the corresponding exponent:
+        //
+        // float fhi = (bits-as-float)(hi | 0x53000000); // 0x1.0p39f + hi*2^16
+        // float flo = (bits-as-float)(lo | 0x4b000000); // 0x1.0p23f + lo
+        //
+        // Subtract the bias from the hi part:
+        //
+        // fhi -= (0x1.0p39 + 0x1.0p23) // hi*2^16 - 0x1.0p23
+        //
+        // And finally combine:
+        //
+        // result = flo + fhi // lo + hi*2^16.
+
+        // Compute hi = obj >> 16 (lane-wise unsigned shift).
+        MInstruction* c16 = MConstant::New(alloc, Int32Value(16));
+        addTo->add(c16);
+        MInstruction* hi = MSimdShift::New(alloc, obj, c16, MSimdShift::ursh, MIRType_Int32x4);
+        addTo->add(hi);
+
+        // Compute lo = obj & 0xffff (lane-wise).
+        MInstruction* m16 =
+          MSimdConstant::New(alloc, SimdConstant::SplatX4(0xffff), MIRType_Int32x4);
+        addTo->add(m16);
+        MInstruction* lo =
+          MSimdBinaryBitwise::New(alloc, obj, m16, MSimdBinaryBitwise::and_, MIRType_Int32x4);
+        addTo->add(lo);
+
+        // Mix in the exponents.
+        MInstruction* exphi =
+          MSimdConstant::New(alloc, SimdConstant::SplatX4(0x53000000), MIRType_Int32x4);
+        addTo->add(exphi);
+        MInstruction* mhi =
+          MSimdBinaryBitwise::New(alloc, hi, exphi, MSimdBinaryBitwise::or_, MIRType_Int32x4);
+        addTo->add(mhi);
+        MInstruction* explo =
+          MSimdConstant::New(alloc, SimdConstant::SplatX4(0x4b000000), MIRType_Int32x4);
+        addTo->add(explo);
+        MInstruction* mlo =
+          MSimdBinaryBitwise::New(alloc, lo, explo, MSimdBinaryBitwise::or_, MIRType_Int32x4);
+        addTo->add(mlo);
+
+        // Bit-cast both to Float32x4.
+        MInstruction* fhi =
+          MSimdReinterpretCast::New(alloc, mhi, MIRType_Int32x4, MIRType_Float32x4);
+        addTo->add(fhi);
+        MInstruction* flo =
+          MSimdReinterpretCast::New(alloc, mlo, MIRType_Int32x4, MIRType_Float32x4);
+        addTo->add(flo);
+
+        // Subtract out the bias: 0x1.0p39f + 0x1.0p23f.
+        // MSVC doesn't support the hexadecimal float syntax.
+        const float BiasValue = 549755813888.f + 8388608.f;
+        MInstruction* bias =
+          MSimdConstant::New(alloc, SimdConstant::SplatX4(BiasValue), MIRType_Float32x4);
+        addTo->add(bias);
+        MInstruction* fhi_debiased =
+          MSimdBinaryArith::New(alloc, fhi, bias, MSimdBinaryArith::Op_sub, MIRType_Float32x4);
+        addTo->add(fhi_debiased);
+
+        // Compute the final result.
+        MInstruction* result = MSimdBinaryArith::New(alloc, fhi_debiased, flo,
+                                                     MSimdBinaryArith::Op_add, MIRType_Float32x4);
+        addTo->add(result);
+
+        return result;
+    }
+
+    if (fromType == MIRType_Float32x4 && toType == MIRType_Int32x4) {
+        // The Float32x4 -> Uint32x4 conversion can throw if the input is out of
+        // range. This is handled by the LFloat32x4ToUint32x4 expansion.
+        MInstruction* ins = New(alloc, obj, fromType, toType, sign);
+        addTo->add(ins);
+        return ins;
+    }
+
+    MOZ_CRASH("Unhandled SIMD type conversion");
+}
+
+MInstruction*
+MSimdBinaryComp::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
+                              MDefinition* right, Operation op, MIRType opType, SimdSign sign)
+{
+    bool IsEquality = op == equal || op == notEqual;
+
+    if (!SupportsUint32x4Compares && sign == SimdSign::Unsigned && !IsEquality) {
+        MOZ_ASSERT(opType == MIRType_Int32x4);
+        // This is an order comparison of Uint32x4 vectors which are not supported on this target.
+        // Simply offset |left| and |right| by INT_MIN, then do a signed comparison.
+        MInstruction* bias =
+          MSimdConstant::New(alloc, SimdConstant::SplatX4(int32_t(0x80000000)), opType);
+        addTo->add(bias);
+
+        // Add the bias.
+        MInstruction* bleft =
+          MSimdBinaryArith::New(alloc, left, bias, MSimdBinaryArith::Op_add, opType);
+        addTo->add(bleft);
+        MInstruction* bright =
+          MSimdBinaryArith::New(alloc, right, bias, MSimdBinaryArith::Op_add, opType);
+        addTo->add(bright);
+
+        // Do the equivalent signed comparison.
+        MInstruction* result =
+          MSimdBinaryComp::New(alloc, bleft, bright, op, opType, SimdSign::Signed);
+        addTo->add(result);
+
+        return result;
+    }
+
+    if (!SupportsUint32x4Compares && sign == SimdSign::Unsigned && opType == MIRType_Int32x4) {
+        // The sign doesn't matter for equality tests. Flip it to make the
+        // backend assertions happy.
+        MOZ_ASSERT(IsEquality);
+        sign = SimdSign::Signed;
+    }
+
+    // This is a legal operation already. Just create the instruction requested.
+    MInstruction* result = MSimdBinaryComp::New(alloc, left, right, op, opType, sign);
+    addTo->add(result);
+    return result;
+}
+
 template <typename T>
 static void
 PrintOpcodeOperation(T* mir, GenericPrinter& out)
 {
     mir->MDefinition::printOpcode(out);
     out.printf(" (%s)", T::OperationName(mir->operation()));
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1537,50 +1537,73 @@ class MSimdConstant
     ALLOW_CLONE(MSimdConstant)
 };
 
 // Converts all lanes of a given vector into the type of another vector
 class MSimdConvert
   : public MUnaryInstruction,
     public SimdPolicy<0>::Data
 {
-    MSimdConvert(MDefinition* obj, MIRType fromType, MIRType toType)
-      : MUnaryInstruction(obj)
+    // When either fromType or toType is an integer vector, should it be treated
+    // as signed or unsigned. Note that we don't support int-int conversions -
+    // use MSimdReinterpretCast for that.
+    SimdSign sign_;
+
+    MSimdConvert(MDefinition* obj, MIRType fromType, MIRType toType, SimdSign sign)
+      : MUnaryInstruction(obj), sign_(sign)
     {
         MOZ_ASSERT(IsSimdType(toType));
+        // All conversions are int <-> float, so signedness is required.
+        MOZ_ASSERT(sign != SimdSign::NotApplicable);
+
         setResultType(toType);
         specialization_ = fromType; // expects fromType as input
 
         setMovable();
         if (IsFloatingPointSimdType(fromType) && IsIntegerSimdType(toType)) {
             // Does the extra range check => do not remove
             setGuard();
         }
     }
 
   public:
     INSTRUCTION_HEADER(SimdConvert)
     static MSimdConvert* NewAsmJS(TempAllocator& alloc, MDefinition* obj, MIRType fromType,
                                   MIRType toType)
     {
         MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
-        return new(alloc) MSimdConvert(obj, fromType, toType);
+        // AsmJS only has signed integer vectors for now.
+        return new(alloc) MSimdConvert(obj, fromType, toType, SimdSign::Signed);
     }
 
     static MSimdConvert* New(TempAllocator& alloc, MDefinition* obj, MIRType fromType,
-                             MIRType toType)
-    {
-        return new(alloc) MSimdConvert(obj, fromType, toType);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
+                             MIRType toType, SimdSign sign)
+    {
+        return new(alloc) MSimdConvert(obj, fromType, toType, sign);
+    }
+
+    // Create a MSimdConvert instruction and add it to the basic block.
+    // Possibly create and add an equivalent sequence of instructions instead if
+    // the current target doesn't support the requested conversion directly.
+    // Return the inserted MInstruction that computes the converted value.
+    static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* obj,
+                                      MIRType fromType, MIRType toType, SimdSign sign);
+
+    SimdSign signedness() const {
+        return sign_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        const MSimdConvert* other = ins->toSimdConvert();
+        return sign_ == other->sign_;
     }
     ALLOW_CLONE(MSimdConvert)
 };
 
 // Casts bits of a vector input to another SIMD type (doesn't generate code).
 class MSimdReinterpretCast
   : public MUnaryInstruction,
     public SimdPolicy<0>::Data
@@ -1614,66 +1637,88 @@ class MSimdReinterpretCast
     }
     bool congruentTo(const MDefinition* ins) const override {
         return congruentIfOperandsEqual(ins);
     }
     ALLOW_CLONE(MSimdReinterpretCast)
 };
 
 // Extracts a lane element from a given vector type, given by its lane symbol.
+//
+// For integer SIMD types, a SimdSign must be provided so the lane value can be
+// converted to a scalar correctly.
 class MSimdExtractElement
   : public MUnaryInstruction,
     public SimdPolicy<0>::Data
 {
   protected:
     SimdLane lane_;
-
-    MSimdExtractElement(MDefinition* obj, MIRType vecType, MIRType laneType, SimdLane lane)
-      : MUnaryInstruction(obj), lane_(lane)
+    SimdSign sign_;
+
+    MSimdExtractElement(MDefinition* obj, MIRType vecType, MIRType laneType, SimdLane lane,
+                        SimdSign sign)
+      : MUnaryInstruction(obj), lane_(lane), sign_(sign)
     {
         MOZ_ASSERT(IsSimdType(vecType));
         MOZ_ASSERT(uint32_t(lane) < SimdTypeToLength(vecType));
         MOZ_ASSERT(!IsSimdType(laneType));
+        MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(vecType),
+                   "Signedness must be specified for integer SIMD extractLanes");
         // The resulting type should match the lane type.
         // Allow extracting boolean lanes directly into an Int32 (for asm.js).
+        // Allow extracting Uint32 lanes into a double.
+        //
+        // We also allow extracting Uint32 lanes into a MIRType_Int32. This is
+        // equivalent to extracting the Uint32 lane to a double and then
+        // applying MTruncateToInt32, but it bypasses the conversion to/from
+        // double.
         MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType ||
-                   (IsBooleanSimdType(vecType) && laneType == MIRType_Int32));
+                   (IsBooleanSimdType(vecType) && laneType == MIRType_Int32) ||
+                   (vecType == MIRType_Int32x4 && laneType == MIRType_Double &&
+                    sign == SimdSign::Unsigned));
 
         setMovable();
         specialization_ = vecType;
         setResultType(laneType);
     }
 
   public:
     INSTRUCTION_HEADER(SimdExtractElement)
 
     static MSimdExtractElement* NewAsmJS(TempAllocator& alloc, MDefinition* obj, MIRType type,
                                          SimdLane lane)
     {
-        return new(alloc) MSimdExtractElement(obj, obj->type(), type, lane);
+        // Only signed integer types in AsmJS so far.
+        SimdSign sign =
+          IsIntegerSimdType(obj->type()) ? SimdSign::Signed : SimdSign::NotApplicable;
+        return new (alloc) MSimdExtractElement(obj, obj->type(), type, lane, sign);
     }
 
     static MSimdExtractElement* New(TempAllocator& alloc, MDefinition* obj, MIRType vecType,
-                                    MIRType scalarType, SimdLane lane)
-    {
-        return new(alloc) MSimdExtractElement(obj, vecType, scalarType, lane);
+                                    MIRType scalarType, SimdLane lane, SimdSign sign)
+    {
+        return new(alloc) MSimdExtractElement(obj, vecType, scalarType, lane, sign);
     }
 
     SimdLane lane() const {
         return lane_;
     }
 
+    SimdSign signedness() const {
+        return sign_;
+    }
+
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
     bool congruentTo(const MDefinition* ins) const override {
         if (!ins->isSimdExtractElement())
             return false;
         const MSimdExtractElement* other = ins->toSimdExtractElement();
-        if (other->lane_ != lane_)
+        if (other->lane_ != lane_ || other->sign_ != sign_)
             return false;
         return congruentIfOperandsEqual(other);
     }
     ALLOW_CLONE(MSimdExtractElement)
 };
 
 // Replaces the datum in the given lane by a scalar value of the same type.
 class MSimdInsertElement
@@ -2105,18 +2150,20 @@ class MSimdUnaryArith
     }
 
     void printOpcode(GenericPrinter& out) const override;
 
     ALLOW_CLONE(MSimdUnaryArith);
 };
 
 // Compares each value of a SIMD vector to each corresponding lane's value of
-// another SIMD vector, and returns a int32x4 vector containing the results of
+// another SIMD vector, and returns a boolean vector containing the results of
 // the comparison: all bits are set to 1 if the comparison is true, 0 otherwise.
+// When comparing integer vectors, a SimdSign must be provided to request signed
+// or unsigned comparison.
 class MSimdBinaryComp
   : public MBinaryInstruction,
     public SimdAllPolicy::Data
 {
   public:
     enum Operation {
 #define NAME_(x) x,
         FOREACH_COMP_SIMD_OP(NAME_)
@@ -2129,48 +2176,64 @@ class MSimdBinaryComp
         FOREACH_COMP_SIMD_OP(NAME_)
 #undef NAME_
         }
         MOZ_CRASH("unexpected operation");
     }
 
   private:
     Operation operation_;
-
-    MSimdBinaryComp(MDefinition* left, MDefinition* right, Operation op, MIRType opType)
-      : MBinaryInstruction(left, right), operation_(op)
-    {
+    SimdSign sign_;
+
+    MSimdBinaryComp(MDefinition* left, MDefinition* right, Operation op, MIRType opType,
+                    SimdSign sign)
+      : MBinaryInstruction(left, right), operation_(op), sign_(sign)
+    {
+        MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(opType),
+                   "Signedness must be specified for integer SIMD compares");
         setResultType(MIRType_Bool32x4);
         specialization_ = opType;
         setMovable();
         if (op == equal || op == notEqual)
             setCommutative();
     }
 
   public:
     INSTRUCTION_HEADER(SimdBinaryComp)
     static MSimdBinaryComp* NewAsmJS(TempAllocator& alloc, MDefinition* left, MDefinition* right,
                                      Operation op)
     {
         MOZ_ASSERT(IsSimdType(left->type()));
         MOZ_ASSERT(left->type() == right->type());
-        return new(alloc) MSimdBinaryComp(left, right, op, left->type());
+        // AsmJS only has signed vectors for now.
+        SimdSign sign =
+          IsIntegerSimdType(left->type()) ? SimdSign::Signed : SimdSign::NotApplicable;
+        return new (alloc) MSimdBinaryComp(left, right, op, left->type(), sign);
     }
 
     static MSimdBinaryComp* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
-                                Operation op, MIRType opType)
-    {
-        return new(alloc) MSimdBinaryComp(left, right, op, opType);
-    }
-
-    AliasSet getAliasSet() const override {
+                                Operation op, MIRType opType, SimdSign sign)
+    {
+        return new(alloc) MSimdBinaryComp(left, right, op, opType, sign);
+    }
+
+    // Create a MSimdBinaryComp or an equivalent sequence of instructions
+    // supported by the current target.
+    // Add all instructions to the basic block |addTo|.
+    static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
+                                      MDefinition* right, Operation op, MIRType opType,
+                                      SimdSign sign);
+
+    AliasSet getAliasSet() const override
+    {
         return AliasSet::None();
     }
 
     Operation operation() const { return operation_; }
+    SimdSign signedness() const { return sign_; }
     MIRType specialization() const { return specialization_; }
 
     // Swap the operands and reverse the comparison predicate.
     void reverse() {
         switch (operation()) {
           case greaterThan:        operation_ = lessThan; break;
           case greaterThanOrEqual: operation_ = lessThanOrEqual; break;
           case lessThan:           operation_ = greaterThan; break;
@@ -2183,17 +2246,18 @@ class MSimdBinaryComp
         swapOperands();
     }
 
     bool congruentTo(const MDefinition* ins) const override {
         if (!binaryCongruentTo(ins))
             return false;
         const MSimdBinaryComp* other = ins->toSimdBinaryComp();
         return specialization_ == other->specialization() &&
-               operation_ == other->operation();
+               operation_ == other->operation() &&
+               sign_ == other->signedness();
     }
 
     void printOpcode(GenericPrinter& out) const override;
 
     ALLOW_CLONE(MSimdBinaryComp)
 };
 
 class MSimdBinaryArith
@@ -2362,16 +2426,21 @@ class MSimdShift
 
     static MSimdShift* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
                            Operation op, MIRType type)
     {
         MOZ_ASSERT(type == MIRType_Int32x4);
         return new(alloc) MSimdShift(left, right, op);
     }
 
+    // Get the relevant right shift operation given the signedness of a type.
+    static Operation rshForSign(SimdSign sign) {
+        return sign == SimdSign::Unsigned ? ursh : rsh;
+    }
+
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 
     Operation operation() const { return operation_; }
 
     static const char* OperationName(Operation op) {
         switch (op) {
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -215,16 +215,22 @@ static_assert(CodeAlignment % SimdMemory
   "alignment for SIMD constants.");
 
 static_assert(JitStackAlignment % SimdMemoryAlignment == 0,
   "Stack alignment should be larger than any of the alignments which are used for "
   "spilled values.  Thus it should be larger than the alignment for SIMD accesses.");
 
 static const uint32_t AsmJSStackAlignment = SimdMemoryAlignment;
 
+// Does this architecture support SIMD conversions between Uint32x4 and Float32x4?
+static MOZ_CONSTEXPR_VAR bool SupportsUint32x4FloatConversions = false;
+
+// Does this architecture support comparisons of unsigned 32x4 integer vectors?
+static MOZ_CONSTEXPR_VAR bool SupportsUint32x4Compares = false;
+
 static const Scale ScalePointer = TimesFour;
 
 class Instruction;
 class InstBranchImm;
 uint32_t RM(Register r);
 uint32_t RS(Register r);
 uint32_t RD(Register r);
 uint32_t RT(Register r);
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -171,16 +171,22 @@ static constexpr uint32_t SimdMemoryAlig
 static_assert(CodeAlignment % SimdMemoryAlignment == 0,
   "Code alignment should be larger than any of the alignments which are used for "
   "the constant sections of the code buffer.  Thus it should be larger than the "
   "alignment for SIMD constants.");
 
 static const uint32_t AsmJSStackAlignment = SimdMemoryAlignment;
 static const int32_t AsmJSGlobalRegBias = 1024;
 
+// Does this architecture support SIMD conversions between Uint32x4 and Float32x4?
+static MOZ_CONSTEXPR_VAR bool SupportsUint32x4FloatConversions = false;
+
+// Does this architecture support comparisons of unsign