Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 02 Jun 2017 11:10:02 -0400
changeset 362022 95d2d23ff510bea680e9707c1ec166b0cc08dc6b
parent 362001 d69d09cff6dc8074a080cb09108eace712102dc2 (current diff)
parent 362021 54163bd59f7b3d415a3966c1b9370b9161a6e317 (diff)
child 362023 40eca3ed1d841a0d8f2fce7ecd485d1c53ab8af4
child 362034 ef4bfbee5d5e66a1d580cc5f42c271380c02ae5f
child 362073 39bbafe0ef81b6d16438bc7de2549ae595adaf86
push id31955
push userryanvm@gmail.com
push dateFri, 02 Jun 2017 15:10:12 +0000
treeherdermozilla-central@95d2d23ff510 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
--- a/accessible/tests/mochitest/role/test_general.html
+++ b/accessible/tests/mochitest/role/test_general.html
@@ -52,16 +52,23 @@
       testRole("head5", ROLE_HEADING);
       testRole("head6", ROLE_HEADING);
 
       // Test that an html:input @type="file" is exposed as ROLE_TEXT_CONTAINER.
       // After fix for bug 471356, it was temporarily exposed as a paragraph,
       // breaking JAWS compatibility.
       testRole("data", ROLE_TEXT_CONTAINER);
 
+      // Test that input type="checkbox" and type="radio" are
+      // exposed as such regardless of appearance style.
+      testRole("checkbox_regular", ROLE_CHECKBUTTON);
+      testRole("checkbox_appearance_none", ROLE_CHECKBUTTON);
+      testRole("radio_regular", ROLE_RADIOBUTTON);
+      testRole("radio_appearance_none", ROLE_RADIOBUTTON);
+
       // Test regular paragraph by comparison to make sure exposure does not
       // get broken.
       testRole("p", ROLE_PARAGRAPH);
 
       // Test dl, dt, dd
       testRole("definitionlist", ROLE_DEFINITION_LIST);
       testRole("definitionterm", ROLE_TERM);
       testRole("definitiondescription", ROLE_DEFINITION);
@@ -131,16 +138,20 @@
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <form id="frm" action="submit.php" method="post">
     <label for="data">File</label>:
     <input type="file" id="data" name="data" size="50"/>
+    <input type="checkbox" id="checkbox_regular" value="Check me"/>
+    <input type="checkbox" style="-moz-appearance: none;" id="checkbox_appearance_none" value="Check me"/>
+    <input type="radio" id="radio_regular" value="Check me"/>
+    <input type="radio" style="-moz-appearance: none;" id="radio_appearance_none" value="Check me"/>
   </form>
 
   <nav id="nav">a nav</nav>
   <header id="header">a header</header>
   <footer id="footer">a footer</footer>
   <article id="article">an article</article>
   <aside id="aside">by the way I am an aside</aside>
   <section id="section">a section</section>
--- a/browser/base/content/test/general/browser_sanitizeDialog.js
+++ b/browser/base/content/test/general/browser_sanitizeDialog.js
@@ -539,17 +539,17 @@ add_task(async function test_toggling_de
   }
 });
 
 // Test for offline cache deletion
 add_task(async function test_offline_cache() {
   // Prepare stuff, we will work with www.example.com
   var URL = "http://www.example.com";
   var URI = makeURI(URL);
-  var principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(URI);
+  var principal = Services.scriptSecurityManager.createCodebasePrincipal(URI, {});
 
   // Give www.example.com privileges to store offline data
   Services.perms.addFromPrincipal(principal, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
   Services.perms.addFromPrincipal(principal, "offline-app", Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
 
   // Store something to the offline cache
   var appcacheserv = Cc["@mozilla.org/network/application-cache-service;1"]
                      .getService(Ci.nsIApplicationCacheService);
--- a/browser/base/content/test/general/browser_web_channel.js
+++ b/browser/base/content/test/general/browser_web_channel.js
@@ -249,17 +249,17 @@ var gTests = [
 
       await BrowserTestUtils.withNewTab({
         gBrowser,
         url: HTTP_PATH + HTTP_ENDPOINT + "?unsolicited"
       }, async function(targetBrowser) {
 
         channel.send({ command: "unsolicited" }, {
           browser: targetBrowser,
-          principal: Services.scriptSecurityManager.getNoAppCodebasePrincipal(targetURI)
+          principal: Services.scriptSecurityManager.createCodebasePrincipal(targetURI, {}),
         });
 
         await messagePromise;
         channel.stopListening();
       });
     }
   },
   {
@@ -285,26 +285,26 @@ var gTests = [
       });
 
       await BrowserTestUtils.withNewTab({
         gBrowser,
         url: HTTP_PATH + HTTP_ENDPOINT + "?unsolicited"
       }, async function(targetBrowser) {
 
         let mismatchURI = Services.io.newURI(HTTP_MISMATCH_PATH);
-        let mismatchPrincipal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(mismatchURI);
+        let mismatchPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(mismatchURI, {});
 
         // send a message to the wrong principal. It should not be delivered
         // to content, and should not be echoed back.
         channel.send({ command: "unsolicited_no_response_expected" }, {
           browser: targetBrowser,
           principal: mismatchPrincipal
         });
 
-        let targetPrincipal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(targetURI);
+        let targetPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(targetURI, {});
 
         // send the `done` message to the correct principal. It
         // should be echoed back.
         channel.send({ command: "done" }, {
           browser: targetBrowser,
           principal: targetPrincipal
         });
 
--- a/browser/extensions/pocket/content/AboutPocket.jsm
+++ b/browser/extensions/pocket/content/AboutPocket.jsm
@@ -37,17 +37,17 @@ AboutPage.prototype = {
 
   newChannel(aURI, aLoadInfo) {
     let newURI = Services.io.newURI(this.chromeURL);
     let channel = Services.io.newChannelFromURIWithLoadInfo(newURI,
                                                             aLoadInfo);
     channel.originalURI = aURI;
 
     if (this.uriFlags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) {
-      let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(aURI);
+      let principal = Services.scriptSecurityManager.createCodebasePrincipal(aURI, {});
       channel.owner = principal;
     }
     return channel;
   },
 
   createInstance(outer, iid) {
     if (outer !== null) {
       throw Cr.NS_ERROR_NO_AGGREGATION;
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -295,24 +295,16 @@ BasePrincipal::GetOriginAttributes(JSCon
 NS_IMETHODIMP
 BasePrincipal::GetOriginSuffix(nsACString& aOriginAttributes)
 {
   MOZ_ASSERT(mOriginSuffix);
   return mOriginSuffix->ToUTF8String(aOriginAttributes);
 }
 
 NS_IMETHODIMP
-BasePrincipal::GetAppStatus(uint16_t* aAppStatus)
-{
-  // TODO: Remove GetAppStatus.
-  *aAppStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 BasePrincipal::GetAppId(uint32_t* aAppId)
 {
   if (AppId() == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
     MOZ_ASSERT(false);
     *aAppId = nsIScriptSecurityManager::NO_APP_ID;
     return NS_OK;
   }
 
@@ -336,23 +328,16 @@ BasePrincipal::GetPrivateBrowsingId(uint
 
 NS_IMETHODIMP
 BasePrincipal::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
 {
   *aIsInIsolatedMozBrowserElement = IsInIsolatedMozBrowserElement();
   return NS_OK;
 }
 
-NS_IMETHODIMP
-BasePrincipal::GetUnknownAppId(bool* aUnknownAppId)
-{
-  *aUnknownAppId = AppId() == nsIScriptSecurityManager::UNKNOWN_APP_ID;
-  return NS_OK;
-}
-
 bool
 BasePrincipal::AddonHasPermission(const nsAString& aPerm)
 {
   nsAutoString addonId;
   NS_ENSURE_SUCCESS(GetAddonId(addonId), false);
 
   if (addonId.IsEmpty()) {
     return false;
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -58,20 +58,18 @@ public:
   NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetCspJSON(nsAString& outCSPinJSON) override;
   NS_IMETHOD GetIsNullPrincipal(bool* aResult) override;
   NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override;
   NS_IMETHOD GetIsExpandedPrincipal(bool* aResult) override;
   NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override;
   NS_IMETHOD GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) final;
   NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final;
-  NS_IMETHOD GetAppStatus(uint16_t* aAppStatus) final;
-  NS_IMETHOD GetAppId(uint32_t* aAppStatus) final;
+  NS_IMETHOD GetAppId(uint32_t* aAppId) final;
   NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) final;
-  NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId) final;
   NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final;
   NS_IMETHOD GetPrivateBrowsingId(uint32_t* aPrivateBrowsingId) final;
 
   virtual bool AddonHasPermission(const nsAString& aPerm);
 
   virtual bool IsCodebasePrincipal() const { return false; };
 
   static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast<BasePrincipal*>(aPrin); }
--- a/caps/nsIPrincipal.idl
+++ b/caps/nsIPrincipal.idl
@@ -246,61 +246,31 @@ interface nsIPrincipal : nsISerializable
 
     /**
      * The base domain of the codebase URI to which this principal pertains
      * (generally the document URI), handling null principals and
      * non-hierarchical schemes correctly.
      */
     readonly attribute ACString baseDomain;
 
-    const short APP_STATUS_NOT_INSTALLED = 0;
-    const short APP_STATUS_INSTALLED     = 1;
-    const short APP_STATUS_PRIVILEGED    = 2;
-    const short APP_STATUS_CERTIFIED     = 3;
-
-    /**
-     * Gets the principal's app status, which indicates whether the principal
-     * corresponds to "app code", and if it does, how privileged that code is.
-     * This method returns one of the APP_STATUS constants above.
-     *
-     * Note that a principal may have
-     *
-     *   appId != nsIScriptSecurityManager::NO_APP_ID &&
-     *   appId != nsIScriptSecurityManager::UNKNOWN_APP_ID
-     *
-     * and still have appStatus == APP_STATUS_NOT_INSTALLED.  That's because
-     * appId identifies the app that contains this principal, but a window
-     * might be contained in an app and not be running code that the app has
-     * vouched for.  For example, the window might be inside an <iframe
-     * mozbrowser>, or the window's origin might not match the app's origin.
-     *
-     * If you're doing a check to determine "does this principal correspond to
-     * app code?", you must check appStatus; checking appId != NO_APP_ID is not
-     * sufficient.
-     */
-    [infallible] readonly attribute unsigned short appStatus;
-
     /**
      * Gets the id of the app this principal is inside.  If this principal is
      * not inside an app, returns nsIScriptSecurityManager::NO_APP_ID.
      *
      * Note that this principal does not necessarily have the permissions of
      * the app identified by appId.  For example, this principal might
      * correspond to an iframe whose origin differs from that of the app frame
      * containing it.  In this case, the iframe will have the appId of its
      * containing app frame, but the iframe must not run with the app's
      * permissions.
      *
      * Similarly, this principal might correspond to an <iframe mozbrowser>
      * inside an app frame; in this case, the content inside the iframe should
      * not have any of the app's permissions, even if the iframe is at the same
      * origin as the app.
-     *
-     * If you're doing a security check based on appId, you must check
-     * appStatus as well.
      */
     [infallible] readonly attribute unsigned long appId;
 
     /**
      * Gets the ID of the add-on this principal belongs to.
      */
     readonly attribute AString addonId;
 
@@ -323,23 +293,16 @@ interface nsIPrincipal : nsISerializable
      * <xul:browser> is not considered to be a mozbrowser element.
      * <iframe mozbrowser noisolation> does not count as isolated since
      * isolation is disabled.  Isolation can only be disabled if the
      * containing document is chrome.
      */
     [infallible] readonly attribute boolean isInIsolatedMozBrowserElement;
 
     /**
-     * Returns true if this principal has an unknown appId. This shouldn't
-     * generally be used. We only expose it due to not providing the correct
-     * appId everywhere where we construct principals.
-     */
-    [infallible] readonly attribute boolean unknownAppId;
-
-    /**
      * Returns true iff this is a null principal (corresponding to an
      * unknown, hence assumed minimally privileged, security context).
      */
     [infallible] readonly attribute boolean isNullPrincipal;
 
     /**
      * Returns true iff this principal corresponds to a codebase origin.
      */
--- a/caps/nsIScriptSecurityManager.idl
+++ b/caps/nsIScriptSecurityManager.idl
@@ -129,53 +129,30 @@ interface nsIScriptSecurityManager : nsI
     ///////////////// Principals ///////////////////////
 
     /**
      * Return the all-powerful system principal.
      */
     nsIPrincipal getSystemPrincipal();
 
     /**
-     * Returns a principal that has the given information.
-     * @param appId is the app id of the principal. It can't be UNKNOWN_APP_ID.
-     * @param inMozBrowser is true if the principal has to be considered as
-     * inside a mozbrowser frame.
-     *
-     * @deprecated use createCodebasePrincipal instead.
-     */
-    [deprecated] nsIPrincipal getAppCodebasePrincipal(in nsIURI uri,
-                                                      in unsigned long appId,
-                                                      in boolean inMozBrowser);
-
-    /**
-     * Returns a principal that has the appId and inMozBrowser of the load
-     * context.
-     * @param loadContext to get appId/inMozBrowser from.
+     * Returns a principal that has the OriginAttributes of the load context.
+     * @param loadContext to get the OriginAttributes from.
      */
     nsIPrincipal getLoadContextCodebasePrincipal(in nsIURI uri,
                                                  in nsILoadContext loadContext);
 
     /**
-     * Returns a principal that has the appId and inMozBrowser of the docshell
-     * inside a mozbrowser frame.
-     * @param docShell to get appId/inMozBrowser from.
+     * Returns a principal that has the OriginAttributes of the docshell.
+     * @param docShell to get the OriginAttributes from.
      */
     nsIPrincipal getDocShellCodebasePrincipal(in nsIURI uri,
                                               in nsIDocShell docShell);
 
     /**
-     * Returns a principal with that has the same origin as uri and is not part
-     * of an appliction.
-     * The returned principal will have appId = NO_APP_ID.
-     *
-     * @deprecated use createCodebasePrincipal instead.
-     */
-    [deprecated] nsIPrincipal getNoAppCodebasePrincipal(in nsIURI uri);
-
-    /**
      * Legacy method for getting a principal with no origin attributes.
      *
      * @deprecated use createCodebasePrincipal instead.
      */
     [deprecated] nsIPrincipal getCodebasePrincipal(in nsIURI uri);
 
     /**
      * Returns a principal whose origin is composed of |uri| and |originAttributes|.
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -1100,30 +1100,24 @@ NS_IMETHODIMP
 nsScriptSecurityManager::GetSystemPrincipal(nsIPrincipal **result)
 {
     NS_ADDREF(*result = mSystemPrincipal);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsScriptSecurityManager::GetNoAppCodebasePrincipal(nsIURI* aURI,
-                                                   nsIPrincipal** aPrincipal)
-{
-  OriginAttributes attrs;
-  nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
-  prin.forget(aPrincipal);
-  return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP
 nsScriptSecurityManager::GetCodebasePrincipal(nsIURI* aURI,
                                               nsIPrincipal** aPrincipal)
 {
-  return GetNoAppCodebasePrincipal(aURI, aPrincipal);
+  OriginAttributes attrs;
+  nsCOMPtr<nsIPrincipal> prin =
+    BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
+  prin.forget(aPrincipal);
+  return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, JS::Handle<JS::Value> aOriginAttributes,
                                                  JSContext* aCx, nsIPrincipal** aPrincipal)
 {
   OriginAttributes attrs;
   if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
@@ -1160,31 +1154,16 @@ nsScriptSecurityManager::CreateNullPrinc
       return NS_ERROR_INVALID_ARG;
   }
   nsCOMPtr<nsIPrincipal> prin = NullPrincipal::Create(attrs);
   prin.forget(aPrincipal);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI,
-                                                 uint32_t aAppId,
-                                                 bool aInIsolatedMozBrowser,
-                                                 nsIPrincipal** aPrincipal)
-{
-  NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
-                 NS_ERROR_INVALID_ARG);
-
-  OriginAttributes attrs(aAppId, aInIsolatedMozBrowser);
-  nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
-  prin.forget(aPrincipal);
-  return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP
 nsScriptSecurityManager::
   GetLoadContextCodebasePrincipal(nsIURI* aURI,
                                   nsILoadContext* aLoadContext,
                                   nsIPrincipal** aPrincipal)
 {
   NS_ENSURE_STATE(aLoadContext);
   OriginAttributes docShellAttrs;
   aLoadContext->GetOriginAttributes(docShellAttrs);
--- a/dom/animation/test/crashtests/crashtests.list
+++ b/dom/animation/test/crashtests/crashtests.list
@@ -1,17 +1,17 @@
 pref(dom.animations-api.core.enabled,true) load 1239889-1.html
 pref(dom.animations-api.core.enabled,true) load 1244595-1.html
 pref(dom.animations-api.core.enabled,true) load 1216842-1.html
 pref(dom.animations-api.core.enabled,true) load 1216842-2.html
 pref(dom.animations-api.core.enabled,true) load 1216842-3.html
 pref(dom.animations-api.core.enabled,true) load 1216842-4.html
 pref(dom.animations-api.core.enabled,true) load 1216842-5.html
 pref(dom.animations-api.core.enabled,true) load 1216842-6.html
-pref(dom.animations-api.core.enabled,true) load 1272475-1.html
+skip-if(webrender) pref(dom.animations-api.core.enabled,true) load 1272475-1.html # see bug 1367994
 pref(dom.animations-api.core.enabled,true) load 1272475-2.html
 pref(dom.animations-api.core.enabled,true) load 1278485-1.html
 pref(dom.animations-api.core.enabled,true) load 1277272-1.html
 pref(dom.animations-api.core.enabled,true) load 1290535-1.html
 pref(dom.animations-api.core.enabled,true) load 1304886-1.html
 pref(dom.animations-api.core.enabled,true) load 1322382-1.html
 pref(dom.animations-api.core.enabled,true) load 1322291-1.html
 pref(dom.animations-api.core.enabled,true) load 1322291-2.html
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -3617,17 +3617,17 @@ private:
 
     nsPIDOMWindowInner* window = wp->GetWindow();
     if (window && window->GetExtantDoc()) {
       window->GetExtantDoc()->WarnOnceAbout(mOperation);
     }
   }
 
   void
-  RunBackOnWorkerThread() override
+  RunBackOnWorkerThreadForCleanup() override
   {}
 };
 
 } // anonymous namespace
 
 void
 DeprecationWarning(JSContext* aCx, JSObject* aObject,
                    nsIDocument::DeprecatedOperations aOperation)
--- a/dom/cache/PrincipalVerifier.cpp
+++ b/dom/cache/PrincipalVerifier.cpp
@@ -118,20 +118,18 @@ PrincipalVerifier::VerifyOnMainThread()
   nsresult rv;
   RefPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(mPrincipalInfo,
                                                               &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     DispatchToInitiatingThread(rv);
     return;
   }
 
-  // We disallow null principal and unknown app IDs on the client side, but
-  // double-check here.
-  if (NS_WARN_IF(principal->GetIsNullPrincipal() ||
-                 principal->GetUnknownAppId())) {
+  // We disallow null principal on the client side, but double-check here.
+  if (NS_WARN_IF(principal->GetIsNullPrincipal())) {
     DispatchToInitiatingThread(NS_ERROR_FAILURE);
     return;
   }
 
   nsCOMPtr<nsIScriptSecurityManager> ssm = nsContentUtils::GetSecurityManager();
   if (NS_WARN_IF(!ssm)) {
     DispatchToInitiatingThread(NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
     return;
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -332,22 +332,22 @@ public:
   }
 
   bool
   Dispatch(JSContext* aCx)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
 
     if (NS_WARN_IF(!PreDispatch(aCx))) {
-      RunBackOnWorkerThread();
+      RunBackOnWorkerThreadForCleanup();
       return false;
     }
 
     if (NS_WARN_IF(!WorkerProxyToMainThreadRunnable::Dispatch())) {
-      // RunBackOnWorkerThread() will be called by
+      // RunBackOnWorkerThreadForCleanup() will be called by
       // WorkerProxyToMainThreadRunnable::Dispatch().
       return false;
     }
 
     return true;
   }
 
 protected:
@@ -416,17 +416,17 @@ protected:
     global = js::UncheckedUnwrap(global);
 
     JSAutoCompartment ac(cx, global);
 
     RunConsole(cx, nullptr, nullptr);
   }
 
   void
-  RunBackOnWorkerThread() override
+  RunBackOnWorkerThreadForCleanup() override
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
     ReleaseData();
     mConsole = nullptr;
   }
 
   // This method is called in the owning thread of the Console object.
   virtual bool
--- a/dom/file/ipc/IPCBlobInputStreamStorage.cpp
+++ b/dom/file/ipc/IPCBlobInputStreamStorage.cpp
@@ -117,37 +117,56 @@ IPCBlobInputStreamStorage::ForgetStream(
   mozilla::StaticMutexAutoLock lock(gMutex);
   mStorage.Remove(aID);
 }
 
 void
 IPCBlobInputStreamStorage::GetStream(const nsID& aID,
                                      nsIInputStream** aInputStream)
 {
-  mozilla::StaticMutexAutoLock lock(gMutex);
-  StreamData* data = mStorage.Get(aID);
-  if (!data) {
-    *aInputStream = nullptr;
-    return;
+  *aInputStream = nullptr;
+
+  nsCOMPtr<nsIInputStream> inputStream;
+
+  // NS_CloneInputStream cannot be called when the mutex is locked because it
+  // can, recursively call GetStream() in case the child actor lives on the
+  // parent process.
+  {
+    mozilla::StaticMutexAutoLock lock(gMutex);
+    StreamData* data = mStorage.Get(aID);
+    if (!data) {
+      return;
+    }
+
+    inputStream = data->mInputStream;
   }
 
+  MOZ_ASSERT(inputStream);
+
   // We cannot return always the same inputStream because not all of them are
   // able to be reused. Better to clone them.
 
   nsCOMPtr<nsIInputStream> clonedStream;
   nsCOMPtr<nsIInputStream> replacementStream;
 
   nsresult rv =
-    NS_CloneInputStream(data->mInputStream, getter_AddRefs(clonedStream),
+    NS_CloneInputStream(inputStream, getter_AddRefs(clonedStream),
                         getter_AddRefs(replacementStream));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   if (replacementStream) {
+    mozilla::StaticMutexAutoLock lock(gMutex);
+    StreamData* data = mStorage.Get(aID);
+    // data can be gone in the meantime.
+    if (!data) {
+      return;
+    }
+
     data->mInputStream = replacementStream;
   }
 
   clonedStream.forget(aInputStream);
 }
 
 void
 IPCBlobInputStreamStorage::StoreCallback(const nsID& aID,
--- a/dom/push/test/xpcshell/head.js
+++ b/dom/push/test/xpcshell/head.js
@@ -425,24 +425,16 @@ var tearDownServiceInParent = Task.async
 
   let record = yield db.getByIdentifiers({
     scope: 'https://example.com/sub/ok',
     originAttributes: '',
   });
   ok(record.pushEndpoint.startsWith('https://example.org/push'),
     'Wrong push endpoint in subscription record');
 
-  record = yield db.getByIdentifiers({
-    scope: 'https://example.net/scope/1',
-    originAttributes: ChromeUtils.originAttributesToSuffix(
-      { appId: 1, inIsolatedMozBrowser: true }),
-  });
-  ok(record.pushEndpoint.startsWith('https://example.org/push'),
-    'Wrong push endpoint in app record');
-
   record = yield db.getByKeyID('3a414737-2fd0-44c0-af05-7efc172475fc');
   ok(!record, 'Unsubscribed record should not exist');
 });
 
 function putTestRecord(db, keyID, scope, quota) {
   return db.put({
     channelID: keyID,
     pushEndpoint: 'https://example.org/push/' + keyID,
--- a/dom/push/test/xpcshell/test_service_child.js
+++ b/dom/push/test/xpcshell/test_service_child.js
@@ -224,37 +224,16 @@ add_test(function test_unsubscribe_error
       strictEqual(success, false, 'Unexpected successful unsubscribe');
 
       do_test_finished();
       run_next_test();
     }
   );
 });
 
-add_test(function test_subscribe_app_principal() {
-  let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(
-    Services.io.newURI('https://example.net/app/1'),
-    1, /* appId */
-    true /* browserOnly */
-  );
-
-  do_test_pending();
-  PushServiceComponent.subscribe('https://example.net/scope/1', principal, (result, subscription) => {
-    ok(Components.isSuccessCode(result), 'Error creating subscription');
-    ok(subscription.endpoint.startsWith('https://example.org/push'),
-      'Wrong push endpoint in app subscription');
-    ok(!subscription.isSystemSubscription,
-      'Unexpected system subscription for app principal');
-    equal(subscription.quota, 16, 'Wrong quota for app subscription');
-
-    do_test_finished();
-    run_next_test();
-  });
-});
-
 add_test(function test_subscribe_origin_principal() {
   let scope = 'https://example.net/origin-principal';
   let principal =
     Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(scope);
 
   do_test_pending();
   PushServiceComponent.subscribe(scope, principal, (result, subscription) => {
     ok(Components.isSuccessCode(result),
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -672,23 +672,23 @@ WorkerProxyToMainThreadRunnable::~Worker
 {}
 
 bool
 WorkerProxyToMainThreadRunnable::Dispatch()
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   if (NS_WARN_IF(!HoldWorker())) {
-    RunBackOnWorkerThread();
+    RunBackOnWorkerThreadForCleanup();
     return false;
   }
 
   if (NS_WARN_IF(NS_FAILED(mWorkerPrivate->DispatchToMainThread(this)))) {
     ReleaseWorker();
-    RunBackOnWorkerThread();
+    RunBackOnWorkerThreadForCleanup();
     return false;
   }
 
   return true;
 }
 
 NS_IMETHODIMP
 WorkerProxyToMainThreadRunnable::Run()
@@ -710,32 +710,33 @@ WorkerProxyToMainThreadRunnable::PostDis
     ReleaseRunnable(WorkerPrivate* aWorkerPrivate,
                     WorkerProxyToMainThreadRunnable* aRunnable)
       : MainThreadWorkerControlRunnable(aWorkerPrivate)
       , mRunnable(aRunnable)
     {
       MOZ_ASSERT(aRunnable);
     }
 
-    // We must call RunBackOnWorkerThread() also if the runnable is canceled.
+    // We must call RunBackOnWorkerThreadForCleanup() also if the runnable is
+    // canceled.
     nsresult
     Cancel() override
     {
       WorkerRun(nullptr, mWorkerPrivate);
       return MainThreadWorkerControlRunnable::Cancel();
     }
 
     virtual bool
     WorkerRun(JSContext* aCx, workers::WorkerPrivate* aWorkerPrivate) override
     {
       MOZ_ASSERT(aWorkerPrivate);
       aWorkerPrivate->AssertIsOnWorkerThread();
 
       if (mRunnable) {
-        mRunnable->RunBackOnWorkerThread();
+        mRunnable->RunBackOnWorkerThreadForCleanup();
 
         // Let's release the worker thread.
         mRunnable->ReleaseWorker();
         mRunnable = nullptr;
       }
 
       return true;
     }
--- a/dom/workers/WorkerRunnable.h
+++ b/dom/workers/WorkerRunnable.h
@@ -410,28 +410,34 @@ public:
 
 private:
   NS_IMETHOD Run() override;
 };
 
 // This runnable is an helper class for dispatching something from a worker
 // thread to the main-thread and back to the worker-thread. During this
 // operation, this class will keep the worker alive.
+// The purpose of RunBackOnWorkerThreadForCleanup() must be used, as the name
+// says, only to release resources, no JS has to be executed, no timers, or
+// other things. The reason of such limitations is that, in order to execute
+// this method in any condition (also when the worker is shutting down), a
+// Control Runnable is used, and, this could generate a reordering of existing
+// runnables.
 class WorkerProxyToMainThreadRunnable : public Runnable
 {
 protected:
   explicit WorkerProxyToMainThreadRunnable(WorkerPrivate* aWorkerPrivate);
 
   virtual ~WorkerProxyToMainThreadRunnable();
 
   // First this method is called on the main-thread.
   virtual void RunOnMainThread() = 0;
 
   // After this second method is called on the worker-thread.
-  virtual void RunBackOnWorkerThread() = 0;
+  virtual void RunBackOnWorkerThreadForCleanup() = 0;
 
 public:
   bool Dispatch();
 
 private:
   NS_IMETHOD Run() override;
 
   void PostDispatchOnMainThread();
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -487,17 +487,17 @@ private:
   DECL_GFX_PREF(Once, "image.mem.surfacecache.size_factor",    ImageMemSurfaceCacheSizeFactor, uint32_t, 64);
   DECL_GFX_PREF(Once, "image.multithreaded_decoding.limit",    ImageMTDecodingLimit, int32_t, -1);
 
   DECL_GFX_PREF(Once, "layers.acceleration.disabled",          LayersAccelerationDisabledDoNotUseDirectly, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps",          LayersDrawFPS, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram",  FPSPrintHistogram, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabledDoNotUseDirectly, bool, false);
-  DECL_OVERRIDE_PREF(Live, "layers.advanced.background-color",        LayersAllowBackgroundColorLayers, gfxPrefs::OverrideBase_WebRendest());
+  DECL_OVERRIDE_PREF(Live, "layers.advanced.background-color",        LayersAllowBackgroundColorLayers, gfxPrefs::OverrideBase_WebRender());
   DECL_OVERRIDE_PREF(Live, "layers.advanced.background-image",        LayersAllowBackgroundImage, gfxPrefs::OverrideBase_WebRendest());
   DECL_GFX_PREF(Live, "layers.advanced.basic-layer.enabled",          LayersAdvancedBasicLayerEnabled, bool, false);
   DECL_OVERRIDE_PREF(Live, "layers.advanced.border-layers",           LayersAllowBorderLayers, gfxPrefs::OverrideBase_WebRendest());
   DECL_OVERRIDE_PREF(Live, "layers.advanced.boxshadow-inset-layers",  LayersAllowInsetBoxShadow, gfxPrefs::OverrideBase_WebRender());
   DECL_OVERRIDE_PREF(Live, "layers.advanced.boxshadow-outer-layers",  LayersAllowOuterBoxShadow, gfxPrefs::OverrideBase_WebRender());
   DECL_OVERRIDE_PREF(Live, "layers.advanced.bullet-layers",           LayersAllowBulletLayers, gfxPrefs::OverrideBase_WebRender());
   DECL_OVERRIDE_PREF(Live, "layers.advanced.button-foreground-layers", LayersAllowButtonForegroundLayers, gfxPrefs::OverrideBase_WebRender());
   DECL_OVERRIDE_PREF(Live, "layers.advanced.canvas-background-color", LayersAllowCanvasBackgroundColorLayers, gfxPrefs::OverrideBase_WebRendest());
--- a/js/public/HeapAPI.h
+++ b/js/public/HeapAPI.h
@@ -158,22 +158,22 @@ struct Zone
     // Note: Unrestricted access to the zone's runtime from an arbitrary
     // thread can easily lead to races. Use this method very carefully.
     JSRuntime* runtimeFromAnyThread() const {
         return runtime_;
     }
 
     GCState gcState() const { return gcState_; }
     bool wasGCStarted() const { return gcState_ != NoGC; }
-    bool isGCMarkingBlack() { return gcState_ == Mark; }
-    bool isGCMarkingGray() { return gcState_ == MarkGray; }
-    bool isGCSweeping() { return gcState_ == Sweep; }
-    bool isGCFinished() { return gcState_ == Finished; }
-    bool isGCCompacting() { return gcState_ == Compact; }
-    bool isGCSweepingOrCompacting() { return gcState_ == Sweep || gcState_ == Compact; }
+    bool isGCMarkingBlack() const { return gcState_ == Mark; }
+    bool isGCMarkingGray() const { return gcState_ == MarkGray; }
+    bool isGCSweeping() const { return gcState_ == Sweep; }
+    bool isGCFinished() const { return gcState_ == Finished; }
+    bool isGCCompacting() const { return gcState_ == Compact; }
+    bool isGCSweepingOrCompacting() const { return gcState_ == Sweep || gcState_ == Compact; }
 
     static MOZ_ALWAYS_INLINE JS::shadow::Zone* asShadowZone(JS::Zone* zone) {
         return reinterpret_cast<JS::shadow::Zone*>(zone);
     }
 };
 
 } /* namespace shadow */
 
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -4,16 +4,17 @@
  * 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 gc_GCRuntime_h
 #define gc_GCRuntime_h
 
 #include "mozilla/Atomics.h"
 #include "mozilla/EnumSet.h"
+#include "mozilla/Maybe.h"
 
 #include "jsfriendapi.h"
 #include "jsgc.h"
 
 #include "gc/AtomMarking.h"
 #include "gc/Heap.h"
 #include "gc/Nursery.h"
 #include "gc/Statistics.h"
@@ -993,16 +994,19 @@ class GCRuntime
     void sweepJitDataOnMainThread(FreeOp* fop);
     void endSweepingSweepGroup();
     IncrementalProgress performSweepActions(SliceBudget& sliceBudget,
                                             AutoLockForExclusiveAccess& lock);
     static IncrementalProgress sweepTypeInformation(GCRuntime* gc, FreeOp* fop, Zone* zone,
                                                     SliceBudget& budget, AllocKind kind);
     static IncrementalProgress mergeSweptObjectArenas(GCRuntime* gc, FreeOp* fop, Zone* zone,
                                                       SliceBudget& budget, AllocKind kind);
+    static IncrementalProgress sweepAtomsTable(GCRuntime* gc, FreeOp* fop, Zone* zone,
+                                               SliceBudget& budget, AllocKind kind);
+    IncrementalProgress sweepAtomsTable(SliceBudget& budget);
     static IncrementalProgress finalizeAllocKind(GCRuntime* gc, FreeOp* fop, Zone* zone,
                                                  SliceBudget& budget, AllocKind kind);
     static IncrementalProgress sweepShapeTree(GCRuntime* gc, FreeOp* fop, Zone* zone,
                                               SliceBudget& budget, AllocKind kind);
     void endSweepPhase(bool lastGC, AutoLockForExclusiveAccess& lock);
     bool allCCVisibleZonesWereCollected() const;
     void sweepZones(FreeOp* fop, ZoneGroup* group, bool lastGC);
     void sweepZoneGroups(FreeOp* fop, bool destroyingRuntime);
@@ -1218,16 +1222,17 @@ class GCRuntime
     /*
      * Incremental sweep state.
      */
     ActiveThreadData<JS::Zone*> sweepGroups;
     ActiveThreadOrGCTaskData<JS::Zone*> currentSweepGroup;
     ActiveThreadData<size_t> sweepPhaseIndex;
     ActiveThreadData<JS::Zone*> sweepZone;
     ActiveThreadData<size_t> sweepActionIndex;
+    ActiveThreadData<mozilla::Maybe<AtomSet::Enum>> maybeAtomsToSweep;
     ActiveThreadData<bool> abortSweepAfterCurrentGroup;
 
     /*
      * Concurrent sweep infrastructure.
      */
     void startTask(GCParallelTask& task, gcstats::PhaseKind phase, AutoLockHelperThreadState& locked);
     void joinTask(GCParallelTask& task, gcstats::PhaseKind phase, AutoLockHelperThreadState& locked);
     friend class AutoRunParallelTask;
--- a/js/src/gc/GenerateStatsPhases.py
+++ b/js/src/gc/GenerateStatsPhases.py
@@ -92,17 +92,18 @@ PhaseKindGraphRoots = [
             PhaseKind("SWEEP_MARK_INCOMING_GRAY", "Mark Incoming Gray Pointers", 14),
             PhaseKind("SWEEP_MARK_GRAY", "Mark Gray", 15),
             PhaseKind("SWEEP_MARK_GRAY_WEAK", "Mark Gray and Weak", 16)
         ]),
         PhaseKind("FINALIZE_START", "Finalize Start Callbacks", 17, [
             PhaseKind("WEAK_ZONES_CALLBACK", "Per-Slice Weak Callback", 57),
             PhaseKind("WEAK_COMPARTMENT_CALLBACK", "Per-Compartment Weak Callback", 58)
         ]),
-        PhaseKind("SWEEP_ATOMS", "Sweep Atoms", 18),
+        PhaseKind("UPDATE_ATOMS_BITMAP", "Sweep Atoms Bitmap", 68),
+        PhaseKind("SWEEP_ATOMS_TABLE", "Sweep Atoms Table", 18),
         PhaseKind("SWEEP_COMPARTMENTS", "Sweep Compartments", 20, [
             PhaseKind("SWEEP_DISCARD_CODE", "Sweep Discard Code", 21),
             PhaseKind("SWEEP_INNER_VIEWS", "Sweep Inner Views", 22),
             PhaseKind("SWEEP_CC_WRAPPER", "Sweep Cross Compartment Wrappers", 23),
             PhaseKind("SWEEP_BASE_SHAPE", "Sweep Base Shapes", 24),
             PhaseKind("SWEEP_INITIAL_SHAPE", "Sweep Initial Shapes", 25),
             PhaseKind("SWEEP_TYPE_OBJECT", "Sweep Type Objects", 26),
             PhaseKind("SWEEP_BREAKPOINT", "Sweep Breakpoints", 27),
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2606,16 +2606,18 @@ GCMarker::stackContainsCrossZonePointerT
         Zone* sourceZone = source->zone();
         if (sourceZone == targetZone)
             continue;
 
         // The private slot of proxy objects might contain a cross-compartment
         // pointer.
         if (source->is<ProxyObject>()) {
             Value value = source->as<ProxyObject>().private_();
+            MOZ_ASSERT_IF(!IsCrossCompartmentWrapper(source),
+                          IsObjectValueInCompartment(value, source->compartment()));
             if (value.isObject() && &value.toObject() == target)
                 return sourceZone;
         }
 
         if (Debugger::isDebuggerCrossCompartmentEdge(source, target))
             return sourceZone;
     }
 
--- a/js/src/jit-test/tests/wasm/basic.js
+++ b/js/src/jit-test/tests/wasm/basic.js
@@ -126,24 +126,27 @@ wasmEvalText('(module (import "a" "" (re
 wasmEvalText('(module (import "a" "" (result f64)))', {a:{"":()=>{}}});
 wasmEvalText('(module (import $foo "a" "" (result f64)))', {a:{"":()=>{}}});
 
 // ----------------------------------------------------------------------------
 // memory
 
 wasmValidateText('(module (memory 0))');
 wasmValidateText('(module (memory 1))');
-wasmFailValidateText('(module (memory 65536))', /initial memory size too big/);
+wasmValidateText('(module (memory 16384))');
+wasmFailValidateText('(module (memory 16385))', /initial memory size too big/);
+
+wasmEvalText('(module (memory 0 65536))')
+wasmFailValidateText('(module (memory 0 65537))', /maximum memory size too big/);
 
 // May OOM, but must not crash:
 try {
-    wasmEvalText('(module (memory 65535))');
+    wasmEvalText('(module (memory 16384))');
 } catch (e) {
-    assertEq(String(e).indexOf("out of memory") != -1 ||
-             String(e).indexOf("memory size too big") != -1, true);
+    assertEq(String(e).indexOf("out of memory") !== -1, true);
 }
 
 var buf = wasmEvalText('(module (memory 1) (export "memory" memory))').exports.memory.buffer;
 assertEq(buf instanceof ArrayBuffer, true);
 assertEq(buf.byteLength, 65536);
 
 var obj = wasmEvalText('(module (memory 1) (func (result i32) (i32.const 42)) (func (nop)) (export "memory" memory) (export "b" 0) (export "c" 1))').exports;
 assertEq(obj.memory.buffer instanceof ArrayBuffer, true);
--- a/js/src/jit-test/tests/wasm/import-export.js
+++ b/js/src/jit-test/tests/wasm/import-export.js
@@ -14,18 +14,37 @@ const mem3Page = new Memory({initial:3})
 const mem3PageMax3 = new Memory({initial:3, maximum: 3});
 const mem4Page = new Memory({initial:4});
 const mem4PageMax4 = new Memory({initial:4, maximum: 4});
 const tab1Elem = new Table({initial:1, element:"anyfunc"});
 const tab2Elem = new Table({initial:2, element:"anyfunc"});
 const tab3Elem = new Table({initial:3, element:"anyfunc"});
 const tab4Elem = new Table({initial:4, element:"anyfunc"});
 
+// Memory size consistency and internal limits.
 assertErrorMessage(() => new Memory({initial:2, maximum:1}), RangeError, /bad Memory maximum size/);
 
+try {
+    new Memory({initial:16384});
+} catch(e) {
+    assertEq(String(e).indexOf("out of memory") !== -1, true);
+}
+
+assertErrorMessage(() => new Memory({initial: 16385}), RangeError, /bad Memory initial size/);
+
+new Memory({initial: 0, maximum: 65536});
+assertErrorMessage(() => new Memory({initial: 0, maximum: 65537}), RangeError, /bad Memory maximum size/);
+
+// Table size consistency and internal limits.
+assertErrorMessage(() => new Table({initial:2, maximum:1, element:"anyfunc"}), RangeError, /bad Table maximum size/);
+new Table({ initial: 10000000, element:"anyfunc" });
+assertErrorMessage(() => new Table({initial:10000001, element:"anyfunc"}), RangeError, /bad Table initial size/);
+new Table({ initial: 0, maximum: 2**32 - 1, element:"anyfunc" });
+assertErrorMessage(() => new Table({initial:0, maximum: 2**32, element:"anyfunc"}), RangeError, /bad Table maximum size/);
+
 const m1 = new Module(wasmTextToBinary('(module (import "foo" "bar") (import "baz" "quux"))'));
 assertErrorMessage(() => new Instance(m1), TypeError, /second argument must be an object/);
 assertErrorMessage(() => new Instance(m1, {foo:null}), TypeError, /import object field 'foo' is not an Object/);
 assertErrorMessage(() => new Instance(m1, {foo:{bar:{}}}), LinkError, /import object field 'bar' is not a Function/);
 assertErrorMessage(() => new Instance(m1, {foo:{bar:()=>{}}, baz:null}), TypeError, /import object field 'baz' is not an Object/);
 assertErrorMessage(() => new Instance(m1, {foo:{bar:()=>{}}, baz:{}}), LinkError, /import object field 'quux' is not a Function/);
 assertEq(new Instance(m1, {foo:{bar:()=>{}}, baz:{quux:()=>{}}}) instanceof Instance, true);
 
--- a/js/src/jit-test/tests/wasm/memory.js
+++ b/js/src/jit-test/tests/wasm/memory.js
@@ -269,20 +269,16 @@ for (var foldOffsets = 0; foldOffsets <=
     wasmFailValidateText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "f64"));
 
     wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f32"));
     wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "f32"));
 
     wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "i32"));
     wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "i32"));
 
-    wasmEvalText('(module (memory 0 65535))')
-    wasmEvalText('(module (memory 0 65536))')
-    wasmFailValidateText('(module (memory 0 65537))', /maximum memory size too big/);
-
     // Test high charge of registers
     function testRegisters() {
         assertEq(wasmEvalText(
             `(module
               (memory 1)
               (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
               (data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
               (func (param i32) (local i32 i32 i32 i32 f32 f64) (result i32)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/timeout/interrupt-several-instances.js
@@ -0,0 +1,23 @@
+// |jit-test| exitstatus: 6;
+
+// Don't include wasm.js in timeout tests: when wasm isn't supported, it will
+// quit(0) which will cause the test to fail.
+if (!wasmIsSupported())
+    quit(6);
+
+load(libdir + "asm.js");
+
+var code = `
+    var out = ffi.out;
+    function f() {
+        out();
+    }
+    return f;
+`;
+
+var ffi = {};
+ffi.out = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func (export "f") (loop $top (br $top))))'))).exports.f;
+
+timeout(1);
+asmLink(asmCompile('glob', 'ffi', USE_ASM + code), this, ffi)();
+assertEq(true, false);
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -221,23 +221,16 @@ js::TraceWellKnownSymbols(JSTracer* trc)
         return;
 
     if (WellKnownSymbols* wks = rt->wellKnownSymbols) {
         for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++)
             TraceProcessGlobalRoot(trc, wks->get(i).get(), "well_known_symbol");
     }
 }
 
-void
-JSRuntime::sweepAtoms()
-{
-    if (atoms_)
-        atoms_->sweep();
-}
-
 bool
 JSRuntime::transformToPermanentAtoms(JSContext* cx)
 {
     MOZ_ASSERT(!parentRuntime);
 
     // All static strings were created as permanent atoms, now move the contents
     // of the atoms table into permanentAtoms and mark each as permanent.
 
@@ -347,18 +340,40 @@ AtomizeAndCopyChars(JSContext* cx, const
 
     // Validate the length before taking the exclusive access lock, as throwing
     // an exception here may reenter this code.
     if (MOZ_UNLIKELY(!JSString::validateLength(cx, length)))
         return nullptr;
 
     AutoLockForExclusiveAccess lock(cx);
 
-    AtomSet& atoms = cx->atoms(lock);
-    AtomSet::AddPtr p = atoms.lookupForAdd(lookup);
+    JSRuntime* rt = cx->runtime();
+    AtomSet& atoms = rt->atoms(lock);
+    AtomSet* atomsAddedWhileSweeping = rt->atomsAddedWhileSweeping();
+    AtomSet::AddPtr p;
+
+    if (!atomsAddedWhileSweeping) {
+        p = atoms.lookupForAdd(lookup);
+    } else {
+        // We're currently sweeping the main atoms table and all new atoms will
+        // be added to a secondary table. Check this first.
+        MOZ_ASSERT(rt->atomsZone(lock)->isGCSweeping());
+        p = atomsAddedWhileSweeping->lookupForAdd(lookup);
+
+        // If that fails check the main table but check if any atom found there
+        // is dead.
+        if (!p) {
+            if (AtomSet::AddPtr p2 = atoms.lookupForAdd(lookup)) {
+                JSAtom* atom = p2->asPtr(cx);
+                if (!IsAboutToBeFinalizedUnbarriered(&atom))
+                    p = p2;
+            }
+        }
+    }
+
     if (p) {
         JSAtom* atom = p->asPtr(cx);
         p->setPinned(bool(pin));
         cx->atomMarking().inlinedMarkAtom(cx, atom);
         if (zonePtr)
             mozilla::Unused << zone->atomCache().add(*zonePtr, AtomStateEntry(atom, false));
         return atom;
     }
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -4906,30 +4906,32 @@ class SweepWeakCacheTask : public GCPara
     {}
 
     void run() override {
         cache.sweep();
     }
 };
 
 static void
-SweepAtoms(JSRuntime* runtime)
+UpdateAtomsBitmap(JSRuntime* runtime)
 {
     DenseBitmap marked;
     if (runtime->gc.atomMarking.computeBitmapFromChunkMarkBits(runtime, marked)) {
         for (GCZonesIter zone(runtime); !zone.done(); zone.next())
             runtime->gc.atomMarking.updateZoneBitmap(zone, marked);
     } else {
         // Ignore OOM in computeBitmapFromChunkMarkBits. The updateZoneBitmap
         // call can only remove atoms from the zone bitmap, so it is
         // conservative to just not call it.
     }
 
     runtime->gc.atomMarking.updateChunkMarkBits(runtime);
-    runtime->sweepAtoms();
+
+    // For convenience sweep these tables non-incrementally as part of bitmap
+    // sweeping; they are likely to be much smaller than the main atoms table.
     runtime->unsafeSymbolRegistry().sweep();
     for (CompartmentsIter comp(runtime, SkipAtoms); !comp.done(); comp.next())
         comp->sweepVarNames();
 }
 
 static void
 SweepCCWrappers(JSRuntime* runtime)
 {
@@ -5224,19 +5226,19 @@ GCRuntime::beginSweepingSweepGroup()
         callFinalizeCallbacks(&fop, JSFINALIZE_GROUP_START);
     }
 
     sweepDebuggerOnMainThread(&fop);
 
     {
         AutoLockHelperThreadState lock;
 
-        Maybe<AutoRunParallelTask> sweepAtoms;
+        Maybe<AutoRunParallelTask> updateAtomsBitmap;
         if (sweepingAtoms)
-            sweepAtoms.emplace(rt, SweepAtoms, PhaseKind::SWEEP_ATOMS, lock);
+            updateAtomsBitmap.emplace(rt, UpdateAtomsBitmap, PhaseKind::UPDATE_ATOMS_BITMAP, lock);
 
         AutoPhase ap(stats(), PhaseKind::SWEEP_COMPARTMENTS);
 
         AutoRunParallelTask sweepCCWrappers(rt, SweepCCWrappers, PhaseKind::SWEEP_CC_WRAPPER, lock);
         AutoRunParallelTask sweepObjectGroups(rt, SweepObjectGroups, PhaseKind::SWEEP_TYPE_OBJECT, lock);
         AutoRunParallelTask sweepRegExps(rt, SweepRegExps, PhaseKind::SWEEP_REGEXP, lock);
         AutoRunParallelTask sweepMisc(rt, SweepMisc, PhaseKind::SWEEP_MISC, lock);
         AutoRunParallelTask sweepCompTasks(rt, SweepCompressionTasks, PhaseKind::SWEEP_COMPRESSION, lock);
@@ -5469,16 +5471,74 @@ GCRuntime::mergeSweptObjectArenas(GCRunt
     // available for allocation.
 
     MOZ_ASSERT(kind == AllocKind::LIMIT);
     zone->arenas.mergeForegroundSweptObjectArenas();
     return Finished;
 }
 
 /* static */ IncrementalProgress
+GCRuntime::sweepAtomsTable(GCRuntime* gc, FreeOp* fop, Zone* zone, SliceBudget& budget,
+                           AllocKind kind)
+{
+    if (!zone->isAtomsZone())
+        return Finished;
+
+    return gc->sweepAtomsTable(budget);
+}
+
+IncrementalProgress
+GCRuntime::sweepAtomsTable(SliceBudget& budget)
+{
+    gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP_ATOMS_TABLE);
+
+    auto& maybeAtoms = maybeAtomsToSweep.ref();
+    MOZ_ASSERT_IF(maybeAtoms.isSome(), !maybeAtoms.ref().empty());
+
+    AtomSet* atomsTable = rt->atomsForSweeping();
+    if (!atomsTable)
+        return Finished;
+
+    if (maybeAtoms.isNothing()) {
+        // Create a secondary table to hold new atoms added while we're sweeping
+        // the main table incrementally.
+        if (!rt->createAtomsAddedWhileSweepingTable()) {
+            atomsTable->sweep();
+            return Finished;
+        }
+
+        // Initialize remaining atoms to sweep.
+        maybeAtoms.emplace(*atomsTable);
+    }
+
+    // Sweep the table incrementally until we run out of work or budget.
+    auto& atomsToSweep = *maybeAtoms;
+    while (!atomsToSweep.empty()) {
+        if (budget.isOverBudget())
+            return NotFinished;
+
+        JSAtom* atom = atomsToSweep.front().asPtrUnbarriered();
+        if (IsAboutToBeFinalizedUnbarriered(&atom))
+            atomsToSweep.removeFront();
+        atomsToSweep.popFront();
+    }
+
+    // Add any new atoms from the secondary table.
+    AutoEnterOOMUnsafeRegion oomUnsafe;
+    for (auto r = rt->atomsAddedWhileSweeping()->all(); !r.empty(); r.popFront()) {
+        if (!atomsTable->putNew(AtomHasher::Lookup(r.front().asPtrUnbarriered()), r.front()))
+            oomUnsafe.crash("Adding atom from secondary table after sweep");
+    }
+    rt->destroyAtomsAddedWhileSweepingTable();
+
+    maybeAtoms.reset();
+    return Finished;
+}
+
+/* static */ IncrementalProgress
 GCRuntime::finalizeAllocKind(GCRuntime* gc, FreeOp* fop, Zone* zone, SliceBudget& budget,
                              AllocKind kind)
 {
     // Set the number of things per arena for this AllocKind.
     size_t thingsPerArena = Arena::thingsPerArena(kind);
     auto& sweepList = gc->incrementalSweepList.ref();
     sweepList.setThingsPerArena(thingsPerArena);
 
@@ -5527,16 +5587,17 @@ AddSweepAction(bool* ok, SweepAction::Fu
 }
 
 /* static */ bool
 GCRuntime::initializeSweepActions()
 {
     bool ok = true;
 
     AddSweepPhase(&ok);
+    AddSweepAction(&ok, GCRuntime::sweepAtomsTable);
     for (auto kind : ForegroundObjectFinalizePhase.kinds)
         AddSweepAction(&ok, GCRuntime::finalizeAllocKind, kind);
 
     AddSweepPhase(&ok);
     AddSweepAction(&ok, GCRuntime::sweepTypeInformation);
     AddSweepAction(&ok, GCRuntime::mergeSweptObjectArenas);
 
     for (const auto& finalizePhase : IncrementalFinalizePhases) {
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -705,16 +705,17 @@ ArrayBufferObject::BufferContents::wasmB
 #define ROUND_UP(v, a) ((v) % (a) == 0 ? (v) : v + a - ((v) % (a)))
 
 /* static */ ArrayBufferObject*
 ArrayBufferObject::createForWasm(JSContext* cx, uint32_t initialSize,
                                  const Maybe<uint32_t>& maybeMaxSize)
 {
     MOZ_ASSERT(initialSize % wasm::PageSize == 0);
     MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
+    MOZ_RELEASE_ASSERT((initialSize / wasm::PageSize) <= wasm::MaxMemoryInitialPages);
 
     // Prevent applications specifying a large max (like UINT32_MAX) from
     // unintentially OOMing the browser on 32-bit: they just want "a lot of
     // memory". Maintain the invariant that initialSize <= maxSize.
     Maybe<uint32_t> maxSize = maybeMaxSize;
     if (sizeof(void*) == 4 && maybeMaxSize) {
         static const uint32_t OneGiB = 1 << 30;
         uint32_t clamp = Max(OneGiB, initialSize);
--- a/js/src/vm/ProxyObject.cpp
+++ b/js/src/vm/ProxyObject.cpp
@@ -87,17 +87,20 @@ ProxyObject::New(JSContext* cx, const Ba
     JS_TRY_VAR_OR_RETURN_NULL(cx, proxy, create(cx, clasp, proto, allocKind, newKind));
 
     proxy->setInlineValueArray();
 
     detail::ProxyValueArray* values = detail::GetProxyDataLayout(proxy)->values();
     values->init(proxy->numReservedSlots());
 
     proxy->data.handler = handler;
-    proxy->setCrossCompartmentPrivate(priv);
+    if (IsCrossCompartmentWrapper(proxy))
+        proxy->setCrossCompartmentPrivate(priv);
+    else
+        proxy->setSameCompartmentPrivate(priv);
 
     /* Don't track types of properties of non-DOM and non-singleton proxies. */
     if (newKind != SingletonObject && !clasp->isDOMClass())
         MarkObjectGroupUnknownProperties(cx, proxy->group());
 
     return proxy;
 }
 
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -151,16 +151,17 @@ JSRuntime::JSRuntime(JSRuntime* parentRu
 #if !EXPOSE_INTL_API
     thousandsSeparator(nullptr),
     decimalSeparator(nullptr),
     numGrouping(nullptr),
 #endif
     beingDestroyed_(false),
     allowContentJS_(true),
     atoms_(nullptr),
+    atomsAddedWhileSweeping_(nullptr),
     atomsCompartment_(nullptr),
     staticStrings(nullptr),
     commonNames(nullptr),
     permanentAtoms(nullptr),
     wellKnownSymbols(nullptr),
     jitSupportsFloatingPoint(false),
     jitSupportsUnalignedAccesses(false),
     jitSupportsSimd(false),
@@ -838,16 +839,44 @@ JSRuntime::onOutOfMemoryCanGC(AllocFunct
 bool
 JSRuntime::activeGCInAtomsZone()
 {
     Zone* zone = atomsCompartment_->zone();
     return (zone->needsIncrementalBarrier() && !gc.isVerifyPreBarriersEnabled()) ||
            zone->wasGCStarted();
 }
 
+bool
+JSRuntime::createAtomsAddedWhileSweepingTable()
+{
+    MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
+    MOZ_ASSERT(!atomsAddedWhileSweeping_);
+
+    atomsAddedWhileSweeping_ = js_new<AtomSet>();
+    if (!atomsAddedWhileSweeping_)
+        return false;
+
+    if (!atomsAddedWhileSweeping_->init()) {
+        destroyAtomsAddedWhileSweepingTable();
+        return false;
+    }
+
+    return true;
+}
+
+void
+JSRuntime::destroyAtomsAddedWhileSweepingTable()
+{
+    MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
+    MOZ_ASSERT(atomsAddedWhileSweeping_);
+
+    js_delete(atomsAddedWhileSweeping_.ref());
+    atomsAddedWhileSweeping_ = nullptr;
+}
+
 void
 JSRuntime::setUsedByHelperThread(Zone* zone)
 {
     MOZ_ASSERT(!zone->group()->usedByHelperThread);
     MOZ_ASSERT(!zone->wasGCStarted());
     zone->group()->usedByHelperThread = true;
     numHelperThreadZones++;
 }
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -810,50 +810,69 @@ struct JSRuntime : public js::MallocProv
     friend class js::AutoAssertNoContentJS;
 
   private:
     // Set of all atoms other than those in permanentAtoms and staticStrings.
     // Reading or writing this set requires the calling thread to use
     // AutoLockForExclusiveAccess.
     js::ExclusiveAccessLockOrGCTaskData<js::AtomSet*> atoms_;
 
+    // Set of all atoms added while the main atoms table is being swept.
+    js::ExclusiveAccessLockData<js::AtomSet*> atomsAddedWhileSweeping_;
+
     // Compartment and associated zone containing all atoms in the runtime, as
     // well as runtime wide IonCode stubs. Modifying the contents of this
     // compartment requires the calling thread to use AutoLockForExclusiveAccess.
     js::WriteOnceData<JSCompartment*> atomsCompartment_;
 
     // Set of all live symbols produced by Symbol.for(). All such symbols are
     // allocated in the atomsCompartment. Reading or writing the symbol
     // registry requires the calling thread to use AutoLockForExclusiveAccess.
     js::ExclusiveAccessLockOrGCTaskData<js::SymbolRegistry> symbolRegistry_;
 
   public:
     bool initializeAtoms(JSContext* cx);
     void finishAtoms();
     bool atomsAreFinished() const { return !atoms_; }
 
-    void sweepAtoms();
+    js::AtomSet* atomsForSweeping() {
+        MOZ_ASSERT(JS::CurrentThreadIsHeapCollecting());
+        return atoms_;
+    }
 
     js::AtomSet& atoms(js::AutoLockForExclusiveAccess& lock) {
+        MOZ_ASSERT(atoms_);
         return *atoms_;
     }
     js::AtomSet& unsafeAtoms() {
+        MOZ_ASSERT(atoms_);
         return *atoms_;
     }
+
+    bool createAtomsAddedWhileSweepingTable();
+    void destroyAtomsAddedWhileSweepingTable();
+    js::AtomSet* atomsAddedWhileSweeping() {
+        return atomsAddedWhileSweeping_;
+    }
+
     JSCompartment* atomsCompartment(js::AutoLockForExclusiveAccess& lock) {
         return atomsCompartment_;
     }
     JSCompartment* unsafeAtomsCompartment() {
         return atomsCompartment_;
     }
 
     bool isAtomsCompartment(JSCompartment* comp) {
         return comp == atomsCompartment_;
     }
 
+    const JS::Zone* atomsZone(js::AutoLockForExclusiveAccess& lock) const {
+        return gc.atomsZone;
+    }
+
     // The atoms compartment is the only one in its zone.
     bool isAtomsZone(const JS::Zone* zone) const {
         return zone == gc.atomsZone;
     }
 
     bool activeGCInAtomsZone();
 
     js::SymbolRegistry& symbolRegistry(js::AutoLockForExclusiveAccess& lock) {
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -21,16 +21,17 @@
 #include "jit/JitFrameIterator-inl.h"
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/Probes-inl.h"
 
 using namespace js;
 
 using mozilla::ArrayLength;
+using mozilla::DebugOnly;
 using mozilla::Maybe;
 using mozilla::PodCopy;
 
 /*****************************************************************************/
 
 void
 InterpreterFrame::initExecuteFrame(JSContext* cx, HandleScript script,
                                    AbstractFramePtr evalInFramePrev,
@@ -1696,17 +1697,30 @@ WasmActivation::finishInterrupt()
 
     cx_->runtime()->setWasmResumePC(nullptr);
     exitFP_ = nullptr;
 }
 
 bool
 WasmActivation::interrupted() const
 {
-    return !!cx_->runtime()->wasmResumePC();
+    void* pc = cx_->runtime()->wasmResumePC();
+    if (!pc)
+        return false;
+
+    Activation* act = cx_->activation();
+    while (act && !act->isWasm())
+        act = act->prev();
+
+    if (act->asWasm() != this)
+        return false;
+
+    DebugOnly<wasm::Frame*> fp = act->asWasm()->exitFP();
+    MOZ_ASSERT(fp && fp->instance()->code().containsFunctionPC(pc));
+    return true;
 }
 
 void*
 WasmActivation::resumePC() const
 {
     MOZ_ASSERT(interrupted());
     return cx_->runtime()->wasmResumePC();
 }
--- a/js/src/wasm/WasmFrameIterator.cpp
+++ b/js/src/wasm/WasmFrameIterator.cpp
@@ -69,16 +69,17 @@ FrameIterator::FrameIterator(WasmActivat
     // itself and so we do not want to skip it. Instead, we can recover the
     // Code and CodeRange from the WasmActivation, which are set when control
     // flow was interrupted. There is no CallSite (b/c the interrupt was async),
     // but this is fine because CallSite is only used for line number for which
     // we can use the beginning of the function from the CodeRange instead.
 
     code_ = activation_->compartment()->wasm.lookupCode(activation->resumePC());
     MOZ_ASSERT(code_);
+    MOZ_ASSERT(&fp_->tls->instance->code() == code_);
 
     codeRange_ = code_->lookupRange(activation->resumePC());
     MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
 
     MOZ_ASSERT(!done());
 }
 
 bool
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -418,55 +418,54 @@ static bool
 ToNonWrappingUint32(JSContext* cx, HandleValue v, uint32_t max, const char* kind, const char* noun,
                     uint32_t* u32)
 {
     double dbl;
     if (!ToInteger(cx, v, &dbl))
         return false;
 
     if (dbl < 0 || dbl > max) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32,
-                                  kind, noun);
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32, kind, noun);
         return false;
     }
 
     *u32 = uint32_t(dbl);
     MOZ_ASSERT(double(*u32) == dbl);
     return true;
 }
 
 static bool
-GetLimits(JSContext* cx, HandleObject obj, uint32_t max, const char* kind,
-          Limits* limits)
+GetLimits(JSContext* cx, HandleObject obj, uint32_t maxInitial, uint32_t maxMaximum,
+          const char* kind, Limits* limits)
 {
     JSAtom* initialAtom = Atomize(cx, "initial", strlen("initial"));
     if (!initialAtom)
         return false;
     RootedId initialId(cx, AtomToId(initialAtom));
 
     RootedValue initialVal(cx);
     if (!GetProperty(cx, obj, obj, initialId, &initialVal))
         return false;
 
-    if (!ToNonWrappingUint32(cx, initialVal, max, kind, "initial size", &limits->initial))
+    if (!ToNonWrappingUint32(cx, initialVal, maxInitial, kind, "initial size", &limits->initial))
         return false;
 
     JSAtom* maximumAtom = Atomize(cx, "maximum", strlen("maximum"));
     if (!maximumAtom)
         return false;
     RootedId maximumId(cx, AtomToId(maximumAtom));
 
     bool found;
     if (HasProperty(cx, obj, maximumId, &found) && found) {
         RootedValue maxVal(cx);
         if (!GetProperty(cx, obj, obj, maximumId, &maxVal))
             return false;
 
         limits->maximum.emplace();
-        if (!ToNonWrappingUint32(cx, maxVal, max, kind, "maximum size", limits->maximum.ptr()))
+        if (!ToNonWrappingUint32(cx, maxVal, maxMaximum, kind, "maximum size", limits->maximum.ptr()))
             return false;
 
         if (limits->initial > *limits->maximum) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32,
                                       kind, "maximum size");
             return false;
         }
     }
@@ -1338,17 +1337,17 @@ WasmMemoryObject::construct(JSContext* c
 
     if (!args.get(0).isObject()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_DESC_ARG, "memory");
         return false;
     }
 
     RootedObject obj(cx, &args[0].toObject());
     Limits limits;
-    if (!GetLimits(cx, obj, UINT32_MAX / PageSize, "Memory", &limits))
+    if (!GetLimits(cx, obj, MaxMemoryInitialPages, MaxMemoryMaximumPages, "Memory", &limits))
         return false;
 
     limits.initial *= PageSize;
     if (limits.maximum)
         limits.maximum = Some(*limits.maximum * PageSize);
 
     RootedArrayBufferObject buffer(cx,
         ArrayBufferObject::createForWasm(cx, limits.initial, limits.maximum));
@@ -1649,17 +1648,17 @@ WasmTableObject::construct(JSContext* cx
         return false;
 
     if (!StringEqualsAscii(elementStr, "anyfunc")) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_ELEMENT);
         return false;
     }
 
     Limits limits;
-    if (!GetLimits(cx, obj, UINT32_MAX, "Table", &limits))
+    if (!GetLimits(cx, obj, MaxTableInitialLength, UINT32_MAX, "Table", &limits))
         return false;
 
     RootedWasmTableObject table(cx, WasmTableObject::create(cx, limits));
     if (!table)
         return false;
 
     args.rval().setObject(*table);
     return true;
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -166,17 +166,17 @@ fuzzy(50,500) fuzzy-if(skiaContent,51,32
 == attachment-local-clipping-image-1.html attachment-local-clipping-image-1-ref.html
 == attachment-local-clipping-image-2.html attachment-local-clipping-image-1-ref.html  # Same ref as the previous test.
 == attachment-local-clipping-image-3.html attachment-local-clipping-image-3-ref.html
 # The next three tests are fuzzy due to bug 1128229.
 fuzzy(16,69) fuzzy-if(skiaContent,95,2200) == attachment-local-clipping-image-4.html attachment-local-clipping-image-4-ref.html
 fuzzy(16,69) fuzzy-if(skiaContent,95,2200) == attachment-local-clipping-image-5.html attachment-local-clipping-image-4-ref.html
 fuzzy(80,500) fuzzy-if(skiaContent,100,908) fails-if(webrender) == attachment-local-clipping-image-6.html attachment-local-clipping-image-6-ref.html
 
-fuzzy-if(skiaContent,1,8) == background-multiple-with-border-radius.html background-multiple-with-border-radius-ref.html
+fuzzy-if(skiaContent,1,8) fuzzy-if(webrender,1,84) == background-multiple-with-border-radius.html background-multiple-with-border-radius-ref.html
 == background-repeat-large-area.html background-repeat-large-area-ref.html
 
 fuzzy(30,474) fuzzy-if(skiaContent,31,474) == background-tiling-zoom-1.html background-tiling-zoom-1-ref.html
 
 skip-if(!cocoaWidget) == background-repeat-resampling.html background-repeat-resampling-ref.html
 
 fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) == background-clip-text-1a.html background-clip-text-1-ref.html
 fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) == background-clip-text-1b.html background-clip-text-1-ref.html
--- a/layout/reftests/border-image/reftest.list
+++ b/layout/reftests/border-image/reftest.list
@@ -82,11 +82,11 @@ fuzzy(1,1054) fails-if(OSX) fuzzy-if(ski
 
 # border-image-source (-moz-)element
 fuzzy(125,5808) == border-image-element.html border-image-element-ref.html
 
 # svg-as-border-image
 == svg-as-border-image-1a.html svg-as-border-image-1-ref.html
 == svg-as-border-image-1b.html svg-as-border-image-1-ref.html
 == svg-as-border-image-1c.html svg-as-border-image-1-ref.html
-== svg-as-border-image-2.html svg-as-border-image-2-ref.html
+fails-if(webrender) == svg-as-border-image-2.html svg-as-border-image-2-ref.html # see bug 1151016. The svg viewport size may be wrong
 == svg-as-border-image-3.html svg-as-border-image-3-ref.html
 == svg-as-border-image-4.html svg-as-border-image-4-ref.html
--- a/layout/reftests/border-radius/reftest.list
+++ b/layout/reftests/border-radius/reftest.list
@@ -18,17 +18,17 @@
 # ridge/groove borders
 
 # percent units
 == percent-1.html percent-1-ref.html
 fuzzy-if(skiaContent,1,342) == percent-2.html percent-2-ref.html
 fuzzy-if(skiaContent,1,343) == percent-3.html percent-3-ref.html
 
 # more serious tests, using SVG reference
-fuzzy-if(skiaContent,17,58) == border-circle-2.html border-circle-2-ref.xhtml
+fuzzy-if(skiaContent,17,58) fuzzy-if(webrender,16,59) == border-circle-2.html border-circle-2-ref.xhtml
 fuzzy-if(gtkWidget,14,280) fuzzy-if(cocoaWidget,4,582) fuzzy-if(Android,36,264) fuzzy-if(d2d,51,323) fuzzy-if(winWidget&&!d2d,16,377) fuzzy-if(skiaContent,63,398) == curved-stripe-border.html curved-stripe-border-ref.svg # bug 459945
 
 # Corners
 fuzzy-if(skiaContent,17,47) == corner-1.html corner-1-ref.svg # bottom corners different radius than top corners
 fuzzy-if(gtkWidget,23,5) fuzzy-if(winWidget&&!d2d,23,5) fuzzy-if(d2d,32,8) fuzzy-if(Android,10,8) fuzzy-if(skiaContent,18,49) == corner-2.html corner-2-ref.svg # right corners different radius than left corners; see bug 500804
 fuzzy-if(gtkWidget,3,10) fuzzy-if(winWidget&&!d2d,3,10) fuzzy-if(d2d,15,32) fuzzy-if(Android,3,15) fuzzy-if(skiaContent,18,90) == corner-3.html corner-3-ref.svg
 fuzzy-if(skiaContent,12,83) == corner-4.html corner-4-ref.svg
 
@@ -48,17 +48,17 @@ fuzzy-if(true,1,20) fuzzy-if(d2d,64,196)
 fuzzy-if(Android,5,54) fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) fuzzy-if(skiaContent,1,172) == clipping-4-image.html clipping-4-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,10) fuzzy-if(skiaContent,1,77) == clipping-4-overflow-hidden.html clipping-4-ref.html
 == clipping-5-canvas.html clipping-5-refc.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-image.html clipping-5-refi.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(skiaContent,1,77) == clipping-5-overflow-hidden.html clipping-5-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(Android,5,21) fuzzy-if(skiaContent,1,97) == clipping-5-refi.html clipping-5-ref.html
 fuzzy-if(true,1,7) fuzzy-if(d2d,48,94) fuzzy-if(cocoaWidget,1,99) fuzzy-if(Android,99,115) fuzzy-if(skiaContent,1,77) == clipping-5-refc.html clipping-5-ref.html # bug 732535
 fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,469) fuzzy-if(skiaContent,7,58) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical
-fuzzy-if(true,2,29) fuzzy-if(d2d,46,50) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,28,96) fails-if(webrender) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures).
+fuzzy-if(true,2,29) fuzzy-if(d2d,46,50) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,28,96) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures).
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html
 fuzzy-if(cocoaWidget,1,4) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html
 == intersecting-clipping-1-image.html intersecting-clipping-1-refi.html
 == intersecting-clipping-1-overflow-hidden.html intersecting-clipping-1-ref.html
 fuzzy-if(Android,5,105) fuzzy-if(d2d,1,20) fuzzy-if(skiaContent,1,300) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html
 fuzzy-if(true,1,33) fuzzy-if(d2d,48,350) fuzzy-if(cocoaWidget,1,332) fuzzy-if(Android,124,440) fuzzy-if(skiaContent,1,135) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # bug 732535
 
 # Inheritance
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1592,17 +1592,17 @@ fails-if(styloVsGecko||stylo) == 589615-
 == 589672-1.html 589672-1-ref.html
 != 589682-1.html 589682-1-notref.html
 pref(dom.meta-viewport.enabled,true) skip-if(Android) == 593243-1.html 593243-1-ref.html # bug 593168
 pref(dom.meta-viewport.enabled,true) skip-if(Android) == 593243-2.html 593243-2-ref.html # bug 593168
 == 593544-1.html 593544-1-ref.html
 random-if(Android) == 594333-1.html 594333-1-ref.html
 == 594624-1.html 594624-1-ref.html
 == 594737-1.html 594737-1-ref.html
-fuzzy-if(skiaContent,1,80) == 597721-1.html 597721-1-ref.html
+fuzzy-if(skiaContent,1,80) fuzzy-if(webrender,1,100) == 597721-1.html 597721-1-ref.html
 random-if(winWidget) fuzzy-if(Android,38,539) fuzzy-if(skiaContent,1,480) needs-focus skip-if(styloVsGecko) == 598726-1.html 598726-1-ref.html # Fails on Windows, bug 782196
 == 599113-1.html 599113-1-ref.html
 fails-if(!haveTestPlugin) HTTP == 599476.html 599476-ref.html
 == 599882-1a.html 599882-1-ref.html
 == 599882-1b.html 599882-1-ref.html
 == 599882-2.html 599882-2-ref.html
 == 600045-1.html 600045-1-ref.html
 fails-if(styloVsGecko) == 600803-1.html 600803-1-ref.html
@@ -1658,17 +1658,17 @@ fuzzy-if(skiaContent,1,500) == 634232-1.
 fuzzy-if(skiaContent,3,120000) == 635302-1.html 635302-1-ref.html
 fuzzy(1,68) fuzzy-if(gtkWidget,1,70) fails-if(Android) fuzzy-if(skiaContent&&!Android,1,300) == 635373-1.html 635373-1-ref.html
 random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,118) fuzzy-if(skiaContent&&!Android,2,550) == 635373-2.html 635373-2-ref.html
 random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,116) fuzzy-if(skiaContent&&!Android,2,650) == 635373-3.html 635373-3-ref.html
 HTTP(..) == 635639-1.html 635639-1-ref.html
 HTTP(..) == 635639-2.html 635639-2-ref.html
 random == 637597-1.html 637597-1-ref.html # bug 637597 was never really fixed!
 fuzzy-if(Android,8,500) == 637852-1.html 637852-1-ref.html
-fuzzy-if(Android,8,500) fuzzy-if(skiaContent,2,1) == 637852-2.html 637852-2-ref.html
+fuzzy-if(Android,8,500) fuzzy-if(skiaContent,2,1) fuzzy-if(webrender,3,19) == 637852-2.html 637852-2-ref.html
 fuzzy-if(Android,8,500) == 637852-3.html 637852-3-ref.html
 == 641770-1.html 641770-1-ref.html
 == 641856-1.html 641856-1-ref.html
 fails-if(styloVsGecko||stylo) == 645491-1.html 645491-1-ref.html
 == 645647-1.html 645647-1-ref.html
 == 645647-2.html 645647-2-ref.html
 == 645768-1.html 645768-1-ref.html
 fails-if(layersGPUAccelerated&&cocoaWidget) fuzzy-if(!layersGPUAccelerated,41,260) fuzzy-if(skiaContent,57,11000) == 650228-1.html 650228-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
@@ -1978,18 +1978,18 @@ fuzzy(8,1900) == 1291528.html 1291528-re
 # should be same.  |fuzzy()| here allows the difference in border, but not
 # background color.
 fuzzy(255,1000) skip-if(!cocoaWidget) == 1294102-1.html 1294102-1-ref.html
 random-if(Android) fuzzy-if(skiaContent,15,50) == 1295466-1.xhtml 1295466-1-ref.xhtml #bug 982547
 fuzzy-if(Android,27,874) fuzzy-if(gtkWidget,14,29) == 1313772.xhtml 1313772-ref.xhtml # Bug 1128229
 fuzzy(2,320000) == 1315113-1.html 1315113-1-ref.html
 fuzzy(2,20000) == 1315113-2.html 1315113-2-ref.html
 == 1315632-1.html 1315632-1-ref.html
-fuzzy(2,40000) == 1316719-1a.html 1316719-1-ref.html
-fuzzy(2,40000) == 1316719-1b.html 1316719-1-ref.html
+fuzzy(2,40000) fuzzy-if(webrender,26,691) == 1316719-1a.html 1316719-1-ref.html
+fuzzy(2,40000) fuzzy-if(webrender,26,691) == 1316719-1b.html 1316719-1-ref.html
 fuzzy(2,40000) == 1316719-1c.html 1316719-1-ref.html
 pref(layers.advanced.background-color,1) skip-if(!webrender) fuzzy-if(webrender,27,700) == 1316719-1a.html 1316719-1-ref.html
 pref(layers.advanced.background-color,1) skip-if(!webrender) fuzzy-if(webrender,27,700) == 1316719-1b.html 1316719-1-ref.html
 pref(layers.advanced.background-color,1) skip-if(!webrender) fuzzy-if(webrender,27,700) == 1316719-1c.html 1316719-1-ref.html
 skip-if(Android) != 1318769-1.html 1318769-1-ref.html
 fails-if(styloVsGecko) == 1322512-1.html 1322512-1-ref.html
 == 1330051.svg 1330051-ref.svg
 == 1348481-1.html 1348481-ref.html
--- a/layout/reftests/invalidation/reftest.list
+++ b/layout/reftests/invalidation/reftest.list
@@ -56,17 +56,17 @@ fails-if(webrender) != paintedlayer-recy
 fails-if(webrender) != paintedlayer-recycling-5.html about:blank
 fails-if(webrender) != paintedlayer-recycling-6.html about:blank
 fails-if(webrender) != paintedlayer-recycling-7.html about:blank
 != masklayer-1.html about:blank
 != masklayer-2.html about:blank
 fails-if(webrender) != layer-splitting-1.html about:blank
 fails-if(webrender) != layer-splitting-2.html about:blank
 fails-if(webrender) != layer-splitting-3.html about:blank
-!= layer-splitting-4.html about:blank
+fails-if(webrender) != layer-splitting-4.html about:blank
 fails-if(webrender) != layer-splitting-5.html about:blank
 fails-if(webrender) != layer-splitting-6.html about:blank
 fails-if(webrender) != layer-splitting-7.html about:blank
 fuzzy-if(gtkWidget,2,4) fuzzy-if(asyncPan,2,3955) fuzzy-if(OSX,179,30) fuzzy-if(skiaContent,16,3230) == image-scrolling-zoom-1.html image-scrolling-zoom-1-ref.html
 != image-scrolling-zoom-1-ref.html image-scrolling-zoom-1-notref.html
 pref(layers.single-tile.enabled,false) fails-if(webrender) != fast-scrolling.html about:blank
 fails-if(webrender) == background-position-1.html background-position-1-ref.html
 == background-position-2a.html background-position-2-ref.html
--- a/layout/reftests/reftest-sanity/reftest.list
+++ b/layout/reftests/reftest-sanity/reftest.list
@@ -150,18 +150,18 @@ ref-pref(font.size.variable.x-western,24
 # reftest syntax: fuzzy(maxPixelDifference,maxNumberDifferingPixels)
 fuzzy(1,250000) == fuzzy.html fuzzy-ref.html
 fuzzy(1,250000) != too-fuzzy.html fuzzy-ref.html
 fuzzy-if(true,1,250000) == fuzzy.html fuzzy-ref.html
 fuzzy-if(false,2,1) == fuzzy-ref.html fuzzy-ref.html
 # When using 565 fuzzy.html and fuzzy-ref.html will compare as equal
 fails-if(!styloVsGecko) fuzzy-if(false,2,1) random-if(Android) == fuzzy.html fuzzy-ref.html
 
-# Test that reftest-no-paint fails correctly
-fails == reftest-no-paint.html reftest-no-paint-ref.html
+# Test that reftest-no-paint fails correctly. With WR enabled, it will generate color layers instead of updating color on the painted layer.
+fails skip-if(webrender) == reftest-no-paint.html reftest-no-paint-ref.html
 
 skip-if(!asyncPan||!browserIsRemote) == async-scroll-1a.html async-scroll-1-ref.html
 
 # Disable low-res painting for this test as it will cause more to
 # be drawn than we want.
 default-preferences pref(layers.low-precision-buffer,false)
 skip-if(!asyncPan||!browserIsRemote) != async-scroll-1b.html async-scroll-1-ref.html
 default-preferences
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -211,17 +211,17 @@ fuzzy-if(skiaContent,1,500) == filter-sc
 == filter-use-element-01.svg pass.svg
 fuzzy-if(skiaContent,1,800000) == filters-and-group-opacity-01.svg filters-and-group-opacity-01-ref.svg
 
 == foreignObject-01.svg pass.svg
 == foreignObject-02.svg foreignObject-02-ref.svg
 == foreignObject-ancestor-style-change-01.svg foreignObject-ancestor-style-change-01-ref.svg
 == foreignObject-change-transform-01.svg pass.svg
 == foreignObject-display-01.svg pass.svg
-== foreignObject-form-theme.svg foreignObject-form-theme-ref.html
+fuzzy-if(webrender,1,35) == foreignObject-form-theme.svg foreignObject-form-theme-ref.html
 == foreignObject-img-form-theme.html foreignObject-img-form-theme-ref.html
 == foreignObject-move-repaint-01.svg pass.svg
 == foreignObject-overflow-01.svg pass.svg
 == foreignObject-start-hidden-01.svg pass.svg # followup from Bug 596765
 == foreignObject-start-hidden-02.svg pass.svg
 == foreignObject-style-change-01.svg pass.svg
 == foreignObject-dynamic-abspos-01.html foreignObject-dynamic-abspos-01-ref.html
 fuzzy-if(Android,18,600) == foreignObject-fixedpos-01.html foreignObject-dynamic-abspos-01-ref.html
--- a/layout/reftests/svg/svg-integration/clip-path/reftest.list
+++ b/layout/reftests/svg/svg-integration/clip-path/reftest.list
@@ -13,46 +13,46 @@ default-preferences pref(layout.css.clip
 == clip-path-polygon-007.html clip-path-stripes-001-ref.html
 == clip-path-polygon-008.html clip-path-stripes-002-ref.html
 == clip-path-polygon-009.html clip-path-square-002-ref.html
 == clip-path-polygon-010.html clip-path-stripes-001-ref.html
 == clip-path-polygon-011.html clip-path-stripes-001-ref.html
 == clip-path-polygon-012.html clip-path-stripes-001-ref.html
 fuzzy-if(skiaContent,1,20) == clip-path-polygon-013.html clip-path-stripes-003-ref.html
 
-== clip-path-circle-001.html clip-path-circle-001-ref.html
-== clip-path-circle-002.html clip-path-circle-001-ref.html
-== clip-path-circle-003.html clip-path-circle-001-ref.html
-== clip-path-circle-004.html clip-path-circle-001-ref.html
-== clip-path-circle-005.html clip-path-circle-002-ref.html
-== clip-path-circle-006.html clip-path-circle-001-ref.html
-== clip-path-circle-007.html clip-path-circle-002-ref.html
-== clip-path-circle-008.html clip-path-circle-002-ref.html
-== clip-path-circle-009.html clip-path-circle-003-ref.html
-== clip-path-circle-010.html clip-path-circle-004-ref.html
-== clip-path-circle-011.html clip-path-circle-005-ref.html
-== clip-path-circle-012.html clip-path-circle-006-ref.html
-== clip-path-circle-013.html clip-path-circle-002-ref.html
-== clip-path-circle-014.html clip-path-circle-007-ref.html
-== clip-path-circle-015.html clip-path-circle-008-ref.html
-== clip-path-circle-016.html clip-path-circle-009-ref.html
+fuzzy-if(webrender,89,690) == clip-path-circle-001.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,89,690) == clip-path-circle-002.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,89,690) == clip-path-circle-003.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,89,690) == clip-path-circle-004.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-005.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,89,690) == clip-path-circle-006.html clip-path-circle-001-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-007.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-008.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-009.html clip-path-circle-003-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-010.html clip-path-circle-004-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-011.html clip-path-circle-005-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-012.html clip-path-circle-006-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-013.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,89,698) == clip-path-circle-014.html clip-path-circle-007-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-015.html clip-path-circle-008-ref.html
+fuzzy-if(webrender,89,702) == clip-path-circle-016.html clip-path-circle-009-ref.html
 fuzzy-if(webrender,128,714) == clip-path-circle-017.html clip-path-circle-007-ref.html
-== clip-path-circle-018.html clip-path-circle-010-ref.html
-== clip-path-circle-019.html clip-path-circle-002-ref.html
-== clip-path-circle-020.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-018.html clip-path-circle-010-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-019.html clip-path-circle-002-ref.html
+fuzzy-if(webrender,64,714) == clip-path-circle-020.html clip-path-circle-002-ref.html
 == clip-path-circle-021.html clip-path-circle-021-ref.html
 
-== clip-path-ellipse-001.html clip-path-ellipse-001-ref.html
-== clip-path-ellipse-002.html clip-path-ellipse-001-ref.html
-== clip-path-ellipse-003.html clip-path-ellipse-001-ref.html
-== clip-path-ellipse-004.html clip-path-ellipse-001-ref.html
-== clip-path-ellipse-005.html clip-path-ellipse-001-ref.html
-== clip-path-ellipse-006.html clip-path-ellipse-001-ref.html
-== clip-path-ellipse-007.html clip-path-ellipse-001-ref.html
-== clip-path-ellipse-008.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,64,1106) == clip-path-ellipse-001.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,64,1106) == clip-path-ellipse-002.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,64,1106) == clip-path-ellipse-003.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,64,1106) == clip-path-ellipse-004.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,64,1106) == clip-path-ellipse-005.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,64,1106) == clip-path-ellipse-006.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,64,1106) == clip-path-ellipse-007.html clip-path-ellipse-001-ref.html
+fuzzy-if(webrender,64,1106) == clip-path-ellipse-008.html clip-path-ellipse-001-ref.html
 
 == clip-path-inset-001a.html clip-path-inset-001-ref.html
 == clip-path-inset-001b.html clip-path-inset-001-ref.html
 == clip-path-inset-001c.html clip-path-inset-001-ref.html
 # Anti-aliasing behavior for masking and borders is different
 fuzzy(64,146) == clip-path-inset-002a.html clip-path-inset-002-ref.html
 fuzzy(64,146) == clip-path-inset-002b.html clip-path-inset-002-ref.html
 fuzzy(64,146) == clip-path-inset-002c.html clip-path-inset-002-ref.html
--- a/layout/reftests/svg/svg-integration/reftest.list
+++ b/layout/reftests/svg/svg-integration/reftest.list
@@ -22,21 +22,21 @@ fuzzy-if(Android,255,30) == clipPath-htm
 == conditions-outer-svg-02.xhtml ../pass.svg
 == dynamic-conditions-outer-svg-01.xhtml ../pass.svg
 == dynamic-conditions-outer-svg-02.xhtml ../pass.svg
 == dynamic-conditions-outer-svg-03.xhtml ../pass.svg
 == dynamic-conditions-outer-svg-04.xhtml ../pass.svg
 == filter-html-01.xhtml filter-html-01-ref.svg
 random-if(Android) random-if(styloVsGecko) == filter-html-01-extref.xhtml filter-html-01-ref.svg # Android: bug 1198380
 == filter-html-zoomed-01.xhtml filter-html-01-ref.svg
-== mask-html-01.xhtml mask-html-01-ref.svg
-== mask-html-01-extref-01.xhtml mask-html-01-ref.svg
+fuzzy-if(webrender,1,125414) == mask-html-01.xhtml mask-html-01-ref.svg
+fuzzy-if(webrender,1,125414) == mask-html-01-extref-01.xhtml mask-html-01-ref.svg
 random == mask-html-01-extref-02.xhtml mask-html-01-ref.svg # random due to bug 877661
-== mask-html-zoomed-01.xhtml mask-html-01-ref.svg
-== mask-html-xbl-bound-01.html mask-html-01-ref.svg
+fuzzy-if(webrender,1,125414) == mask-html-zoomed-01.xhtml mask-html-01-ref.svg
+fuzzy-if(webrender,1,125414) == mask-html-xbl-bound-01.html mask-html-01-ref.svg
 == mask-transformed-html-01.xhtml ../pass.svg
 == mask-transformed-html-02.xhtml ../pass.svg
 fuzzy-if(skiaContent,1,5) == patterned-svg-under-transformed-html-01.xhtml ../pass.svg
 == patterned-svg-under-transformed-html-02.xhtml ../pass.svg
 
 fuzzy(1,5000) == mask-clipPath-opacity-01a.xhtml mask-clipPath-opacity-01-ref.xhtml
 fuzzy(1,5000) == mask-clipPath-opacity-01b.xhtml mask-clipPath-opacity-01-ref.xhtml
 fuzzy(1,5000) == mask-clipPath-opacity-01c.xhtml mask-clipPath-opacity-01-ref.xhtml
--- a/layout/reftests/table-background/reftest.list
+++ b/layout/reftests/table-background/reftest.list
@@ -36,18 +36,18 @@ asserts-if(gtkWidget,0-6) != backgr_bord
 == border-separate-table.html border-separate-table-ref.html
 == border-collapse-table-cell.html border-collapse-table-cell-ref.html
 == border-collapse-table-column-group.html border-collapse-table-column-group-ref.html
 == border-collapse-table-column.html border-collapse-table-column-ref.html
 == border-collapse-table-row-group.html border-collapse-table-row-group-ref.html
 == border-collapse-table-row.html border-collapse-table-row-ref.html
 == border-collapse-table.html border-collapse-table-ref.html
 fuzzy-if(d2d,1,1083) fuzzy-if(skiaContent,1,2200) == border-collapse-opacity-table-cell.html border-collapse-opacity-table-cell-ref.html
-fails-if(!styloVsGecko) == border-collapse-opacity-table-column-group.html border-collapse-opacity-table-column-group-ref.html # bug 424274
-fails-if(!styloVsGecko) == border-collapse-opacity-table-column.html border-collapse-opacity-table-column-ref.html # bug 424274
+fails-if(!styloVsGecko&&!webrender) == border-collapse-opacity-table-column-group.html border-collapse-opacity-table-column-group-ref.html # bug 424274
+fails-if(!styloVsGecko&&!webrender) == border-collapse-opacity-table-column.html border-collapse-opacity-table-column-ref.html # bug 424274
 fuzzy-if(d2d,1,16359) fuzzy-if(skiaContent,1,17000) == border-collapse-opacity-table-row-group.html border-collapse-opacity-table-row-group-ref.html
 fuzzy-if(d2d,1,11000) fuzzy-if(skiaContent,1,11000) == border-collapse-opacity-table-row.html border-collapse-opacity-table-row-ref.html
 fuzzy-if(d2d||skiaContent,1,60000) == border-collapse-opacity-table.html border-collapse-opacity-table-ref.html
 fuzzy-if(d2d,1,2478) fuzzy-if(skiaContent,1,2500) == border-separate-opacity-table-cell.html border-separate-opacity-table-cell-ref.html
 fuzzy-if(d2d,1,38000) == border-separate-opacity-table-column-group.html border-separate-opacity-table-column-group-ref.html # bug 424274
 fuzzy-if(d2d,1,13000) == border-separate-opacity-table-column.html border-separate-opacity-table-column-ref.html # bug 424274
 fuzzy-if(d2d,1,37170) fuzzy-if(skiaContent,1,38000) == border-separate-opacity-table-row-group.html border-separate-opacity-table-row-group-ref.html
 fuzzy-if(d2d,1,12390) fuzzy-if(skiaContent,1,13000) == border-separate-opacity-table-row.html border-separate-opacity-table-row-ref.html
--- a/layout/reftests/transform/reftest.list
+++ b/layout/reftests/transform/reftest.list
@@ -1,14 +1,14 @@
 # Transforms specifying singular matrices shouldn't display at all.
 # NOTE: Regressions might manifest themselves as reftest timeouts on
 # this test.
 == singular-1a.html about:blank
 # Multiple transforms should act identically to nested divs.
-== compound-1a.html compound-1-ref.html
+fuzzy-if(webrender,1,27) == compound-1a.html compound-1-ref.html
 != compound-1a.html compound-1-fail.html
 == dynamic-inherit-1.html dynamic-inherit-1-ref.html
 == dynamic-addremove-1a.html dynamic-addremove-1-ref.html
 == dynamic-addremove-1b.html dynamic-addremove-1-ref.html
 == dynamic-addremove-1c.html dynamic-addremove-1-ref.html
 == dynamic-addremove-2.html dynamic-addremove-2-ref.html
 # translatex should act like position: relative
 == translatex-1a.html translatex-1-ref.html
@@ -82,19 +82,19 @@ fuzzy-if(skiaContent,1,350) == origin-na
 == origin-name-3b.html origin-name-3-ref.html
 # Snapping still applies after 90 degree rotations.
 == snapping-1.html snapping-1-ref.html
 # SVG effects should work on transforms.
 == transform-svg-1a.xhtml transform-svg-1-ref.xhtml
 fuzzy-if(skiaContent,2,500) == transform-svg-2a.xhtml transform-svg-2-ref.xhtml
 != transform-svg-2a.xhtml transform-svg-2-fail.xhtml
 # skew should allow a mix of one and two parameters.
-== skew-1a.html skew-1-ref.html
+fuzzy-if(webrender,1,20) == skew-1a.html skew-1-ref.html
 fuzzy-if(skiaContent,1,80) == skew-1b.html skew-1-ref.html
-== skew-2a.html skew-2-ref.html
+fuzzy-if(webrender,1,250) == skew-2a.html skew-2-ref.html
 # matrix with values equal to other transforms should behave indistinguishably
 == matrix-1a.html matrix-1-ref.html
 == matrix-2a.html matrix-2-ref.html
 == matrix-3a.html matrix-3-ref.html
 == matrix-4a.html matrix-4-ref.html
 fuzzy-if(skiaContent,1,120) == matrix-5a.html matrix-5-ref.html
 fuzzy-if(skiaContent,1,110) == matrix-6a.html matrix-6-ref.html
 == matrix-7a.html matrix-7-ref.html
--- a/layout/reftests/w3c-css/submitted/background/reftest.list
+++ b/layout/reftests/w3c-css/submitted/background/reftest.list
@@ -30,9 +30,9 @@
 == border-image-repeat-space-4-ref-1.html border-image-repeat-space-4-ref-2.html
 == border-image-repeat-space-5.html border-image-repeat-space-5-ref-1.html
 == border-image-repeat-space-5-ref-1.html border-image-repeat-space-5-ref-2.html
 == border-image-repeat-space-6.html border-image-repeat-space-6-ref.html
 == border-image-repeat-space-7.html border-image-repeat-space-7-ref.html
 == border-image-repeat-1.html border-image-repeat-1-ref.html
 
 # background-attachment test cases
-== background-attachment-fixed-inside-transform-1.html background-attachment-fixed-inside-transform-1-ref.html
+fuzzy-if(webrender,1,10) == background-attachment-fixed-inside-transform-1.html background-attachment-fixed-inside-transform-1-ref.html
--- a/layout/reftests/w3c-css/submitted/flexbox/reftest.list
+++ b/layout/reftests/w3c-css/submitted/flexbox/reftest.list
@@ -23,17 +23,17 @@
 
 == flexbox-align-self-stretch-vert-001.html flexbox-align-self-stretch-vert-001-ref.html
 == flexbox-align-self-stretch-vert-002.html flexbox-align-self-stretch-vert-002-ref.html
 
 == flexbox-align-self-horiz-001-block.xhtml  flexbox-align-self-horiz-001-ref.xhtml
 == flexbox-align-self-horiz-001-table.xhtml  flexbox-align-self-horiz-001-ref.xhtml
 == flexbox-align-self-horiz-002.xhtml  flexbox-align-self-horiz-002-ref.xhtml
 == flexbox-align-self-horiz-003.xhtml  flexbox-align-self-horiz-003-ref.xhtml
-== flexbox-align-self-horiz-004.xhtml  flexbox-align-self-horiz-004-ref.xhtml
+fuzzy-if(webrender,1,2) == flexbox-align-self-horiz-004.xhtml  flexbox-align-self-horiz-004-ref.xhtml
 == flexbox-align-self-horiz-005.xhtml  flexbox-align-self-horiz-005-ref.xhtml
 == flexbox-align-self-vert-001.xhtml  flexbox-align-self-vert-001-ref.xhtml
 == flexbox-align-self-vert-002.xhtml  flexbox-align-self-vert-002-ref.xhtml
 == flexbox-align-self-vert-003.xhtml  flexbox-align-self-vert-003-ref.xhtml
 == flexbox-align-self-vert-004.xhtml  flexbox-align-self-vert-004-ref.xhtml
 fuzzy-if(Android,158,32) == flexbox-align-self-vert-rtl-001.xhtml  flexbox-align-self-vert-rtl-001-ref.xhtml
 == flexbox-align-self-vert-rtl-002.xhtml  flexbox-align-self-vert-rtl-002-ref.xhtml
 == flexbox-align-self-vert-rtl-003.xhtml  flexbox-align-self-vert-rtl-003-ref.xhtml
--- a/layout/reftests/w3c-css/submitted/masking/reftest.list
+++ b/layout/reftests/w3c-css/submitted/masking/reftest.list
@@ -83,33 +83,33 @@ fails-if(!styloVsGecko) == mask-origin-2
 == mask-size-percent.html mask-size-percent-percent-ref.html
 == mask-size-percent-auto.html mask-size-percent-percent-ref.html
 == mask-size-percent-length.html mask-size-percent-percent-ref.html
 == mask-size-percent-percent.html mask-size-percent-percent-ref.html
 == mask-size-percent-percent-stretch.html mask-size-percent-percent-stretch-ref.html
 
 default-preferences pref(layout.css.clip-path-shapes.enabled,true)
 
-fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-contentBox-1a.html clip-path-geometryBox-1-ref.html
+fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) fuzzy-if(webrender,64,371) == clip-path-contentBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-contentBox-1b.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-contentBox-1c.html clip-path-geometryBox-1-ref.html
-fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-paddingBox-1a.html clip-path-geometryBox-1-ref.html
+fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) fuzzy-if(webrender,64,371) == clip-path-paddingBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-paddingBox-1b.html clip-path-geometryBox-1-ref.html
-fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-paddingBox-1c.html clip-path-geometryBox-1-ref.html
+fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) fuzzy-if(webrender,64,371) == clip-path-paddingBox-1c.html clip-path-geometryBox-1-ref.html
 fuzzy(64,370) == clip-path-borderBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-borderBox-1b.html clip-path-geometryBox-1-ref.html
 fuzzy(64,370) == clip-path-borderBox-1c.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-marginBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy(64,370) == clip-path-fillBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy(64,370) == clip-path-strokeBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy(64,370) == clip-path-strokeBox-1b.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-viewBox-1a.html clip-path-geometryBox-1-ref.html
 fuzzy-if(winWidget,1,21) fuzzy-if(skiaContent,1,60) == clip-path-viewBox-1b.html clip-path-geometryBox-1-ref.html
 fuzzy(64,370) == clip-path-viewBox-1c.html clip-path-geometryBox-1-ref.html
-fuzzy-if(winWidget,9,98) == clip-path-geometryBox-2.html clip-path-geometryBox-2-ref.html
+fuzzy-if(winWidget,9,98) fuzzy-if(webrender,64,100) == clip-path-geometryBox-2.html clip-path-geometryBox-2-ref.html
 
 == clip-path-localRef-1.html clip-path-localRef-1-ref.html
 
 default-preferences
 
 # mask with opacity test cases
 fuzzy(1,5000) == mask-opacity-1a.html mask-opacity-1-ref.html
 fuzzy(1,5000) == mask-opacity-1b.html mask-opacity-1-ref.html
--- a/layout/reftests/w3c-css/submitted/values3/reftest.list
+++ b/layout/reftests/w3c-css/submitted/values3/reftest.list
@@ -18,14 +18,14 @@
 == calc-offsets-absolute-top-1.html calc-offsets-absolute-top-1-ref.html
 == calc-offsets-relative-bottom-1.html calc-offsets-relative-top-1-ref.html
 == calc-offsets-relative-left-1.html calc-offsets-relative-left-1-ref.html
 == calc-offsets-relative-right-1.html calc-offsets-relative-left-1-ref.html
 == calc-offsets-relative-top-1.html calc-offsets-relative-top-1-ref.html
 == calc-padding-block-1.html calc-padding-block-1-ref.html
 == calc-text-indent-1.html calc-text-indent-1-ref.html
 == calc-text-indent-intrinsic-1.html calc-text-indent-intrinsic-1-ref.html
-fuzzy-if(skiaContent,1,11) == calc-transform-origin-1.html calc-transform-origin-1-ref.html
+fuzzy-if(skiaContent,1,11) fuzzy-if(webrender,1,30) == calc-transform-origin-1.html calc-transform-origin-1-ref.html
 == calc-vertical-align-1.html calc-vertical-align-1-ref.html
 == calc-width-block-1.html calc-width-block-1-ref.html
 == calc-width-block-intrinsic-1.html calc-width-block-intrinsic-1-ref.html
 == calc-width-table-auto-1.html calc-width-table-auto-1-ref.html
 == calc-width-table-fixed-1.html calc-width-table-fixed-1-ref.html
--- a/layout/reftests/webm-video/reftest.list
+++ b/layout/reftests/webm-video/reftest.list
@@ -46,10 +46,10 @@ fails-if(layersGPUAccelerated&&!webrende
 fails-if(layersGPUAccelerated&&!webrender) fails-if(webrender&&browserIsRemote) skip-if(Android) fails-if(styloVsGecko) == object-fit-cover-webm-001.html object-fit-cover-webm-001-ref.html # Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures
 fails-if(layersGPUAccelerated&&!webrender) fails-if(webrender&&browserIsRemote) skip-if(Android) fails-if(styloVsGecko) == object-fit-cover-webm-002.html object-fit-cover-webm-002-ref.html # Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures
 fails-if(layersGPUAccelerated&&!webrender) fails-if(webrender&&browserIsRemote) skip-if(Android) fails-if(styloVsGecko) == object-fit-fill-webm-001.html object-fit-fill-webm-001-ref.html # Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures
 fails-if(layersGPUAccelerated&&!webrender) fails-if(webrender&&browserIsRemote) skip-if(Android) fails-if(styloVsGecko) == object-fit-fill-webm-002.html object-fit-fill-webm-002-ref.html # Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures
 fails-if(layersGPUAccelerated&&!webrender) fails-if(webrender&&browserIsRemote) skip-if(Android) fails-if(styloVsGecko) == object-fit-none-webm-001.html object-fit-none-webm-001-ref.html # Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures
 fails-if(layersGPUAccelerated&&!webrender) fails-if(webrender&&browserIsRemote) skip-if(Android) fails-if(styloVsGecko) == object-fit-none-webm-002.html object-fit-none-webm-002-ref.html # Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures
 fails-if(layersGPUAccelerated&&!webrender) fails-if(webrender&&browserIsRemote) skip-if(Android) fails-if(styloVsGecko) == object-fit-scale-down-webm-001.html object-fit-scale-down-webm-001-ref.html # Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures
 fails-if(layersGPUAccelerated&&!webrender) fails-if(webrender&&browserIsRemote) skip-if(Android) fails-if(styloVsGecko) == object-fit-scale-down-webm-002.html object-fit-scale-down-webm-002-ref.html # Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures
-fails-if(layersGPUAccelerated) skip-if(Android) fails fails-if(styloVsGecko) == object-position-webm-001.html object-position-webm-001-ref.html # Bug 1098417 for across-the-board failure, Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures
-fails-if(layersGPUAccelerated) skip-if(Android) fails fails-if(styloVsGecko) == object-position-webm-002.html object-position-webm-002-ref.html # Bug 1098417 for across-the-board failure, Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures
+fails-if(layersGPUAccelerated) skip-if(Android) fails fails-if(styloVsGecko) skip-if(webrender) == object-position-webm-001.html object-position-webm-001-ref.html # Bug 1098417 for across-the-board failure, Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures, Bug 1358055 for webrender failures
+fails-if(layersGPUAccelerated) skip-if(Android) fails fails-if(styloVsGecko) skip-if(webrender) == object-position-webm-002.html object-position-webm-002-ref.html # Bug 1098417 for across-the-board failure, Bug 1083516 for layersGPUAccelerated failures, Bug 1084564 for Android failures, Bug 1358055 for webrender failures
--- a/layout/reftests/writing-mode/reftest.list
+++ b/layout/reftests/writing-mode/reftest.list
@@ -142,17 +142,17 @@ test-pref(dom.meta-viewport.enabled,true
 == 1175789-underline-overline-1.html 1175789-underline-overline-1-ref.html
 == 1188061-1-nsChangeHint_ClearAncestorIntrinsics.html 1188061-1-nsChangeHint_ClearAncestorIntrinsics-ref.html
 == 1188061-2-nsChangeHint_UpdateComputedBSize.html 1188061-2-nsChangeHint_UpdateComputedBSize-ref.html
 
 # tests involving sideways-lr mode
 == 1193519-sideways-lr-1.html 1193519-sideways-lr-1-ref.html
 == 1193519-sideways-lr-2.html 1193519-sideways-lr-2-ref.html
 fuzzy-if(winWidget,3,84) == 1193519-sideways-lr-3.html 1193519-sideways-lr-3-ref.html
-fuzzy-if(winWidget,3,112) == 1193519-sideways-lr-4.html 1193519-sideways-lr-4-ref.html
+fuzzy-if(winWidget,3,112) fails-if(webrender) == 1193519-sideways-lr-4.html 1193519-sideways-lr-4-ref.html # see bug 1366692. Rounding error with WR enabled.
 fuzzy-if(gtkWidget,255,6) fuzzy-if(cocoaWidget,65,69) == 1193519-sideways-lr-decoration-1.html 1193519-sideways-lr-decoration-1-ref.html
 
 == 1196887-1-computed-display-inline-block.html 1196887-1-computed-display-inline-block-ref.html
 == 1205787-legacy-svg-values-1.html 1205787-legacy-svg-values-1-ref.html
 
 == 1216747-1.html 1216747-1-ref.html
 != 1216747-1.html 1216747-1-notref.html
 
--- a/testing/mozharness/mozharness/mozilla/building/buildbase.py
+++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py
@@ -1612,18 +1612,26 @@ or run without that action (ie: --no-{ac
         dirs = self.query_abs_dirs()
         buildprops = os.path.join(dirs['base_work_dir'], 'buildprops.json')
         # not finding buildprops is not an error outside of buildbot
         if os.path.exists(buildprops):
             self.copyfile(
                 buildprops,
                 os.path.join(dirs['abs_work_dir'], 'buildprops.json'))
 
+        if 'MOZILLABUILD' in os.environ:
+            mach = [
+                os.path.join(os.environ['MOZILLABUILD'], 'msys', 'bin', 'bash.exe'),
+                os.path.join(dirs['abs_src_dir'], 'mach')
+            ]
+        else:
+            mach = [sys.executable, 'mach']
+
         return_code = self.run_command_m(
-            command=[sys.executable, 'mach', '--log-no-times', 'build', '-v'],
+            command=mach + ['--log-no-times', 'build', '-v'],
             cwd=dirs['abs_src_dir'],
             env=env,
             output_timeout=self.config.get('max_build_output_timeout', 60 * 40)
         )
         if return_code:
             self.return_code = self.worst_level(
                 EXIT_STATUS_DICT[TBPL_FAILURE],  self.return_code,
                 AUTOMATION_EXIT_CODES[::-1]
--- a/widget/nsPrintOptionsImpl.cpp
+++ b/widget/nsPrintOptionsImpl.cpp
@@ -492,48 +492,60 @@ nsPrintOptions::ReadPrefs(nsIPrintSettin
     bool success = GETINTPREF(kPrintPaperSizeUnit, &sizeUnit)
                   && GETDBLPREF(kPrintPaperWidth, width)
                   && GETDBLPREF(kPrintPaperHeight, height)
                   && GETSTRPREF(kPrintPaperName, &str);
 
     // Bug 315687: Sanity check paper size to avoid paper size values in
     // mm when the size unit flag is inches. The value 100 is arbitrary
     // and can be changed.
+#if defined(XP_WIN)
+    bool saveSanitizedSizePrefs = false;
+#endif
     if (success) {
       success = (sizeUnit != nsIPrintSettings::kPaperSizeInches)
              || (width < 100.0)
              || (height < 100.0);
 #if defined(XP_WIN)
       // Work around legacy invalid prefs where the size unit gets set to
-      // millimeters, but the height and width remains as the default inches
-      // ones for letter. See bug 1276717.
+      // millimeters, but the height and width remains as the previous inches
+      // settings. See bug 1276717 and bug 1369386 for details.
       if (sizeUnit == nsIPrintSettings::kPaperSizeMillimeters &&
-          height == 11L && width == 8.5L) {
+          height >= 0L && height < 25L &&
+          width >= 0L && width < 25L) {
 
-        // As an extra precaution only override, when the resolution is also
-        // set to the legacy invalid, uninitialized value. We'll just broadly
-        // assume that anything outside of a million DPI is invalid.
-        if (GETINTPREF(kPrintResolution, &iVal) &&
-            (iVal <= 0 || iVal > 1000000)) {
+        // As small pages sizes can be valid we only override when the old
+        // (now no longer set) pref print_paper_size_type exists. This will be
+        // removed when we save the prefs below.
+        const char* paperSizeTypePref =
+          GetPrefName("print_paper_size_type", aPrinterName);
+        if (Preferences::HasUserValue(paperSizeTypePref)) {
+          saveSanitizedSizePrefs = true;
           height = -1L;
           width = -1L;
         }
       }
 #endif
     }
 
     if (success) {
       aPS->SetPaperSizeUnit(sizeUnit);
       DUMP_INT(kReadStr, kPrintPaperSizeUnit, sizeUnit);
       aPS->SetPaperWidth(width);
       DUMP_DBL(kReadStr, kPrintPaperWidth, width);
       aPS->SetPaperHeight(height);
       DUMP_DBL(kReadStr, kPrintPaperHeight, height);
       aPS->SetPaperName(str.get());
       DUMP_STR(kReadStr, kPrintPaperName, str.get());
+#if defined(XP_WIN)
+      if (saveSanitizedSizePrefs) {
+        SavePrintSettingsToPrefs(aPS, !aPrinterName.IsEmpty(),
+                                 nsIPrintSettings::kInitSavePaperSize);
+      }
+#endif
     }
   }
 
   if (aFlags & nsIPrintSettings::kInitSaveOddEvenPages) {
   if (GETBOOLPREF(kPrintEvenPages, &b)) {
     aPS->SetPrintOptions(nsIPrintSettings::kPrintEvenPages, b);
     DUMP_BOOL(kReadStr, kPrintEvenPages, b);
   }
@@ -765,16 +777,30 @@ nsPrintOptions::WritePrefs(nsIPrintSetti
       Preferences::SetInt(GetPrefName(kPrintPaperSizeUnit, aPrinterName),
                           int32_t(sizeUnit));
       DUMP_DBL(kWriteStr, kPrintPaperWidth, width);
       WritePrefDouble(GetPrefName(kPrintPaperWidth, aPrinterName), width);
       DUMP_DBL(kWriteStr, kPrintPaperHeight, height);
       WritePrefDouble(GetPrefName(kPrintPaperHeight, aPrinterName), height);
       DUMP_STR(kWriteStr, kPrintPaperName, name);
       Preferences::SetString(GetPrefName(kPrintPaperName, aPrinterName), name);
+#if defined(XP_WIN)
+      // If the height and width are -1 then this might be a save triggered by
+      // print pref sanitizing code. This is done as a one off and is partly
+      // triggered by the existence of an old (now no longer set) pref. We
+      // remove that pref if it exists here, so that we don't try and sanitize
+      // what might be valid prefs. See bug 1276717 and bug 1369386 for details.
+      if (height == -1L && width == -1L) {
+        const char* paperSizeTypePref =
+          GetPrefName("print_paper_size_type", aPrinterName);
+        if (Preferences::HasUserValue(paperSizeTypePref)) {
+          Preferences::ClearUser(paperSizeTypePref);
+        }
+      }
+#endif
     }
   }
 
   bool       b;
   char16_t* uStr;
   int32_t    iVal;
   int16_t    iVal16;
   double     dbl;