Merge m-c to graphics
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 24 Jan 2017 08:05:30 -0500
changeset 342216 b86ff4066687c7f880598820360b3c564b4f60d6
parent 342215 6c0b2aee81443c80a0457f4c579a0b28408dd427 (current diff)
parent 330744 8ff550409e1d1f8b54f6f7f115545dbef857be0b (diff)
child 342217 7b33131fed2074be7897b277335f3aa8fa198ca5
push id86826
push userkwierso@gmail.com
push dateFri, 10 Feb 2017 23:33:17 +0000
treeherdermozilla-inbound@2c7816419218 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone54.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 m-c to graphics MozReview-Commit-ID: bxs3Qj28c5
CLOBBER
browser/base/content/browser-captivePortal.js
browser/installer/allowed-dupes.mn
dom/ipc/TabChild.cpp
modules/libpref/init/all.js
taskcluster/ci/test/test-platforms.yml
taskcluster/ci/test/test-sets.yml
taskcluster/docker/rust-build/VERSION
taskcluster/docker/rust-build/repack_rust.py
toolkit/moz.configure
--- a/.hgtags
+++ b/.hgtags
@@ -125,8 +125,9 @@ 67a788db9f07822cfef52351bbbe3745dff8bd7f
 99137d6d4061f408ae0869122649d8bdf489cc30 FIREFOX_AURORA_45_BASE
 67c66c2878aed17ae3096d7db483ddbb2293c503 FIREFOX_AURORA_46_BASE
 68d3781deda0d4d58ec9877862830db89669b3a5 FIREFOX_AURORA_47_BASE
 1c6385ae1fe7e37d8f23f958ce14582f07af729e FIREFOX_AURORA_48_BASE
 d98f20c25feeac4dd7ebbd1c022957df1ef58af4 FIREFOX_AURORA_49_BASE
 465d150bc8be5bbf9f02a8607d4552b6a5e1697c FIREFOX_AURORA_50_BASE
 fc69febcbf6c0dcc4b3dfc7a346d8d348798a65f FIREFOX_AURORA_51_BASE
 1196bf3032e1bce1fb07a01fd9082a767426c5fb FIREFOX_AURORA_52_BASE
+f80dc9fc34680105b714a49b4704bb843f5f7004 FIREFOX_AURORA_53_BASE
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1223692 vp8/common/loopfilter.c removed.
+Merge day clobber
\ No newline at end of file
--- a/addon-sdk/test/browser.ini
+++ b/addon-sdk/test/browser.ini
@@ -2,13 +2,14 @@
 support-files =
   head.js
   Math.jsm
   math.js
   data.json
   invalid.json
 [browser_sdk_loader_sdk_modules.js]
 [browser_sdk_loader_sdk_gui_modules.js]
+skip-if = e10s # Bug 1315042
 [browser_sdk_loader_jsm_modules.js]
 [browser_sdk_loader_js_modules.js]
 [browser_sdk_loader_json.js]
 [browser_sdk_loader_chrome.js]
 [browser_sdk_loader_chrome_in_sdk.js]
--- a/browser/base/content/aboutNetError.xhtml
+++ b/browser/base/content/aboutNetError.xhtml
@@ -542,17 +542,17 @@
         <h1 id="et_remoteXUL">&remoteXUL.title;</h1>
         <h1 id="et_corruptedContentErrorv2">&corruptedContentErrorv2.title;</h1>
         <h1 id="et_sslv3Used">&sslv3Used.title;</h1>
         <h1 id="et_weakCryptoUsed">&weakCryptoUsed.title;</h1>
         <h1 id="et_inadequateSecurityError">&inadequateSecurityError.title;</h1>
       </div>
       <div id="errorDescriptionsContainer">
         <div id="ed_generic">&generic.longDesc;</div>
-        <div id="ed_captivePortal">&captivePortal.longDesc;</div>
+        <div id="ed_captivePortal">&captivePortal.longDesc2;</div>
         <div id="ed_dnsNotFound">&dnsNotFound.longDesc;</div>
         <div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
         <div id="ed_fileAccessDenied">&fileAccessDenied.longDesc;</div>
         <div id="ed_malformedURI">&malformedURI.longDesc;</div>
         <div id="ed_unknownProtocolFound">&unknownProtocolFound.longDesc;</div>
         <div id="ed_connectionFailure">&connectionFailure.longDesc;</div>
         <div id="ed_netTimeout">&netTimeout.longDesc;</div>
         <div id="ed_redirectLoop">&redirectLoop.longDesc;</div>
@@ -611,17 +611,17 @@
 
         <div id="prefChangeContainer" class="button-container">
           <p>&prefReset.longDesc;</p>
           <button id="prefResetButton" class="primary" autocomplete="off">&prefReset.label;</button>
         </div>
 
         <div id="certErrorAndCaptivePortalButtonContainer" class="button-container">
           <button id="returnButton" class="primary" autocomplete="off" autofocus="true">&returnToPreviousPage.label;</button>
-          <button id="openPortalLoginPageButton" class="primary" autocomplete="off" autofocus="true">&openPortalLoginPage.label;</button>
+          <button id="openPortalLoginPageButton" class="primary" autocomplete="off" autofocus="true">&openPortalLoginPage.label2;</button>
           <div class="button-spacer"></div>
           <button id="advancedButton" autocomplete="off" autofocus="true">&advanced.label;</button>
         </div>
       </div>
 
       <div id="netErrorButtonContainer" class="button-container">
         <button id="errorTryAgain" class="primary" autocomplete="off" onclick="retryThis(this);">&retry.label;</button>
       </div>
--- a/browser/base/content/browser-captivePortal.js
+++ b/browser/base/content/browser-captivePortal.js
@@ -187,28 +187,28 @@ var CaptivePortalWatcher = {
     } else {
       button.style.visibility = "visible";
     }
   },
 
   _showNotification() {
     let buttons = [
       {
-        label: this._browserBundle.GetStringFromName("captivePortal.showLoginPage"),
+        label: this._browserBundle.GetStringFromName("captivePortal.showLoginPage2"),
         callback: () => {
           this.ensureCaptivePortalTab();
 
           // Returning true prevents the notification from closing.
           return true;
         },
         isDefault: true,
       },
     ];
 
-    let message = this._browserBundle.GetStringFromName("captivePortal.infoMessage2");
+    let message = this._browserBundle.GetStringFromName("captivePortal.infoMessage3");
 
     let closeHandler = (aEventName) => {
       if (aEventName != "removed") {
         return;
       }
       gBrowser.tabContainer.removeEventListener("TabSelect", this);
     };
 
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -447,16 +447,29 @@
         <menupopup id="otherBookmarksFolderPopup"
 #ifndef XP_MACOSX
                    placespopup="true"
 #endif
                    context="placesContext"
                    onpopupshowing="if (!this.parentNode._placesView)
                                      new PlacesMenu(event, 'place:folder=UNFILED_BOOKMARKS');"/>
       </menu>
+      <menu id="menu_mobileBookmarks"
+            class="menu-iconic bookmark-item"
+            label="&mobileBookmarksCmd.label;"
+            hidden="true"
+            container="true">
+        <menupopup id="mobileBookmarksFolderPopup"
+#ifndef XP_MACOSX
+                   placespopup="true"
+#endif
+                   context="placesContext"
+                   onpopupshowing="if (!this.parentNode._placesView)
+                                     new PlacesMenu(event, 'place:folder=MOBILE_BOOKMARKS');"/>
+      </menu>
       <menuseparator id="bookmarksMenuItemsSeparator"/>
       <!-- Bookmarks menu items -->
     </menupopup>
   </menu>
 
             <menu id="tools-menu"
                   label="&toolsMenu.label;"
                   accesskey="&toolsMenu.accesskey;"
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -1337,16 +1337,17 @@ var BookmarkingUI = {
     if (widget.overflowed) {
       // Don't open a popup in the overflow popup, rather just open the Library.
       event.preventDefault();
       widget.node.removeAttribute("closemenu");
       PlacesCommandHook.showPlacesOrganizer("BookmarksMenu");
       return;
     }
 
+    this._initMobileBookmarks(document.getElementById("BMB_mobileBookmarks"));
     this._initRecentBookmarks(document.getElementById("BMB_recentBookmarks"),
                               "subviewbutton");
 
     if (!this._popupNeedsUpdate)
       return;
     this._popupNeedsUpdate = false;
 
     let popup = event.target;
@@ -1375,16 +1376,38 @@ var BookmarkingUI = {
         footer: "panel-subview-footer"
       },
       insertionPoint: ".panel-subview-footer"
     });
   },
 
   RECENTLY_BOOKMARKED_PREF: "browser.bookmarks.showRecentlyBookmarked",
 
+  // Set by sync after syncing bookmarks successfully once.
+  MOBILE_BOOKMARKS_PREF: "browser.bookmarks.showMobileBookmarks",
+
+  _shouldShowMobileBookmarks() {
+    try {
+      return Services.prefs.getBoolPref(this.MOBILE_BOOKMARKS_PREF);
+    } catch (e) {}
+    // No pref set (or invalid pref set), look for a mobile bookmarks left pane query.
+    const organizerQueryAnno = "PlacesOrganizer/OrganizerQuery";
+    const mobileBookmarksAnno = "MobileBookmarks";
+    let shouldShow = PlacesUtils.annotations.getItemsWithAnnotation(organizerQueryAnno, {}).filter(
+      id => PlacesUtils.annotations.getItemAnnotation(id, organizerQueryAnno) == mobileBookmarksAnno
+    ).length > 0;
+    // Sync will change this pref if/when it adds a mobile bookmarks query.
+    Services.prefs.setBoolPref(this.MOBILE_BOOKMARKS_PREF, shouldShow);
+    return shouldShow;
+  },
+
+  _initMobileBookmarks(mobileMenuItem) {
+    mobileMenuItem.hidden = !this._shouldShowMobileBookmarks();
+  },
+
   _initRecentBookmarks(aHeaderItem, aExtraCSSClass) {
     this._populateRecentBookmarks(aHeaderItem, aExtraCSSClass);
 
     // Add observers and listeners and remove them again when the menupopup closes.
 
     let bookmarksMenu = aHeaderItem.parentNode;
     let placesContextMenu = document.getElementById("placesContext");
 
@@ -1705,16 +1728,17 @@ var BookmarkingUI = {
 
   onMainMenuPopupShowing: function BUI_onMainMenuPopupShowing(event) {
     // Don't handle events for submenus.
     if (event.target != event.currentTarget)
       return;
 
     this._updateBookmarkPageMenuItem();
     PlacesCommandHook.updateBookmarkAllTabsCommand();
+    this._initMobileBookmarks(document.getElementById("menu_mobileBookmarks"));
     this._initRecentBookmarks(document.getElementById("menu_recentBookmarks"));
   },
 
   _showBookmarkedNotification: function BUI_showBookmarkedNotification() {
     function getCenteringTransformForRects(rectToPosition, referenceRect) {
       let topDiff = referenceRect.top - rectToPosition.top;
       let leftDiff = referenceRect.left - rectToPosition.left;
       let heightDiff = referenceRect.height - rectToPosition.height;
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6241,22 +6241,22 @@ var IndexedDBPromptHelper = {
         accessKey: gNavigatorBundle.getString("offlineApps.dontAllow.accesskey"),
         callback() {
           observer.observe(null, responseTopic,
                            Ci.nsIPermissionManager.DENY_ACTION);
         }
       }
     ];
 
-    PopupNotifications.show(browser, topic, message,
-                            this._notificationIcon, mainAction,
-                            secondaryActions, {
-                              persistent: true,
-                              hideClose: true,
-                            });
+    PopupNotifications.show(
+      browser, topic, message, this._notificationIcon, mainAction, secondaryActions,
+      {
+        persistent: true,
+        hideClose: !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton"),
+      });
   }
 };
 
 function CanCloseWindow() {
   // Avoid redundant calls to canClose from showing multiple
   // PermitUnload dialogs.
   if (Services.startup.shuttingDown || window.skipNextCanClose) {
     return true;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -878,16 +878,29 @@
                   container="true">
               <menupopup id="BMB_unsortedBookmarksPopup"
                          placespopup="true"
                          context="placesContext"
                          onpopupshowing="if (!this.parentNode._placesView)
                                            new PlacesMenu(event, 'place:folder=UNFILED_BOOKMARKS',
                                                           PlacesUIUtils.getViewForNode(this.parentNode.parentNode).options);"/>
             </menu>
+            <menu id="BMB_mobileBookmarks"
+                  class="menu-iconic bookmark-item subviewbutton"
+                  label="&bookmarksMenuButton.mobile.label;"
+                  hidden="true"
+                  container="true">
+              <menupopup id="BMB_mobileBookmarksPopup"
+                         placespopup="true"
+                         context="placesContext"
+                         onpopupshowing="if (!this.parentNode._placesView)
+                                           new PlacesMenu(event, 'place:folder=MOBILE_BOOKMARKS',
+                                                          PlacesUIUtils.getViewForNode(this.parentNode.parentNode).options);"/>
+            </menu>
+
             <menuseparator/>
             <!-- Bookmarks menu items will go here -->
             <menuitem id="BMB_bookmarksShowAll"
                       class="subviewbutton panel-subview-footer"
                       label="&showAllBookmarks2.label;"
                       command="Browser:ShowAllBookmarks"
                       key="manBookmarkKb"/>
           </menupopup>
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -251,16 +251,17 @@ skip-if = true # bug 1057615
 [browser_bug655584.js]
 [browser_bug664672.js]
 [browser_bug676619.js]
 skip-if = os == "mac" # mac: Intermittent failures, bug 925225
 [browser_bug678392.js]
 skip-if = os == "mac" # Bug 1102331 - does focus things on the content window which break in e10s mode (still causes orange on Mac 10.10)
 [browser_bug710878.js]
 [browser_bug719271.js]
+skip-if = e10s # Bug 1315042
 [browser_bug724239.js]
 [browser_bug734076.js]
 [browser_bug735471.js]
 [browser_bug749738.js]
 [browser_bug763468_perwindowpb.js]
 [browser_bug767836_perwindowpb.js]
 [browser_bug817947.js]
 [browser_bug822367.js]
@@ -401,28 +402,30 @@ skip-if = os == "linux" # Bug 1329991 - 
 [browser_selectTabAtIndex.js]
 [browser_ssl_error_reports.js]
 [browser_star_hsts.js]
 [browser_subframe_favicons_not_used.js]
 [browser_syncui.js]
 skip-if = os == 'linux' # Bug 1304272
 [browser_tab_close_dependent_window.js]
 [browser_tabDrop.js]
+skip-if = e10s # Bug 1315042
 [browser_tabReorder.js]
 [browser_tab_detach_restore.js]
 [browser_tab_drag_drop_perwindow.js]
 [browser_tab_dragdrop.js]
 skip-if = buildapp == 'mulet' || (e10s && (debug || asan)) # Bug 1312436
 [browser_tab_dragdrop2.js]
 [browser_tabbar_big_widgets.js]
 skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
                                        # Disabled on OS X because of bug 967917
 [browser_tabfocus.js]
+skip-if = e10s # Bug 1315042
 [browser_tabkeynavigation.js]
-skip-if = (os == "mac" && !e10s) # Bug 1237713 - OSX eats keypresses for some reason
+skip-if = true || (os == "mac" && !e10s) # Bug 1315042, Bug 1237713 - OSX eats keypresses for some reason
 [browser_tabopen_reflows.js]
 [browser_tabs_close_beforeunload.js]
 support-files =
   close_beforeunload_opens_second_tab.html
   close_beforeunload.html
 [browser_tabs_isActive.js]
 [browser_tabs_owner.js]
 [browser_temporary_permissions.js]
--- a/browser/base/content/test/plugins/browser.ini
+++ b/browser/base/content/test/plugins/browser.ini
@@ -51,16 +51,17 @@ skip-if = toolkit == "gtk2" || toolkit =
 [browser_CTP_crashreporting.js]
 skip-if = !crashreporter
 [browser_CTP_data_urls.js]
 [browser_CTP_drag_drop.js]
 [browser_CTP_hide_overlay.js]
 [browser_CTP_iframe.js]
 [browser_CTP_multi_allow.js]
 [browser_CTP_nonplugins.js]
+skip-if = e10s # Bug 1315042
 [browser_CTP_notificationBar.js]
 [browser_CTP_outsideScrollArea.js]
 [browser_CTP_remove_navigate.js]
 [browser_CTP_resize.js]
 [browser_CTP_zoom.js]
 [browser_blocking.js]
 [browser_iterate_hidden_plugins.js]
 [browser_plugins_added_dynamically.js]
--- a/browser/base/content/test/popupNotifications/browser_popupNotification_2.js
+++ b/browser/base/content/test/popupNotifications/browser_popupNotification_2.js
@@ -193,20 +193,42 @@ var tests = [
       checkPopup(popup, this.notifyObj);
       let notification = popup.childNodes[0];
       EventUtils.synthesizeMouseAtCenter(notification.closebutton, {});
     },
     onHidden(popup) {
       ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered");
       this.notification.remove();
       ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
+      ok(!this.notifyObj.secondaryActionClicked, "secondary action not clicked");
+    }
+  },
+  // Test that notification close button calls secondary action instead of
+  // dismissal callback if privacy.permissionPrompts.showCloseButton is set.
+  { id: "Test#10",
+    run() {
+      Preferences.set("privacy.permissionPrompts.showCloseButton", true);
+      this.notifyObj = new BasicNotification(this.id);
+      this.notification = showNotification(this.notifyObj);
+    },
+    onShown(popup) {
+      checkPopup(popup, this.notifyObj);
+      let notification = popup.childNodes[0];
+      EventUtils.synthesizeMouseAtCenter(notification.closebutton, {});
+    },
+    onHidden(popup) {
+      ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback not triggered");
+      ok(this.notifyObj.secondaryActionClicked, "secondary action clicked");
+      Preferences.reset("privacy.permissionPrompts.showCloseButton");
+      this.notification.remove();
+      ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered");
     }
   },
   // Test notification when chrome is hidden
-  { id: "Test#10",
+  { id: "Test#11",
     run() {
       window.locationbar.visible = false;
       this.notifyObj = new BasicNotification(this.id);
       this.notification = showNotification(this.notifyObj);
     },
     onShown(popup) {
       checkPopup(popup, this.notifyObj);
       is(popup.anchorNode.className, "tabbrowser-tab", "notification anchored to tab");
--- a/browser/base/content/test/referrer/browser.ini
+++ b/browser/base/content/test/referrer/browser.ini
@@ -1,17 +1,19 @@
 [DEFAULT]
 support-files =
   file_referrer_policyserver.sjs
   file_referrer_policyserver_attr.sjs
   file_referrer_testserver.sjs
   head.js
 
 [browser_referrer_middle_click.js]
+skip-if = true # Bug 1315042
 [browser_referrer_middle_click_in_container.js]
+skip-if = true # Bug 1315042
 [browser_referrer_open_link_in_private.js]
 skip-if = os == 'linux' # Bug 1145199
 [browser_referrer_open_link_in_tab.js]
 skip-if = os == 'linux' # Bug 1144816
 [browser_referrer_open_link_in_window.js]
 skip-if = os == 'linux' # Bug 1145199
 [browser_referrer_open_link_in_window_in_container.js]
 skip-if = os == 'linux' # Bug 1145199
--- a/browser/base/content/test/tabcrashed/browser.ini
+++ b/browser/base/content/test/tabcrashed/browser.ini
@@ -3,11 +3,11 @@ support-files =
   head.js
 [browser_shown.js]
 skip-if = !e10s || !crashreporter
 [browser_clearEmail.js]
 skip-if = !e10s || !crashreporter
 [browser_showForm.js]
 skip-if = !e10s || !crashreporter
 [browser_withoutDump.js]
-skip-if = !e10s
+skip-if = !e10s || !crashreporter
 [browser_autoSubmitRequest.js]
 skip-if = !e10s || !crashreporter
--- a/browser/base/content/test/urlbar/browser.ini
+++ b/browser/base/content/test/urlbar/browser.ini
@@ -24,16 +24,17 @@ support-files =
 [browser_bug1024133-switchtab-override-keynav.js]
 [browser_bug1025195_switchToTabHavingURI_aOpenParams.js]
 [browser_bug1070778.js]
 [browser_bug1225194-remotetab.js]
 [browser_bug304198.js]
 [browser_bug556061.js]
 subsuite = clipboard
 [browser_bug562649.js]
+skip-if = e10s # Bug 1315042
 [browser_bug623155.js]
 support-files =
   redirect_bug623155.sjs
 [browser_bug783614.js]
 [browser_canonizeURL.js]
 [browser_dragdropURL.js]
 [browser_locationBarCommand.js]
 [browser_locationBarExternalLoad.js]
--- a/browser/base/content/test/webrtc/browser.ini
+++ b/browser/base/content/test/webrtc/browser.ini
@@ -7,13 +7,14 @@ support-files =
 
 [browser_devices_get_user_media.js]
 skip-if = (os == "linux" && debug) # linux: bug 976544
 [browser_devices_get_user_media_anim.js]
 [browser_devices_get_user_media_in_frame.js]
 [browser_devices_get_user_media_screen.js]
 skip-if = (e10s && debug) || (os == "linux" && !debug) # bug 1320754 for e10s debug, and bug 1320994 for linux opt
 [browser_devices_get_user_media_tear_off_tab.js]
+skip-if = e10s # Bug 1315042
 [browser_devices_get_user_media_unprompted_access.js]
 [browser_devices_get_user_media_unprompted_access_in_frame.js]
 [browser_devices_get_user_media_unprompted_access_tear_off_tab.js]
 skip-if = (os == "linux") # linux: bug 1331616
 [browser_webrtc_hooks.js]
--- a/browser/components/contextualidentity/test/browser/browser.ini
+++ b/browser/components/contextualidentity/test/browser/browser.ini
@@ -8,16 +8,17 @@ support-files =
   worker.js
 
 [browser_aboutURLs.js]
 [browser_eme.js]
 [browser_favicon.js]
 [browser_forgetaboutsite.js]
 [browser_forgetAPI_cookie_getCookiesWithOriginAttributes.js]
 [browser_forgetAPI_EME_forgetThisSite.js]
+skip-if = e10s # Bug 1315042
 [browser_forgetAPI_quota_clearStoragesForPrincipal.js]
 [browser_newtabButton.js]
 [browser_usercontext.js]
 [browser_usercontextid_tabdrop.js]
 skip-if = os == "mac" || os == "win" # Intermittent failure - bug 1268276
 [browser_windowName.js]
 tags = openwindow
 [browser_windowOpen.js]
--- a/browser/components/preferences/in-content/tests/browser_security.js
+++ b/browser/components/preferences/in-content/tests/browser_security.js
@@ -45,20 +45,20 @@ add_task(function*() {
     // check if the other checkboxes have updated
     checked = checkbox.checked;
     is(blockDownloads.hasAttribute("disabled"), !checked, "block downloads checkbox is set correctly");
     is(blockUncommon.hasAttribute("disabled"), !checked || !blockDownloads.checked, "block uncommon checkbox is set correctly");
 
     yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
   }
 
-  yield checkPrefSwitch(true, true);
-  yield checkPrefSwitch(false, true);
-  yield checkPrefSwitch(true, false);
-  yield checkPrefSwitch(false, false);
+  yield* checkPrefSwitch(true, true);
+  yield* checkPrefSwitch(false, true);
+  yield* checkPrefSwitch(true, false);
+  yield* checkPrefSwitch(false, false);
 });
 
 // test the download protection preference
 add_task(function*() {
   function* checkPrefSwitch(val) {
     Services.prefs.setBoolPref("browser.safebrowsing.downloads.enabled", val);
 
     yield openPreferencesViaOpenPreferencesAPI("security", undefined, { leaveOpen: true });
@@ -79,18 +79,18 @@ add_task(function*() {
        "safebrowsing.downloads preference is set correctly");
 
     // check if the uncommon warning checkbox has updated
     is(blockUncommon.hasAttribute("disabled"), val, "block uncommon checkbox is set correctly");
 
     yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
   }
 
-  yield checkPrefSwitch(true);
-  yield checkPrefSwitch(false);
+  yield* checkPrefSwitch(true);
+  yield* checkPrefSwitch(false);
 });
 
 // test the unwanted/uncommon software warning preference
 add_task(function*() {
   function* checkPrefSwitch(val1, val2) {
     Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.block_potentially_unwanted", val1);
     Services.prefs.setBoolPref("browser.safebrowsing.downloads.remote.block_uncommon", val2);
 
--- a/browser/components/privatebrowsing/test/browser/browser.ini
+++ b/browser/components/privatebrowsing/test/browser/browser.ini
@@ -21,16 +21,17 @@ support-files =
 [browser_privatebrowsing_DownloadLastDirWithCPS.js]
 [browser_privatebrowsing_about.js]
 tags = trackingprotection
 [browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js]
 [browser_privatebrowsing_aboutSessionRestore.js]
 [browser_privatebrowsing_cache.js]
 [browser_privatebrowsing_certexceptionsui.js]
 [browser_privatebrowsing_concurrent.js]
+skip-if = e10s # Bug 1315042
 [browser_privatebrowsing_context_and_chromeFlags.js]
 [browser_privatebrowsing_crh.js]
 [browser_privatebrowsing_downloadLastDir.js]
 [browser_privatebrowsing_downloadLastDir_c.js]
 [browser_privatebrowsing_downloadLastDir_toggle.js]
 [browser_privatebrowsing_favicon.js]
 [browser_privatebrowsing_geoprompt.js]
 [browser_privatebrowsing_lastpbcontextexited.js]
--- a/browser/config/version.txt
+++ b/browser/config/version.txt
@@ -1,1 +1,1 @@
-53.0a1
+54.0a1
--- a/browser/config/version_display.txt
+++ b/browser/config/version_display.txt
@@ -1,1 +1,1 @@
-53.0a1
+54.0a1
--- a/browser/installer/allowed-dupes.mn
+++ b/browser/installer/allowed-dupes.mn
@@ -43,18 +43,20 @@ browser/chrome/devtools/modules/devtools
 browser/chrome/devtools/modules/devtools/client/inspector/inspector.xhtml
 browser/chrome/devtools/modules/devtools/client/jsonview/css/controls.png
 browser/chrome/devtools/modules/devtools/client/jsonview/css/controls@2x.png
 browser/chrome/devtools/modules/devtools/client/memory/initializer.js
 browser/chrome/devtools/modules/devtools/client/projecteditor/lib/helpers/readdir.js
 browser/chrome/devtools/modules/devtools/client/shared/frame-script-utils.js
 browser/chrome/devtools/modules/devtools/client/shared/theme-switching.js
 browser/chrome/devtools/modules/devtools/client/themes/common.css
+browser/chrome/devtools/modules/devtools/client/themes/toolbars.css
 browser/chrome/devtools/modules/devtools/client/themes/variables.css
 browser/chrome/devtools/skin/common.css
+browser/chrome/devtools/skin/toolbars.css
 browser/chrome/devtools/skin/images/command-scratchpad.svg
 browser/chrome/devtools/skin/images/controls.png
 browser/chrome/devtools/skin/images/controls@2x.png
 browser/chrome/devtools/skin/images/debugger-blackbox.svg
 browser/chrome/devtools/skin/images/debugger-prettyprint.svg
 browser/chrome/devtools/skin/images/filetypes/store.svg
 browser/chrome/devtools/skin/images/itemToggle.svg
 browser/chrome/devtools/skin/images/security-state-broken.svg
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -179,16 +179,17 @@ These should match what Safari and other
 <!ENTITY shareVideo.accesskey "r">
 <!ENTITY feedsMenu2.label "Subscribe to This Page">
 <!ENTITY subscribeToPageMenupopup.label "Subscribe to This Page">
 <!ENTITY subscribeToPageMenuitem.label "Subscribe to This Page…">
 <!ENTITY addCurPagesCmd.label "Bookmark All Tabs…">
 <!ENTITY showAllBookmarks2.label "Show All Bookmarks">
 <!ENTITY recentBookmarks.label "Recently Bookmarked">
 <!ENTITY otherBookmarksCmd.label "Other Bookmarks">
+<!ENTITY mobileBookmarksCmd.label "Mobile Bookmarks">
 <!ENTITY bookmarksToolbarChevron.tooltip "Show more bookmarks">
 <!ENTITY showRecentlyBookmarked.label     "Show Recently Bookmarked">
 <!ENTITY showRecentlyBookmarked.accesskey "h">
 <!ENTITY hideRecentlyBookmarked.label     "Hide Recently Bookmarked">
 <!ENTITY hideRecentlyBookmarked.accesskey "H">
 
 <!ENTITY backCmd.label                "Back">
 <!ENTITY backButton.tooltip           "Go back one page">
@@ -240,16 +241,17 @@ These should match what Safari and other
 <!-- Toolbar items --> 
 <!ENTITY homeButton.label             "Home">
 
 <!ENTITY bookmarksButton.label          "Bookmarks">
 <!ENTITY bookmarksCmd.commandkey "b">
 
 <!ENTITY bookmarksMenuButton.label          "Bookmarks">
 <!ENTITY bookmarksMenuButton.other.label "Other Bookmarks">
+<!ENTITY bookmarksMenuButton.mobile.label "Mobile Bookmarks">
 <!ENTITY viewBookmarksSidebar2.label        "View Bookmarks Sidebar">
 <!ENTITY viewBookmarksToolbar.label         "View Bookmarks Toolbar">
 
 <!ENTITY containersMenu.label "Containers">
 
 <!-- LOCALIZATION NOTE (bookmarksSidebarGtkCmd.commandkey): This command
   -  key should not contain the letters A-F, since these are reserved
   -  shortcut keys on Linux. -->
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -841,24 +841,24 @@ pendingCrashReports.alwaysSend = Always 
 decoder.noCodecs.button = Learn how
 decoder.noCodecs.accesskey = L
 decoder.noCodecs.message = To play video, you may need to install Microsoft’s Media Feature Pack.
 decoder.noCodecsLinux.message = To play video, you may need to install the required video codecs.
 decoder.noHWAcceleration.message = To improve video quality, you may need to install Microsoft’s Media Feature Pack.
 decoder.noPulseAudio.message = To play audio, you may need to install the required PulseAudio software.
 decoder.unsupportedLibavcodec.message = libavcodec may be vulnerable or is not supported, and should be updated to play video.
 
-# LOCALIZATION NOTE (captivePortal.infoMessage2):
+# LOCALIZATION NOTE (captivePortal.infoMessage3):
 # Shown in a notification bar when we detect a captive portal is blocking network access
 # and requires the user to log in before browsing.
-captivePortal.infoMessage2 = This network may require you to log in to use the internet.
-# LOCALIZATION NOTE (captivePortal.showLoginPage):
+captivePortal.infoMessage3 = You must log in to this network before you can access the Internet.
+# LOCALIZATION NOTE (captivePortal.showLoginPage2):
 # The label for a button shown in the info bar in all tabs except the login page tab.
 # The button shows the portal login page tab when clicked.
-captivePortal.showLoginPage = Show Login Page
+captivePortal.showLoginPage2 = Open Network Login Page
 
 permissions.remove.tooltip = Clear this permission and ask again
 
 # LOCALIZATION NOTE (aboutDialog.architecture.*):
 # The sixtyFourBit and thirtyTwoBit strings describe the architecture of the
 # current Firefox build: 32-bit or 64-bit. These strings are used in parentheses
 # between the Firefox version and the "What's new" link in the About dialog,
 # e.g.: "48.0.2 (32-bit) <What's new>" or "51.0a1 (2016-09-05) (64-bit)".
--- a/browser/locales/en-US/chrome/overrides/netError.dtd
+++ b/browser/locales/en-US/chrome/overrides/netError.dtd
@@ -47,21 +47,21 @@
 ">
 
 <!ENTITY generic.title "Oops.">
 <!ENTITY generic.longDesc "
 <p>&brandShortName; can’t load this page for some reason.</p>
 ">
 
 <!ENTITY captivePortal.title "Log in to network">
-<!ENTITY captivePortal.longDesc "
-<p>This network may require you to log in to access the internet.</p>
+<!ENTITY captivePortal.longDesc2 "
+<p>You must log in to this network before you can access the Internet.</p>
 ">
 
-<!ENTITY openPortalLoginPage.label "Open Login Page">
+<!ENTITY openPortalLoginPage.label2 "Open Network Login Page">
 
 <!ENTITY malformedURI.title "The address isn’t valid">
 <!ENTITY malformedURI.longDesc "
 <ul>
   <li>Web addresses are usually written like
     <strong>http://www.example.com/</strong></li>
   <li>Make sure that you’re using forward slashes (i.e.
     <strong>/</strong>).</li>
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -336,19 +336,19 @@ this.PermissionPromptPrototype = {
                      popupNotificationActions[0] : null;
     let secondaryActions = popupNotificationActions.splice(1);
 
     let options = this.popupOptions;
 
     if (!options.hasOwnProperty("displayURI") || options.displayURI) {
       options.displayURI = this.principal.URI;
     }
-    // Permission prompts are always persistent and don't have a close button.
+    // Permission prompts are always persistent; the close button is controlled by a pref.
     options.persistent = true;
-    options.hideClose = true;
+    options.hideClose = !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton");
 
     this.onBeforeShow();
     chromeWin.PopupNotifications.show(this.browser,
                                       this.notificationID,
                                       this.message,
                                       this.anchorID,
                                       mainAction,
                                       secondaryActions,
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -439,17 +439,17 @@ function prompt(aBrowser, aRequest) {
   } else if (sharingAudio) {
     reasonForNoPermanentAllow = "getUserMedia.reasonForNoPermanentAllow.audio";
   } else if (!aRequest.secure) {
     reasonForNoPermanentAllow = "getUserMedia.reasonForNoPermanentAllow.insecure";
   }
 
   let options = {
     persistent: true,
-    hideClose: true,
+    hideClose: !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton"),
     checkbox: {
       label: stringBundle.getString("getUserMedia.remember"),
       checkedState: reasonForNoPermanentAllow ? {
         disableMainAction: true,
         warningLabel: stringBundle.getFormattedString(reasonForNoPermanentAllow,
                                                       [productName])
       } : undefined,
     },
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -1190,17 +1190,18 @@ menuitem.panel-subview-footer@menuStateA
   /* Hide bottom separator as the styled footer includes a top border serving the same purpose */
   display: none;
 }
 
 /* Popups with only one item don't have a footer */
 #BMB_bookmarksPopup menupopup[placespopup=true][singleitempopup=true] > hbox > .popup-internal-box > .arrowscrollbox-scrollbox > .scrollbox-innerbox,
 /* These popups never have a footer */
 #BMB_bookmarksToolbarPopup > hbox > .popup-internal-box > .arrowscrollbox-scrollbox > .scrollbox-innerbox,
-#BMB_unsortedBookmarksPopup > hbox > .popup-internal-box > .arrowscrollbox-scrollbox > .scrollbox-innerbox {
+#BMB_unsortedBookmarksPopup > hbox > .popup-internal-box > .arrowscrollbox-scrollbox > .scrollbox-innerbox,
+#BMB_mobileBookmarksPopup > hbox > .popup-internal-box > .arrowscrollbox-scrollbox > .scrollbox-innerbox {
   /* And so they need some bottom padding: */
   padding-bottom: 4px;
 }
 
 /* Disabled (empty) item is always alone and never has an icon, so fix its left padding */
 #BMB_bookmarksPopup menupopup[emptyplacesresult] .bookmark-item.subviewbutton {
   padding-left: 6px;
 }
--- a/config/milestone.txt
+++ b/config/milestone.txt
@@ -5,9 +5,9 @@
 #    x.x.x.x
 #    x.x.x+
 #
 # Referenced by milestone.py.
 # Hopefully I'll be able to automate replacement of *all*
 # hardcoded milestones in the tree from these two files.
 #--------------------------------------------------------
 
-53.0a1
+54.0a1
--- a/devtools/client/aboutdebugging/test/browser_service_workers_status.js
+++ b/devtools/client/aboutdebugging/test/browser_service_workers_status.js
@@ -37,19 +37,21 @@ add_task(function* () {
 
   // Check that the service worker appears in the UI
   let names = [...document.querySelectorAll("#service-workers .target-name")];
   let name = names.filter(element => element.textContent === SERVICE_WORKER)[0];
   ok(name, "Found the service worker in the list");
 
   let targetElement = name.parentNode.parentNode;
   let status = targetElement.querySelector(".target-status");
-  is(status.textContent, "Registering", "Service worker is currently registering");
+  // We might miss the registering state in some setup...
+  if (status.textContent == "Registering") {
+    yield waitForMutation(serviceWorkersElement, { childList: true, subtree: true });
+  }
 
-  yield waitForMutation(serviceWorkersElement, { childList: true, subtree: true });
   is(status.textContent, "Running", "Service worker is currently running");
 
   yield waitForMutation(serviceWorkersElement, { attributes: true, subtree: true });
   is(status.textContent, "Stopped", "Service worker is currently stopped");
 
   try {
     yield unregisterServiceWorker(swTab, serviceWorkersElement);
     ok(true, "Service worker unregistered");
--- a/devtools/client/jsonview/converter-child.js
+++ b/devtools/client/jsonview/converter-child.js
@@ -209,16 +209,17 @@ Converter.prototype = {
   },
 
   toHTML: function (json, headers, title) {
     let themeClassName = "theme-" + JsonViewUtils.getCurrentTheme();
     let clientBaseUrl = "resource://devtools/client/";
     let baseUrl = clientBaseUrl + "jsonview/";
     let themeVarsUrl = clientBaseUrl + "themes/variables.css";
     let commonUrl = clientBaseUrl + "themes/common.css";
+    let toolbarsUrl = clientBaseUrl + "themes/toolbars.css";
 
     let os;
     let platform = Services.appinfo.OS;
     if (platform.startsWith("WINNT")) {
       os = "win";
     } else if (platform.startsWith("Darwin")) {
       os = "mac";
     } else {
@@ -233,16 +234,18 @@ Converter.prototype = {
       "<html platform=\"" + os + "\" class=\"" + themeClassName +
         "\" dir=\"" + dir + "\">" +
       "<head><title>" + this.htmlEncode(title) + "</title>" +
       "<base href=\"" + this.htmlEncode(baseUrl) + "\">" +
       "<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
         themeVarsUrl + "\">" +
       "<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
         commonUrl + "\">" +
+      "<link rel=\"stylesheet\" type=\"text/css\" href=\"" +
+        toolbarsUrl + "\">" +
       "<link rel=\"stylesheet\" type=\"text/css\" href=\"css/main.css\">" +
       "<script data-main=\"viewer-config\" src=\"lib/require.js\"></script>" +
       "</head><body>" +
       "<div id=\"content\"></div>" +
       "<div id=\"json\">" + this.htmlEncode(json) + "</div>" +
       "<div id=\"headers\">" + this.htmlEncode(headers) + "</div>" +
       "</body></html>";
   },
--- a/devtools/client/locales/en-US/webconsole.properties
+++ b/devtools/client/locales/en-US/webconsole.properties
@@ -197,17 +197,16 @@ webconsole.find.key=CmdOrCtrl+F
 # Key shortcut used to close the Browser console (doesn't work in regular web console)
 webconsole.close.key=CmdOrCtrl+W
 
 # LOCALIZATION NOTE (webconsole.clear.key*)
 # Key shortcut used to clear the console output
 webconsole.clear.key=Ctrl+Shift+L
 webconsole.clear.keyOSX=Ctrl+L
 
-
 # LOCALIZATION NOTE (webconsole.menu.copyURL.label)
 # Label used for a context-menu item displayed for network message logs. Clicking on it
 # copies the URL displayed in the message to the clipboard.
 webconsole.menu.copyURL.label=Copy Link Location
 webconsole.menu.copyURL.accesskey=a
 
 # LOCALIZATION NOTE (webconsole.menu.openURL.label)
 # Label used for a context-menu item displayed for network message logs. Clicking on it
@@ -234,8 +233,66 @@ webconsole.menu.copy.label=Copy
 webconsole.menu.copy.accesskey=C
 
 # LOCALIZATION NOTE (webconsole.menu.selectAll.label)
 # Label used for a context-menu item that will select all the content of the webconsole
 # output.
 webconsole.menu.selectAll.label=Select all
 webconsole.menu.selectAll.accesskey=A
 
+# LOCALIZATION NOTE (webconsole.clearButton.tooltip)
+# Label used for the tooltip on the clear logs button in the console top toolbar bar.
+# Clicking on it will clear the content of the console.
+webconsole.clearButton.tooltip=Clear the Web Console output
+
+# LOCALIZATION NOTE (webconsole.toggleFilterButton.tooltip)
+# Label used for the tooltip on the toggle filter bar button in the console top
+# toolbar bar. Clicking on it will toggle the visibility of an additional bar which
+# contains filter buttons.
+webconsole.toggleFilterButton.tooltip=Toggle filter bar
+
+# LOCALIZATION NOTE (webconsole.filterInput.placeholder)
+# Label used for for the placeholder on the filter input, in the console top toolbar.
+webconsole.filterInput.placeholder=Filter output
+
+# LOCALIZATION NOTE (webconsole.errorsFilterButton.label)
+# Label used as the text of the "Errors" button in the additional filter toolbar.
+# It shows or hides error messages, either inserted in the page using
+# console.error() or as a result of a javascript error..
+webconsole.errorsFilterButton.label=Errors
+
+# LOCALIZATION NOTE (webconsole.warningsFilterButton.label)
+# Label used as the text of the "Warnings" button in the additional filter toolbar.
+# It shows or hides warning messages, inserted in the page using console.warn().
+webconsole.warningsFilterButton.label=Warnings
+
+# LOCALIZATION NOTE (webconsole.logsFilterButton.label)
+# Label used as the text of the "Logs" button in the additional filter toolbar.
+# It shows or hides log messages, inserted in the page using console.log().
+webconsole.logsFilterButton.label=Logs
+
+# LOCALIZATION NOTE (webconsole.infoFilterButton.label)
+# Label used as the text of the "Info" button in the additional filter toolbar.
+# It shows or hides info messages, inserted in the page using console.info().
+webconsole.infoFilterButton.label=Info
+
+# LOCALIZATION NOTE (webconsole.debugFilterButton.label)
+# Label used as the text of the "Debug" button in the additional filter toolbar.
+# It shows or hides debug messages, inserted in the page using console.debug().
+webconsole.debugFilterButton.label=Debug
+
+# LOCALIZATION NOTE (webconsole.cssFilterButton.label)
+# Label used as the text of the "CSS" button in the additional filter toolbar.
+# It shows or hides CSS warning messages, inserted in the page by the browser
+# when there are CSS errors in the page.
+webconsole.cssFilterButton.label=CSS
+
+# LOCALIZATION NOTE (webconsole.xhrFilterButton.label)
+# Label used as the text of the "XHR" button in the additional filter toolbar.
+# It shows or hides messages displayed when the page makes an XMLHttpRequest or
+# a fetch call.
+webconsole.xhrFilterButton.label=XHR
+
+# LOCALIZATION NOTE (webconsole.requestsFilterButton.label)
+# Label used as the text of the "Requests" button in the additional filter toolbar.
+# It shows or hides messages displayed when the page makes a network call, for example
+# when an image or a scripts is requested.
+webconsole.requestsFilterButton.label=Requests
--- a/devtools/client/shared/components/tabs/tabbar.css
+++ b/devtools/client/shared/components/tabs/tabbar.css
@@ -24,20 +24,16 @@
   height: 23px;
 }
 
 /* Firebug theme is using slightly different height. */
 .theme-firebug .tabs .tabs-navigation {
   height: 28px;
 }
 
-.tabs .tabs-menu-item a {
-  cursor: default;
-}
-
 /* The tab takes entire horizontal space and individual tabs
   should stretch accordingly. Use flexbox for the behavior.
   Use also `overflow: hidden` so, 'overflow' and 'underflow'
   events are fired (it's utilized by the all-tabs-menu). */
 .tabs .tabs-navigation .tabs-menu {
   overflow: hidden;
   display: flex;
 }
--- a/devtools/client/shared/components/tabs/tabs.css
+++ b/devtools/client/shared/components/tabs/tabs.css
@@ -25,16 +25,20 @@
   display: block;
   color: #A9A9A9;
   padding: 4px 8px;
   border: 1px solid transparent;
   text-decoration: none;
   white-space: nowrap;
 }
 
+.tabs .tabs-menu-item a {
+  cursor: default;
+}
+
 /* Make sure panel content takes entire vertical space.
   (minus the height of the tab bar) */
 .tabs .panels {
   height: calc(100% - 24px);
 }
 
 .tabs .tab-panel {
   height: 100%;
--- a/devtools/client/themes/moz.build
+++ b/devtools/client/themes/moz.build
@@ -6,10 +6,11 @@
 
 DIRS += [
     'audio',
 ]
 
 DevToolsModules(
     'common.css',
     'splitters.css',
+    'toolbars.css',
     'variables.css',
 )
--- a/devtools/client/webconsole/new-console-output/components/filter-bar.js
+++ b/devtools/client/webconsole/new-console-output/components/filter-bar.js
@@ -7,19 +7,23 @@ const {
   createFactory,
   createClass,
   DOM: dom,
   PropTypes
 } = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters");
 const { getAllUi } = require("devtools/client/webconsole/new-console-output/selectors/ui");
-const { filterTextSet, filtersClear } = require("devtools/client/webconsole/new-console-output/actions/index");
-const { messagesClear } = require("devtools/client/webconsole/new-console-output/actions/index");
-const uiActions = require("devtools/client/webconsole/new-console-output/actions/index");
+const {
+  filterTextSet,
+  filtersClear,
+  filterBarToggle,
+  messagesClear
+} = require("devtools/client/webconsole/new-console-output/actions/index");
+const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
 const {
   MESSAGE_LEVEL
 } = require("../constants");
 const FilterButton = createFactory(require("devtools/client/webconsole/new-console-output/components/filter-button"));
 
 const FilterBar = createClass({
 
   displayName: "FilterBar",
@@ -38,17 +42,17 @@ const FilterBar = createClass({
       this.wrapperNode.querySelector(".text-filter"));
   },
 
   onClickMessagesClear: function () {
     this.props.dispatch(messagesClear());
   },
 
   onClickFilterBarToggle: function () {
-    this.props.dispatch(uiActions.filterBarToggle());
+    this.props.dispatch(filterBarToggle());
   },
 
   onClickFiltersClear: function () {
     this.props.dispatch(filtersClear());
   },
 
   onSearchInput: function (e) {
     this.props.dispatch(filterTextSet(e.target.value));
@@ -57,109 +61,92 @@ const FilterBar = createClass({
   render() {
     const {dispatch, filter, ui} = this.props;
     let filterBarVisible = ui.filterBarVisible;
     let children = [];
 
     children.push(dom.div({className: "devtools-toolbar webconsole-filterbar-primary"},
       dom.button({
         className: "devtools-button devtools-clear-icon",
-        title: "Clear output",
+        title: l10n.getStr("webconsole.clearButton.tooltip"),
         onClick: this.onClickMessagesClear
       }),
       dom.button({
         className: "devtools-button devtools-filter-icon" + (
           filterBarVisible ? " checked" : ""),
-        title: "Toggle filter bar",
+        title: l10n.getStr("webconsole.toggleFilterButton.tooltip"),
         onClick: this.onClickFilterBarToggle
       }),
       dom.input({
         className: "devtools-plaininput text-filter",
         type: "search",
         value: filter.text,
-        placeholder: "Filter output",
+        placeholder: l10n.getStr("webconsole.filterInput.placeholder"),
         onInput: this.onSearchInput
       })
     ));
 
     if (filterBarVisible) {
       children.push(
         dom.div({className: "devtools-toolbar webconsole-filterbar-secondary"},
           FilterButton({
             active: filter.error,
-            label: "Errors",
+            label: l10n.getStr("webconsole.errorsFilterButton.label"),
             filterKey: MESSAGE_LEVEL.ERROR,
             dispatch
           }),
           FilterButton({
             active: filter.warn,
-            label: "Warnings",
+            label: l10n.getStr("webconsole.warningsFilterButton.label"),
             filterKey: MESSAGE_LEVEL.WARN,
             dispatch
           }),
           FilterButton({
             active: filter.log,
-            label: "Logs",
+            label: l10n.getStr("webconsole.logsFilterButton.label"),
             filterKey: MESSAGE_LEVEL.LOG,
             dispatch
           }),
           FilterButton({
             active: filter.info,
-            label: "Info",
+            label: l10n.getStr("webconsole.infoFilterButton.label"),
             filterKey: MESSAGE_LEVEL.INFO,
             dispatch
           }),
           FilterButton({
             active: filter.debug,
-            label: "Debug",
+            label: l10n.getStr("webconsole.debugFilterButton.label"),
             filterKey: MESSAGE_LEVEL.DEBUG,
             dispatch
           }),
           dom.span({
             className: "devtools-separator",
           }),
           FilterButton({
             active: filter.css,
-            label: "CSS",
+            label: l10n.getStr("webconsole.cssFilterButton.label"),
             filterKey: "css",
             dispatch
           }),
           FilterButton({
             active: filter.netxhr,
-            label: "XHR",
+            label: l10n.getStr("webconsole.xhrFilterButton.label"),
             filterKey: "netxhr",
             dispatch
           }),
           FilterButton({
             active: filter.net,
-            label: "Requests",
+            label: l10n.getStr("webconsole.requestsFilterButton.label"),
             filterKey: "net",
             dispatch
           })
         )
       );
     }
 
-    if (ui.filteredMessageVisible) {
-      children.push(
-        dom.div({className: "devtools-toolbar"},
-          dom.span({
-            className: "clear"},
-            "You have filters set that may hide some results. " +
-            "Learn more about our filtering syntax ",
-            dom.a({}, "here"),
-            "."),
-          dom.button({
-            className: "menu-filter-button",
-            onClick: this.onClickFiltersClear
-          }, "Remove filters")
-        )
-      );
-    }
-
     return (
       dom.div({
         className: "webconsole-filteringbar-wrapper",
         ref: node => {
           this.wrapperNode = node;
         }
       }, ...children
       )
--- a/devtools/client/webconsole/new-console-output/test/components/filter-bar.test.js
+++ b/devtools/client/webconsole/new-console-output/test/components/filter-bar.test.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 const expect = require("expect");
 const sinon = require("sinon");
 const { render, mount } = require("enzyme");
 
-const { createFactory } = require("devtools/client/shared/vendor/react");
+const { createFactory, DOM } = require("devtools/client/shared/vendor/react");
 const Provider = createFactory(require("react-redux").Provider);
 
 const FilterButton = createFactory(require("devtools/client/webconsole/new-console-output/components/filter-button"));
 const FilterBar = createFactory(require("devtools/client/webconsole/new-console-output/components/filter-bar"));
 const { getAllUi } = require("devtools/client/webconsole/new-console-output/selectors/ui");
 const {
   MESSAGES_CLEAR,
   MESSAGE_LEVEL
@@ -27,17 +27,17 @@ describe("FilterBar component:", () => {
     const wrapper = render(Provider({store}, FilterBar({ serviceContainer })));
     const toolbar = wrapper.find(
       ".devtools-toolbar.webconsole-filterbar-primary"
     );
 
     // Clear button
     expect(toolbar.children().eq(0).attr("class"))
       .toBe("devtools-button devtools-clear-icon");
-    expect(toolbar.children().eq(0).attr("title")).toBe("Clear output");
+    expect(toolbar.children().eq(0).attr("title")).toBe("Clear the Web Console output");
 
     // Filter bar toggle
     expect(toolbar.children().eq(1).attr("class"))
       .toBe("devtools-button devtools-filter-icon");
     expect(toolbar.children().eq(1).attr("title")).toBe("Toggle filter bar");
 
     // Text filter
     expect(toolbar.children().eq(2).attr("class"))
@@ -53,32 +53,38 @@ describe("FilterBar component:", () => {
     expect(getAllUi(store.getState()).filterBarVisible).toBe(false);
 
     const wrapper = mount(Provider({store}, FilterBar({ serviceContainer })));
     wrapper.find(".devtools-filter-icon").simulate("click");
 
     expect(getAllUi(store.getState()).filterBarVisible).toBe(true);
 
     // Buttons are displayed
-    const buttonProps = {
-      active: true,
-      dispatch: store.dispatch
-    };
-    const logButton = FilterButton(Object.assign({}, buttonProps,
-      { label: "Logs", filterKey: MESSAGE_LEVEL.LOG }));
-    const debugButton = FilterButton(Object.assign({}, buttonProps,
-      { label: "Debug", filterKey: MESSAGE_LEVEL.DEBUG }));
-    const infoButton = FilterButton(Object.assign({}, buttonProps,
-      { label: "Info", filterKey: MESSAGE_LEVEL.INFO }));
-    const warnButton = FilterButton(Object.assign({}, buttonProps,
-      { label: "Warnings", filterKey: MESSAGE_LEVEL.WARN }));
-    const errorButton = FilterButton(Object.assign({}, buttonProps,
-      { label: "Errors", filterKey: MESSAGE_LEVEL.ERROR }));
-    let buttons = [errorButton, warnButton, logButton, infoButton, debugButton];
-    expect(wrapper.contains(buttons)).toBe(true);
+    const filterBtn = props => FilterButton(
+      Object.assign({}, {
+        active: true,
+        dispatch: store.dispatch
+      }, props)
+    );
+
+    let buttons = [
+      filterBtn({ label: "Errors", filterKey: MESSAGE_LEVEL.ERROR }),
+      filterBtn({ label: "Warnings", filterKey: MESSAGE_LEVEL.WARN }),
+      filterBtn({ label: "Logs", filterKey: MESSAGE_LEVEL.LOG }),
+      filterBtn({ label: "Info", filterKey: MESSAGE_LEVEL.INFO }),
+      filterBtn({ label: "Debug", filterKey: MESSAGE_LEVEL.DEBUG }),
+      DOM.span({
+        className: "devtools-separator",
+      }),
+      filterBtn({ label: "CSS", filterKey: "css" }),
+      filterBtn({ label: "XHR", filterKey: "netxhr", active: false }),
+      filterBtn({ label: "Requests", filterKey: "net", active: false }),
+    ];
+
+    expect(wrapper.containsAllMatchingElements(buttons)).toBe(true);
   });
 
   it("fires MESSAGES_CLEAR action when clear button is clicked", () => {
     const store = setupStore([]);
     store.dispatch = sinon.spy();
 
     const wrapper = mount(Provider({store}, FilterBar({ serviceContainer })));
     wrapper.find(".devtools-clear-icon").simulate("click");
--- a/devtools/client/webconsole/new-console-output/test/fixtures/L10n.js
+++ b/devtools/client/webconsole/new-console-output/test/fixtures/L10n.js
@@ -10,16 +10,38 @@ class L10n {
       case "level.error":
         return "Error";
       case "consoleCleared":
         return "Console was cleared.";
       case "webConsoleXhrIndicator":
         return "XHR";
       case "webConsoleMoreInfoLabel":
         return "Learn More";
+      case "webconsole.clearButton.tooltip":
+        return "Clear the Web Console output";
+      case "webconsole.toggleFilterButton.tooltip":
+        return "Toggle filter bar";
+      case "webconsole.filterInput.placeholder":
+        return "Filter output";
+      case "webconsole.errorsFilterButton.label":
+        return "Errors";
+      case "webconsole.warningsFilterButton.label":
+        return "Warnings";
+      case "webconsole.logsFilterButton.label":
+        return "Logs";
+      case "webconsole.infoFilterButton.label":
+        return "Info";
+      case "webconsole.debugFilterButton.label":
+        return "Debug";
+      case "webconsole.cssFilterButton.label":
+        return "CSS";
+      case "webconsole.xhrFilterButton.label":
+        return "XHR";
+      case "webconsole.requestsFilterButton.label":
+        return "Requests";
       default:
         return str;
     }
   }
 
   getFormatStr(str) {
     return this.getStr(str);
   }
--- a/docshell/test/browser/browser_grouped_shistory_dead_navigate.js
+++ b/docshell/test/browser/browser_grouped_shistory_dead_navigate.js
@@ -1,11 +1,12 @@
 add_task(function* () {
   yield SpecialPowers.pushPrefEnv({
-    set: [["browser.groupedhistory.enabled", true]]
+    set: [["browser.groupedhistory.enabled", true],
+          ["dom.ipc.processCount", 1]]
   });
 
   // Wait for a process change and then fulfil the promise.
   function awaitProcessChange(browser) {
     return new Promise(resolve => {
       browser.addEventListener("BrowserChangedProcess", function bcp(e) {
         browser.removeEventListener("BrowserChangedProcess", bcp);
         ok(true, "The browser changed process!");
--- a/dom/base/test/browser.ini
+++ b/dom/base/test/browser.ini
@@ -15,16 +15,17 @@ support-files =
   file_use_counter_svg_fill_pattern_data.svg
 
 [browser_bug593387.js]
 [browser_bug902350.js]
 tags = mcb
 [browser_bug1011748.js]
 [browser_bug1058164.js]
 [browser_messagemanager_loadprocessscript.js]
+skip-if = e10s # Bug 1315042
 [browser_messagemanager_targetframeloader.js]
 [browser_messagemanager_unload.js]
 [browser_pagehide_on_tab_close.js]
 skip-if = e10s # this tests non-e10s behavior. it's not expected to work in e10s.
 [browser_state_notifications.js]
 skip-if = true # Bug 1271028
 [browser_use_counters.js]
 [browser_bug1307747.js]
--- a/dom/bindings/Nullable.h
+++ b/dom/bindings/Nullable.h
@@ -7,16 +7,18 @@
 #ifndef mozilla_dom_Nullable_h
 #define mozilla_dom_Nullable_h
 
 #include "mozilla/Assertions.h"
 #include "nsTArrayForwardDeclare.h"
 #include "mozilla/Move.h"
 #include "mozilla/Maybe.h"
 
+#include <ostream>
+
 class nsCycleCollectionTraversalCallback;
 
 namespace mozilla {
 namespace dom {
 
 // Support for nullable types
 template <typename T>
 struct Nullable
@@ -105,16 +107,21 @@ public:
   {
     return Equals(aOtherNullable);
   }
 
   bool operator!=(const Nullable<T>& aOtherNullable) const
   {
     return !Equals(aOtherNullable);
   }
+
+  friend std::ostream& operator<<(std::ostream& aStream,
+                                  const Nullable& aNullable) {
+    return aStream << aNullable.mValue;
+  }
 };
 
 
 template<typename T>
 void
 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
                             Nullable<T>& aNullable,
                             const char* aName,
--- a/dom/browser-element/mochitest/mochitest-oop.ini
+++ b/dom/browser-element/mochitest/mochitest-oop.ini
@@ -66,16 +66,17 @@ disabled = disabled for bug 1266035 (bug
 [test_browserElement_oop_OpenWindow.html]
 [test_browserElement_oop_OpenWindowDifferentOrigin.html]
 [test_browserElement_oop_OpenWindowInFrame.html]
 [test_browserElement_oop_OpenWindowRejected.html]
 [test_browserElement_oop_Opensearch.html]
 [test_browserElement_oop_OpenTab.html]
 disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling)
 [test_browserElement_oop_PrivateBrowsing.html]
+skip-if = true # Bug 1315042
 [test_browserElement_oop_PromptCheck.html]
 [test_browserElement_oop_PromptConfirm.html]
 [test_browserElement_oop_PurgeHistory.html]
 disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling)
 [test_browserElement_oop_Reload.html]
 disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling)
 [test_browserElement_oop_ReloadPostRequest.html]
 disabled = Disabling some OOP tests for WebIDL scope changes (bug 1310706 for re-enabling)
--- a/dom/cache/test/mochitest/browser.ini
+++ b/dom/cache/test/mochitest/browser.ini
@@ -1,1 +1,2 @@
 [browser_cache_pb_window.js]
+skip-if = e10s # Bug 1315042
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2665,51 +2665,51 @@ TabChild::InitAPZState()
   RefPtr<GeckoContentController> contentController = new ContentProcessController(this);
   cbc->SendPAPZConstructor(new APZChild(contentController), mLayersId);
 }
 
 void
 TabChild::GetDPI(float* aDPI)
 {
     *aDPI = -1.0;
-    if (!mRemoteFrame) {
+    if (!(mDidFakeShow || mDidSetRealShowInfo)) {
         return;
     }
 
     if (mDPI > 0) {
       *aDPI = mDPI;
       return;
     }
 
     // Fallback to a sync call if needed.
     SendGetDPI(aDPI);
 }
 
 void
 TabChild::GetDefaultScale(double* aScale)
 {
     *aScale = -1.0;
-    if (!mRemoteFrame) {
+    if (!(mDidFakeShow || mDidSetRealShowInfo)) {
         return;
     }
 
     if (mDefaultScale > 0) {
       *aScale = mDefaultScale;
       return;
     }
 
     // Fallback to a sync call if needed.
     SendGetDefaultScale(aScale);
 }
 
 void
 TabChild::GetWidgetRounding(int32_t* aRounding)
 {
   *aRounding = 1;
-  if (!mRemoteFrame) {
+  if (!(mDidFakeShow || mDidSetRealShowInfo)) {
     return;
   }
   if (mRounding > 0) {
     *aRounding = mRounding;
     return;
   }
 
   // Fallback to a sync call if needed.
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -164,17 +164,17 @@ MediaDecoder::ResourceCallback::Disconne
     mTimer = nullptr;
   }
 }
 
 MediaDecoderOwner*
 MediaDecoder::ResourceCallback::GetMediaOwner() const
 {
   MOZ_ASSERT(NS_IsMainThread());
-  return mDecoder ? mDecoder->mOwner : nullptr;
+  return mDecoder ? mDecoder->GetOwner() : nullptr;
 }
 
 void
 MediaDecoder::ResourceCallback::SetInfinite(bool aInfinite)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mDecoder) {
     mDecoder->SetInfinite(aInfinite);
@@ -543,37 +543,37 @@ MediaDecoder::OnPlaybackEvent(MediaEvent
       break;
     case MediaEventType::SeekStarted:
       SeekingStarted();
       break;
     case MediaEventType::Invalidate:
       Invalidate();
       break;
     case MediaEventType::EnterVideoSuspend:
-      mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
+      GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
       break;
     case MediaEventType::ExitVideoSuspend:
-      mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
+      GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
       break;
   }
 }
 
 void
 MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError)
 {
   DecodeError(aError);
 }
 
 void
 MediaDecoder::OnDecoderDoctorEvent(DecoderDoctorEvent aEvent)
 {
   MOZ_ASSERT(NS_IsMainThread());
   // OnDecoderDoctorEvent is disconnected at shutdown time.
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
-  HTMLMediaElement* element = mOwner->GetMediaElement();
+  HTMLMediaElement* element = GetOwner()->GetMediaElement();
   if (!element) {
     return;
   }
   nsIDocument* doc = element->OwnerDoc();
   if (!doc) {
     return;
   }
   DecoderDoctorDiagnostics diags;
@@ -707,17 +707,17 @@ MediaDecoder::Seek(double aTime, SeekTar
   mLogicalPosition = aTime;
 
   mLogicallySeeking = true;
   SeekTarget target = SeekTarget(timeUsecs, aSeekType);
   CallSeek(target, aPromise);
 
   if (mPlayState == PLAY_STATE_ENDED) {
     PinForSeek();
-    ChangeState(mOwner->GetPaused() ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING);
+    ChangeState(GetOwner()->GetPaused() ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING);
   }
   return NS_OK;
 }
 
 void
 MediaDecoder::AsyncResolveSeekDOMPromiseIfExists()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -808,22 +808,22 @@ MediaDecoder::MetadataLoaded(nsAutoPtr<M
   mMediaSeekableOnlyInBufferedRanges = aInfo->mMediaSeekableOnlyInBufferedRanges;
   mInfo = aInfo.forget();
   ConstructMediaTracks();
 
   // Make sure the element and the frame (if any) are told about
   // our new size.
   if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
     mFiredMetadataLoaded = true;
-    mOwner->MetadataLoaded(mInfo, nsAutoPtr<const MetadataTags>(aTags.forget()));
+    GetOwner()->MetadataLoaded(mInfo, nsAutoPtr<const MetadataTags>(aTags.forget()));
   }
-  // Invalidate() will end up calling mOwner->UpdateMediaSize with the last
+  // Invalidate() will end up calling GetOwner()->UpdateMediaSize with the last
   // dimensions retrieved from the video frame container. The video frame
   // container contains more up to date dimensions than aInfo.
-  // So we call Invalidate() after calling mOwner->MetadataLoaded to ensure
+  // So we call Invalidate() after calling GetOwner()->MetadataLoaded to ensure
   // the media element has the latest dimensions.
   Invalidate();
 
   EnsureTelemetryReported();
 }
 
 void
 MediaDecoder::EnsureTelemetryReported()
@@ -888,37 +888,37 @@ MediaDecoder::FirstFrameLoaded(nsAutoPtr
   if (mPlayState == PLAY_STATE_LOADING) {
     ChangeState(mNextState);
   }
 
   // Run NotifySuspendedStatusChanged now to give us a chance to notice
   // that autoplay should run.
   NotifySuspendedStatusChanged();
 
-  // mOwner->FirstFrameLoaded() might call us back. Put it at the bottom of
+  // GetOwner()->FirstFrameLoaded() might call us back. Put it at the bottom of
   // this function to avoid unexpected shutdown from reentrant calls.
   if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
-    mOwner->FirstFrameLoaded();
+    GetOwner()->FirstFrameLoaded();
   }
 }
 
 void
 MediaDecoder::NetworkError()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
-  mOwner->NetworkError();
+  GetOwner()->NetworkError();
 }
 
 void
 MediaDecoder::DecodeError(const MediaResult& aError)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
-  mOwner->DecodeError(aError);
+  GetOwner()->DecodeError(aError);
 }
 
 void
 MediaDecoder::UpdateSameOriginStatus(bool aSameOrigin)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mSameOriginMedia = aSameOrigin;
 }
@@ -930,17 +930,17 @@ MediaDecoder::IsSeeking() const
   return mLogicallySeeking;
 }
 
 bool
 MediaDecoder::OwnerHasError() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
-  return mOwner->HasError();
+  return GetOwner()->HasError();
 }
 
 class MediaElementGMPCrashHelper : public GMPCrashHelper
 {
 public:
   explicit MediaElementGMPCrashHelper(HTMLMediaElement* aElement)
     : mElement(aElement)
   {
@@ -957,18 +957,18 @@ public:
 private:
   WeakPtr<HTMLMediaElement> mElement;
 };
 
 already_AddRefed<GMPCrashHelper>
 MediaDecoder::GetCrashHelper()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  return mOwner->GetMediaElement() ?
-    MakeAndAddRef<MediaElementGMPCrashHelper>(mOwner->GetMediaElement()) : nullptr;
+  return GetOwner()->GetMediaElement() ?
+    MakeAndAddRef<MediaElementGMPCrashHelper>(GetOwner()->GetMediaElement()) : nullptr;
 }
 
 bool
 MediaDecoder::IsEnded() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mPlayState == PLAY_STATE_ENDED;
 }
@@ -992,19 +992,19 @@ MediaDecoder::PlaybackEnded()
                 mLogicallySeeking.Ref(), ToPlayStateStr(mPlayState));
     return;
   }
 
   DECODER_LOG("MediaDecoder::PlaybackEnded");
 
   ChangeState(PLAY_STATE_ENDED);
   InvalidateWithFlags(VideoFrameContainer::INVALIDATE_FORCE);
-  mOwner->PlaybackEnded();
+  GetOwner()->PlaybackEnded();
 
-  // This must be called after |mOwner->PlaybackEnded()| call above, in order
+  // This must be called after |GetOwner()->PlaybackEnded()| call above, in order
   // to fire the required durationchange.
   if (IsInfinite()) {
     SetInfinite(false);
   }
 }
 
 MediaStatistics
 MediaDecoder::GetStatistics()
@@ -1064,40 +1064,40 @@ MediaDecoder::UpdatePlaybackRate()
 
 void
 MediaDecoder::NotifySuspendedStatusChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   if (mResource) {
     bool suspended = mResource->IsSuspendedByCache();
-    mOwner->NotifySuspendedByCache(suspended);
+    GetOwner()->NotifySuspendedByCache(suspended);
   }
 }
 
 void
 MediaDecoder::NotifyBytesDownloaded()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   UpdatePlaybackRate();
-  mOwner->DownloadProgressed();
+  GetOwner()->DownloadProgressed();
 }
 
 void
 MediaDecoder::NotifyDownloadEnded(nsresult aStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   DECODER_LOG("NotifyDownloadEnded, status=%x", aStatus);
 
   if (aStatus == NS_BINDING_ABORTED) {
     // Download has been cancelled by user.
-    mOwner->LoadAborted();
+    GetOwner()->LoadAborted();
     return;
   }
 
   UpdatePlaybackRate();
 
   if (NS_SUCCEEDED(aStatus)) {
     // A final progress event will be fired by the MediaResource calling
     // DownloadSuspended on the element.
@@ -1110,17 +1110,17 @@ MediaDecoder::NotifyDownloadEnded(nsresu
 
 void
 MediaDecoder::NotifyPrincipalChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   nsCOMPtr<nsIPrincipal> newPrincipal = GetCurrentPrincipal();
   mMediaPrincipalHandle = MakePrincipalHandle(newPrincipal);
-  mOwner->NotifyDecoderPrincipalChanged();
+  GetOwner()->NotifyDecoderPrincipalChanged();
 }
 
 void
 MediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
@@ -1147,17 +1147,17 @@ MediaDecoder::OnSeekResolved()
     // in operation.
     UnpinForSeek();
     mLogicallySeeking = false;
   }
 
   // Ensure logical position is updated after seek.
   UpdateLogicalPositionInternal();
 
-  mOwner->SeekCompleted();
+  GetOwner()->SeekCompleted();
   AsyncResolveSeekDOMPromiseIfExists();
 }
 
 void
 MediaDecoder::OnSeekRejected()
 {
   MOZ_ASSERT(NS_IsMainThread());
   mSeekRequest.Complete();
@@ -1165,17 +1165,17 @@ MediaDecoder::OnSeekRejected()
   AsyncRejectSeekDOMPromiseIfExists();
 }
 
 void
 MediaDecoder::SeekingStarted()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
-  mOwner->SeekStarted();
+  GetOwner()->SeekStarted();
 }
 
 void
 MediaDecoder::ChangeState(PlayState aState)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!IsShutdown(), "SHUTDOWN is the final state.");
 
@@ -1240,17 +1240,17 @@ MediaDecoder::DurationChanged()
 
   // Duration has changed so we should recompute playback rate
   UpdatePlaybackRate();
 
   // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=28822 for a discussion
   // of whether we should fire durationchange on explicit infinity.
   if (mFiredMetadataLoaded &&
       (!mozilla::IsInfinite<double>(mDuration) || mExplicitDuration.Ref().isSome())) {
-    mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
+    GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
   }
 
   if (CurrentPosition() > TimeUnit::FromSeconds(mDuration).ToMicroseconds()) {
     Seek(mDuration, SeekTarget::Accurate);
   }
 }
 
 void
@@ -1377,17 +1377,17 @@ MediaDecoder::SetPlaybackRate(double aPl
   double oldRate = mPlaybackRate;
   mPlaybackRate = aPlaybackRate;
   if (aPlaybackRate == 0) {
     Pause();
     return;
   }
 
 
-  if (oldRate == 0 && !mOwner->GetPaused()) {
+  if (oldRate == 0 && !GetOwner()->GetPaused()) {
     // PlaybackRate is no longer null.
     // Restart the playback if the media was playing.
     Play();
   }
 
   if (mDecoderStateMachine) {
     mDecoderStateMachine->DispatchSetPlaybackRate(aPlaybackRate);
   }
@@ -1509,17 +1509,17 @@ MediaDecoder::GetStateMachine() const {
   return mDecoderStateMachine;
 }
 
 void
 MediaDecoder::FireTimeUpdate()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
-  mOwner->FireTimeUpdate(true);
+  GetOwner()->FireTimeUpdate(true);
 }
 
 void
 MediaDecoder::PinForSeek()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MediaResource* resource = GetResource();
   if (!resource || mPinnedForSeek) {
@@ -1667,17 +1667,17 @@ MediaDecoder::ConstructMediaTracks()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
   if (mMediaTracksConstructed || !mInfo) {
     return;
   }
 
-  HTMLMediaElement* element = mOwner->GetMediaElement();
+  HTMLMediaElement* element = GetOwner()->GetMediaElement();
   if (!element) {
     return;
   }
 
   mMediaTracksConstructed = true;
 
   AudioTrackList* audioList = element->AudioTracks();
   if (audioList && mInfo->HasAudio()) {
@@ -1700,17 +1700,17 @@ MediaDecoder::ConstructMediaTracks()
 }
 
 void
 MediaDecoder::RemoveMediaTracks()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
 
-  HTMLMediaElement* element = mOwner->GetMediaElement();
+  HTMLMediaElement* element = GetOwner()->GetMediaElement();
   if (!element) {
     return;
   }
 
   AudioTrackList* audioList = element->AudioTracks();
   if (audioList) {
     audioList->RemoveTracks();
   }
@@ -1733,42 +1733,81 @@ MediaDecoder::NextFrameBufferedStatus()
     media::TimeUnit::FromMicroseconds(CurrentPosition());
   media::TimeInterval interval(currentPosition,
                                currentPosition + media::TimeUnit::FromMicroseconds(DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED));
   return GetBuffered().Contains(interval)
     ? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
     : MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
 }
 
+nsCString
+MediaDecoder::GetDebugInfo()
+{
+  return nsPrintfCString(
+    "channels=%u rate=%u hasAudio=%d hasVideo=%d mPlayState=%s mdsm=%p",
+    mInfo ? mInfo->mAudio.mChannels : 0, mInfo ? mInfo->mAudio.mRate : 0,
+    mInfo ? mInfo->HasAudio() : 0, mInfo ? mInfo->HasVideo() : 0,
+    PlayStateStr(), GetStateMachine());
+}
+
 void
 MediaDecoder::DumpDebugInfo()
 {
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
-  DUMP_LOG("metadata: channels=%u rate=%u hasAudio=%d hasVideo=%d, "
-           "state: mPlayState=%s mdsm=%p",
-           mInfo ? mInfo->mAudio.mChannels : 0, mInfo ? mInfo->mAudio.mRate : 0,
-           mInfo ? mInfo->HasAudio() : 0, mInfo ? mInfo->HasVideo() : 0,
-           PlayStateStr(), GetStateMachine());
+  nsCString str = GetDebugInfo();
 
-  nsAutoCString str;
-  GetMozDebugReaderData(str);
-  if (!str.IsEmpty()) {
-    DUMP_LOG("reader data:\n%s", str.get());
+  nsAutoCString readerStr;
+  GetMozDebugReaderData(readerStr);
+  if (!readerStr.IsEmpty()) {
+    str += "\nreader data:\n";
+    str += readerStr;
+  }
+
+  if (!GetStateMachine()) {
+    DUMP_LOG("%s", str.get());
+    return;
   }
 
-  if (GetStateMachine()) {
-    GetStateMachine()->DumpDebugInfo();
+  GetStateMachine()->RequestDebugInfo()->Then(
+    AbstractThread::MainThread(), __func__,
+    [this, str] (const nsACString& aString) {
+      DUMP_LOG("%s", str.get());
+      DUMP_LOG("%s", aString.Data());
+    },
+    [this, str] () {
+      DUMP_LOG("%s", str.get());
+    });
+}
+
+RefPtr<MediaDecoder::DebugInfoPromise>
+MediaDecoder::RequestDebugInfo()
+{
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
+
+  auto str = GetDebugInfo();
+  if (!GetStateMachine()) {
+    return DebugInfoPromise::CreateAndResolve(str, __func__);
   }
+
+  return GetStateMachine()->RequestDebugInfo()->Then(
+    AbstractThread::MainThread(), __func__,
+    [str] (const nsACString& aString) {
+      nsCString result = str + nsCString("\n") + aString;
+      return DebugInfoPromise::CreateAndResolve(result, __func__);
+    },
+    [str] () {
+      return DebugInfoPromise::CreateAndResolve(str, __func__);
+    });
 }
 
 void
 MediaDecoder::NotifyAudibleStateChanged()
 {
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
-  mOwner->SetAudibleState(mIsAudioDataAudible);
+  GetOwner()->SetAudibleState(mIsAudioDataAudible);
 }
 
 MediaMemoryTracker::MediaMemoryTracker()
 {
 }
 
 void
 MediaMemoryTracker::InitMemoryReporter()
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -468,28 +468,31 @@ private:
   {
     GetFrameStatistics().NotifyDecodedFrames(aStats);
   }
 
   void UpdateReadyState()
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
-    mOwner->UpdateReadyState();
+    GetOwner()->UpdateReadyState();
   }
 
   virtual MediaDecoderOwner::NextFrameStatus NextFrameStatus() { return mNextFrameStatus; }
   virtual MediaDecoderOwner::NextFrameStatus NextFrameBufferedStatus();
 
   // Returns a string describing the state of the media player internal
   // data. Used for debugging purposes.
   virtual void GetMozDebugReaderData(nsACString& aString) {}
 
   virtual void DumpDebugInfo();
 
+  using DebugInfoPromise = MozPromise<nsCString, bool, true>;
+  RefPtr<DebugInfoPromise> RequestDebugInfo();
+
 protected:
   virtual ~MediaDecoder();
 
   // Called when the first audio and/or video from the media file has been loaded
   // by the state machine. Call on the main thread only.
   virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
                                 MediaDecoderEventVisibility aEventVisibility);
 
@@ -547,16 +550,18 @@ protected:
   RefPtr<MediaResource> mResource;
 
   // Amount of buffered data ahead of current time required to consider that
   // the next frame is available.
   // An arbitrary value of 250ms is used.
   static const int DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED = 250000;
 
 private:
+  nsCString GetDebugInfo();
+
   // Called when the metadata from the media file has been loaded by the
   // state machine. Call on the main thread only.
   void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
                       nsAutoPtr<MetadataTags> aTags,
                       MediaDecoderEventVisibility aEventVisibility);
 
   MediaEventSource<void>*
   DataArrivedEvent() override { return &mDataArrivedEvent; }
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -62,34 +62,30 @@ using namespace mozilla::media;
 #define NS_DispatchToMainThread(...) CompileError_UseAbstractThreadDispatchInstead
 
 // avoid redefined macro in unified build
 #undef FMT
 #undef DECODER_LOG
 #undef VERBOSE_LOG
 #undef SAMPLE_LOG
 #undef DECODER_WARN
-#undef DUMP_LOG
 #undef SFMT
 #undef SLOG
 #undef SWARN
-#undef SDUMP
 
 #define FMT(x, ...) "Decoder=%p " x, mDecoderID, ##__VA_ARGS__
 #define DECODER_LOG(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug,   (FMT(x, ##__VA_ARGS__)))
 #define VERBOSE_LOG(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Verbose, (FMT(x, ##__VA_ARGS__)))
 #define SAMPLE_LOG(x, ...)  MOZ_LOG(gMediaSampleLog,  LogLevel::Debug,   (FMT(x, ##__VA_ARGS__)))
 #define DECODER_WARN(x, ...) NS_WARNING(nsPrintfCString(FMT(x, ##__VA_ARGS__)).get())
-#define DUMP_LOG(x, ...) NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString(FMT(x, ##__VA_ARGS__)).get(), nullptr, nullptr, -1)
 
 // Used by StateObject and its sub-classes
 #define SFMT(x, ...) "Decoder=%p state=%s " x, mMaster->mDecoderID, ToStateStr(GetState()), ##__VA_ARGS__
 #define SLOG(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, (SFMT(x, ##__VA_ARGS__)))
 #define SWARN(x, ...) NS_WARNING(nsPrintfCString(SFMT(x, ##__VA_ARGS__)).get())
-#define SDUMP(x, ...) NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString(SFMT(x, ##__VA_ARGS__)).get(), nullptr, nullptr, -1)
 
 // Certain constants get stored as member variables and then adjusted by various
 // scale factors on a per-decoder basis. We want to make sure to avoid using these
 // constants directly, so we put them in a namespace.
 namespace detail {
 
 // If audio queue has less than this many usecs of decoded audio, we won't risk
 // trying to decode the video, we'll skip decoding video up to the next
@@ -240,17 +236,17 @@ public:
   virtual RefPtr<ShutdownPromise> HandleShutdown();
 
   virtual void HandleVideoSuspendTimeout() = 0;
 
   virtual void HandleResumeVideoDecoding();
 
   virtual void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) {}
 
-  virtual void DumpDebugInfo() {}
+  virtual nsCString GetDebugInfo() { return nsCString(); }
 
 private:
   template <class S, typename R, typename... As>
   auto ReturnTypeHelper(R(S::*)(As...)) -> R;
 
   void Crash(const char* aReason, const char* aSite)
   {
     char buf[1024];
@@ -739,19 +735,19 @@ public:
 
     if (aPlayState == MediaDecoder::PLAY_STATE_PAUSED) {
       StartDormantTimer();
     } else {
       mDormantTimer.Reset();
     }
   }
 
-  void DumpDebugInfo() override
+  nsCString GetDebugInfo() override
   {
-    SDUMP("mIsPrerolling=%d", mIsPrerolling);
+    return nsPrintfCString("mIsPrerolling=%d", mIsPrerolling);
   }
 
 private:
   void DispatchDecodeTasksIfNeeded();
   void EnsureAudioDecodeTaskQueued();
   void EnsureVideoDecodeTaskQueued();
   bool NeedToSkipToNextKeyframe();
   void MaybeStartBuffering();
@@ -3649,43 +3645,42 @@ MediaDecoderStateMachine::SetAudioCaptur
 uint32_t MediaDecoderStateMachine::GetAmpleVideoFrames() const
 {
   MOZ_ASSERT(OnTaskQueue());
   return (mReader->IsAsync() && mReader->VideoIsHardwareAccelerated())
     ? std::max<uint32_t>(sVideoQueueHWAccelSize, MIN_VIDEO_QUEUE_SIZE)
     : std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
 }
 
-void
-MediaDecoderStateMachine::DumpDebugInfo()
+nsCString
+MediaDecoderStateMachine::GetDebugInfo()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // It is fine to capture a raw pointer here because MediaDecoder only call
-  // this function before shutdown begins.
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([this] () {
-    mMediaSink->DumpDebugInfo();
-    mStateObj->DumpDebugInfo();
-    DUMP_LOG(
-      "GetMediaTime=%lld GetClock=%lld mMediaSink=%p "
-      "state=%s mPlayState=%d mSentFirstFrameLoadedEvent=%d IsPlaying=%d "
-      "mAudioStatus=%s mVideoStatus=%s mDecodedAudioEndTime=%lld mDecodedVideoEndTime=%lld "
-      "mAudioCompleted=%d mVideoCompleted=%d",
-      GetMediaTime(), mMediaSink->IsStarted() ? GetClock() : -1, mMediaSink.get(),
-      ToStateStr(), mPlayState.Ref(), mSentFirstFrameLoadedEvent, IsPlaying(),
-      AudioRequestStatus(), VideoRequestStatus(), mDecodedAudioEndTime, mDecodedVideoEndTime,
-      mAudioCompleted, mVideoCompleted);
-  });
-
-  // Since the task is run asynchronously, it is possible other tasks get first
-  // and change the object states before we print them. Therefore we want to
-  // dispatch this task immediately without waiting for the tail dispatching
-  // phase so object states are less likely to change before being printed.
-  OwnerThread()->Dispatch(r.forget(),
-    AbstractThread::AssertDispatchSuccess, AbstractThread::TailDispatch);
+  MOZ_ASSERT(OnTaskQueue());
+  return nsPrintfCString(
+    "GetMediaTime=%lld GetClock=%lld mMediaSink=%p "
+    "state=%s mPlayState=%d mSentFirstFrameLoadedEvent=%d IsPlaying=%d "
+    "mAudioStatus=%s mVideoStatus=%s mDecodedAudioEndTime=%lld mDecodedVideoEndTime=%lld "
+    "mAudioCompleted=%d mVideoCompleted=%d ",
+    GetMediaTime(), mMediaSink->IsStarted() ? GetClock() : -1, mMediaSink.get(),
+    ToStateStr(), mPlayState.Ref(), mSentFirstFrameLoadedEvent, IsPlaying(),
+    AudioRequestStatus(), VideoRequestStatus(), mDecodedAudioEndTime, mDecodedVideoEndTime,
+    mAudioCompleted, mVideoCompleted)
+    + mStateObj->GetDebugInfo() + nsCString("\n")
+    + mMediaSink->GetDebugInfo();
+}
+
+RefPtr<MediaDecoder::DebugInfoPromise>
+MediaDecoderStateMachine::RequestDebugInfo()
+{
+  using PromiseType = MediaDecoder::DebugInfoPromise;
+  RefPtr<PromiseType::Private> p = new PromiseType::Private(__func__);
+  OwnerThread()->Dispatch(NS_NewRunnableFunction([this, p] () {
+    p->Resolve(GetDebugInfo(), __func__);
+  }), AbstractThread::AssertDispatchSuccess, AbstractThread::TailDispatch);
+  return p.forget();
 }
 
 void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream,
                                                bool aFinishWhenEnded)
 {
   MOZ_ASSERT(NS_IsMainThread());
   DECODER_LOG("AddOutputStream aStream=%p!", aStream);
   mOutputStreamManager->Add(aStream, aFinishWhenEnded);
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -157,17 +157,17 @@ public:
     DECODER_STATE_DECODING_FIRSTFRAME,
     DECODER_STATE_DECODING,
     DECODER_STATE_SEEKING,
     DECODER_STATE_BUFFERING,
     DECODER_STATE_COMPLETED,
     DECODER_STATE_SHUTDOWN
   };
 
-  void DumpDebugInfo();
+  RefPtr<MediaDecoder::DebugInfoPromise> RequestDebugInfo();
 
   void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
   // Remove an output stream added with AddOutputStream.
   void RemoveOutputStream(MediaStream* aStream);
 
   // Seeks to the decoder to aTarget asynchronously.
   RefPtr<MediaDecoder::SeekPromise> InvokeSeek(const SeekTarget& aTarget);
 
@@ -235,16 +235,18 @@ private:
   class BufferingState;
   class CompletedState;
   class ShutdownState;
 
   static const char* ToStateStr(State aState);
   static const char* ToStr(NextFrameStatus aStatus);
   const char* ToStateStr();
 
+  nsCString GetDebugInfo();
+
   // Functions used by assertions to ensure we're calling things
   // on the appropriate threads.
   bool OnTaskQueue() const;
 
   // Initialization that needs to happen on the task queue. This is the first
   // task that gets run on the task queue, and is dispatched from the MDSM
   // constructor immediately after the task queue is created.
   void InitializationTask(MediaDecoder* aDecoder);
--- a/dom/media/encoder/VP8TrackEncoder.cpp
+++ b/dom/media/encoder/VP8TrackEncoder.cpp
@@ -548,21 +548,25 @@ VP8TrackEncoder::GetEncodedTrack(Encoded
                            VPX_DL_REALTIME)) {
         return NS_ERROR_FAILURE;
       }
       // Get the encoded data from VP8 encoder.
       GetEncodedPartitions(aData);
     } else {
       // SKIP_FRAME
       // Extend the duration of the last encoded data in aData
-      // because this frame will be skip.
+      // because this frame will be skipped.
       VP8LOG(LogLevel::Warning, "MediaRecorder lagging behind. Skipping a frame.");
       RefPtr<EncodedFrame> last = aData.GetEncodedFrames().LastElement();
       if (last) {
-        last->SetDuration(last->GetDuration() + chunk.GetDuration());
+        CheckedInt64 skippedDuration = FramesToUsecs(chunk.mDuration, mTrackRate);
+        if (skippedDuration.isValid() && skippedDuration.value() > 0) {
+          last->SetDuration(last->GetDuration() +
+                            (static_cast<uint64_t>(skippedDuration.value())));
+        }
       }
     }
 
     // Move forward the mEncodedTimestamp.
     mEncodedTimestamp += chunk.GetDuration();
     totalProcessedDuration += chunk.GetDuration();
 
     // Check what to do next.
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -711,19 +711,22 @@ GMPParent::ReadGMPInfoFile(nsIFile* aFil
       }
     }
 
     if (cap.mAPIName.EqualsLiteral(GMP_API_DECRYPTOR)) {
       mCanDecrypt = true;
 
 #if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
       if (!mozilla::SandboxInfo::Get().CanSandboxMedia()) {
-        printf_stderr("GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM"
-                      " but this system can't sandbox it; not loading.\n",
-                      mDisplayName.get());
+        nsPrintfCString msg(
+          "GMPParent::ReadGMPMetaData: Plugin \"%s\" is an EME CDM"
+          " but this system can't sandbox it; not loading.",
+          mDisplayName.get());
+        printf_stderr("%s\n", msg.get());
+        LOGD("%s", msg.get());
         return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
       }
 #endif
     }
 
     mCapabilities.AppendElement(Move(cap));
   }
 
@@ -766,16 +769,28 @@ GMPParent::ParseChromiumManifest(const n
                                  m.mX_cdm_host_versions.ToInteger(&ignored))) {
     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   mDisplayName = NS_ConvertUTF16toUTF8(m.mName);
   mDescription = NS_ConvertUTF16toUTF8(m.mDescription);
   mVersion = NS_ConvertUTF16toUTF8(m.mVersion);
 
+#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+  if (!mozilla::SandboxInfo::Get().CanSandboxMedia()) {
+    nsPrintfCString msg(
+      "GMPParent::ParseChromiumManifest: Plugin \"%s\" is an EME CDM"
+      " but this system can't sandbox it; not loading.",
+      mDisplayName.get());
+    printf_stderr("%s\n", msg.get());
+    LOGD("%s", msg.get());
+    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+  }
+#endif
+
   nsCString kEMEKeySystem;
 
   // We hard code a few of the settings because they can't be stored in the
   // widevine manifest without making our API different to widevine's.
   if (mDisplayName.EqualsASCII("clearkey")) {
     kEMEKeySystem = kEMEKeySystemClearkey;
 #if XP_WIN
     mLibs = NS_LITERAL_CSTRING("dxva2.dll, msmpeg2vdec.dll, evr.dll, mfh264dec.dll, mfplat.dll");
--- a/dom/media/gtest/TestVideoTrackEncoder.cpp
+++ b/dom/media/gtest/TestVideoTrackEncoder.cpp
@@ -424,16 +424,59 @@ TEST(VP8VideoTrackEncoder, NullFrameFirs
   uint64_t totalDuration = 0;
   for (auto& frame : container.GetEncodedFrames()) {
     totalDuration += frame->GetDuration();
   }
   const uint64_t pointThree = (PR_USEC_PER_SEC / 10) * 3;
   EXPECT_EQ(pointThree, totalDuration);
 }
 
+// Test encoding a track that has to skip frames.
+TEST(VP8VideoTrackEncoder, SkippedFrames)
+{
+  // Initiate VP8 encoder
+  TestVP8TrackEncoder encoder;
+  InitParam param = {true, 640, 480};
+  encoder.TestInit(param);
+  YUVBufferGenerator generator;
+  generator.Init(mozilla::gfx::IntSize(640, 480));
+  TimeStamp now = TimeStamp::Now();
+  VideoSegment segment;
+
+  // Pass 100 frames of the shortest possible duration where we don't get
+  // rounding errors between input/output rate.
+  for (uint32_t i = 0; i < 100; ++i) {
+    segment.AppendFrame(generator.GenerateI420Image(),
+                        mozilla::StreamTime(90), // 1ms
+                        generator.GetSize(),
+                        PRINCIPAL_HANDLE_NONE,
+                        false,
+                        now + TimeDuration::FromMilliseconds(i));
+  }
+
+  encoder.SetCurrentFrames(segment);
+
+  // End the track.
+  segment.Clear();
+  encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, TrackEventCommand::TRACK_EVENT_ENDED, segment);
+
+  EncodedFrameContainer container;
+  ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
+
+  EXPECT_TRUE(encoder.IsEncodingComplete());
+
+  // Verify total duration being 100 * 1ms = 100ms.
+  uint64_t totalDuration = 0;
+  for (auto& frame : container.GetEncodedFrames()) {
+    totalDuration += frame->GetDuration();
+  }
+  const uint64_t hundredMillis = PR_USEC_PER_SEC / 10;
+  EXPECT_EQ(hundredMillis, totalDuration);
+}
+
 // EOS test
 TEST(VP8VideoTrackEncoder, EncodeComplete)
 {
   // Initiate VP8 encoder
   TestVP8TrackEncoder encoder;
   InitParam param = {true, 640, 480};
   encoder.TestInit(param);
 
--- a/dom/media/mediasink/DecodedStream.cpp
+++ b/dom/media/mediasink/DecodedStream.cpp
@@ -17,19 +17,16 @@
 #include "MediaStreamListener.h"
 #include "OutputStreamManager.h"
 #include "SharedBuffer.h"
 #include "VideoSegment.h"
 #include "VideoUtils.h"
 
 namespace mozilla {
 
-#undef DUMP_LOG
-#define DUMP_LOG(x, ...) NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString(x, ##__VA_ARGS__).get(), nullptr, nullptr, -1)
-
 /*
  * A container class to make it easier to pass the playback info all the
  * way to DecodedStreamGraphListener from DecodedStream.
  */
 struct PlaybackInfoInit {
   int64_t mStartTime;
   MediaInfo mInfo;
 };
@@ -131,17 +128,17 @@ public:
   DecodedStreamData(OutputStreamManager* aOutputStreamManager,
                     PlaybackInfoInit&& aInit,
                     MozPromiseHolder<GenericPromise>&& aPromise,
                     AbstractThread* aMainThread);
   ~DecodedStreamData();
   void SetPlaying(bool aPlaying);
   MediaEventSource<int64_t>& OnOutput();
   void Forget();
-  void DumpDebugInfo();
+  nsCString GetDebugInfo();
 
   /* The following group of fields are protected by the decoder's monitor
    * and can be read or written on any thread.
    */
   // Count of audio frames written to the stream
   int64_t mAudioFramesWritten;
   // mNextVideoTime is the end timestamp for the last packet sent to the stream.
   // Therefore video packets starting at or after this time need to be copied
@@ -224,22 +221,22 @@ DecodedStreamData::SetPlaying(bool aPlay
 }
 
 void
 DecodedStreamData::Forget()
 {
   mListener->Forget();
 }
 
-void
-DecodedStreamData::DumpDebugInfo()
+nsCString
+DecodedStreamData::GetDebugInfo()
 {
-  DUMP_LOG(
-    "DecodedStreamData=%p mPlaying=%d mAudioFramesWritten=%lld"
-    "mNextAudioTime=%lld mNextVideoTime=%lld mHaveSentFinish=%d"
+  return nsPrintfCString(
+    "DecodedStreamData=%p mPlaying=%d mAudioFramesWritten=%lld "
+    "mNextAudioTime=%lld mNextVideoTime=%lld mHaveSentFinish=%d "
     "mHaveSentFinishAudio=%d mHaveSentFinishVideo=%d",
     this, mPlaying, mAudioFramesWritten, mNextAudioTime, mNextVideoTime,
     mHaveSentFinish, mHaveSentFinishAudio, mHaveSentFinishVideo);
 }
 
 DecodedStream::DecodedStream(AbstractThread* aOwnerThread,
                              AbstractThread* aMainThread,
                              MediaQueue<MediaData>& aAudioQueue,
@@ -774,21 +771,19 @@ DecodedStream::DisconnectListener()
   AssertOwnerThread();
 
   mAudioPushListener.Disconnect();
   mVideoPushListener.Disconnect();
   mAudioFinishListener.Disconnect();
   mVideoFinishListener.Disconnect();
 }
 
-void
-DecodedStream::DumpDebugInfo()
+nsCString
+DecodedStream::GetDebugInfo()
 {
   AssertOwnerThread();
-  DUMP_LOG(
+  return nsPrintfCString(
     "DecodedStream=%p mStartTime=%lld mLastOutputTime=%lld mPlaying=%d mData=%p",
-    this, mStartTime.valueOr(-1), mLastOutputTime, mPlaying, mData.get());
-  if (mData) {
-    mData->DumpDebugInfo();
-  }
+    this, mStartTime.valueOr(-1), mLastOutputTime, mPlaying, mData.get())
+    + (mData ? nsCString("\n") + mData->GetDebugInfo() : nsCString());
 }
 
 } // namespace mozilla
--- a/dom/media/mediasink/DecodedStream.h
+++ b/dom/media/mediasink/DecodedStream.h
@@ -59,17 +59,17 @@ public:
   void SetPreservesPitch(bool aPreservesPitch) override;
   void SetPlaying(bool aPlaying) override;
 
   void Start(int64_t aStartTime, const MediaInfo& aInfo) override;
   void Stop() override;
   bool IsStarted() const override;
   bool IsPlaying() const override;
 
-  void DumpDebugInfo() override;
+  nsCString GetDebugInfo() override;
 
 protected:
   virtual ~DecodedStream();
 
 private:
   void DestroyData(UniquePtr<DecodedStreamData> aData);
   void AdvanceTracks();
   void SendAudio(double aVolume, bool aIsSameOrigin, const PrincipalHandle& aPrincipalHandle);
--- a/dom/media/mediasink/MediaSink.h
+++ b/dom/media/mediasink/MediaSink.h
@@ -114,19 +114,19 @@ public:
   // Can be called in any state.
   virtual bool IsPlaying() const = 0;
 
   // Called on the state machine thread to shut down the sink. All resources
   // allocated by this sink should be released.
   // Must be called after playback stopped.
   virtual void Shutdown() {}
 
-  // Dump debugging information to the logs.
+  // Return a string containing debugging information.
   // Can be called in any phase.
-  virtual void DumpDebugInfo() {}
+  virtual nsCString GetDebugInfo() { return nsCString(); }
 
 protected:
   virtual ~MediaSink() {}
 };
 
 } // namespace media
 } // namespace mozilla
 
--- a/dom/media/mediasink/VideoSink.cpp
+++ b/dom/media/mediasink/VideoSink.cpp
@@ -8,22 +8,20 @@
 #include "VideoSink.h"
 #include "MediaPrefs.h"
 
 namespace mozilla {
 
 extern LazyLogModule gMediaDecoderLog;
 
 #undef FMT
-#undef DUMP_LOG
 
 #define FMT(x, ...) "VideoSink=%p " x, this, ##__VA_ARGS__
 #define VSINK_LOG(x, ...)   MOZ_LOG(gMediaDecoderLog, LogLevel::Debug,   (FMT(x, ##__VA_ARGS__)))
 #define VSINK_LOG_V(x, ...) MOZ_LOG(gMediaDecoderLog, LogLevel::Verbose, (FMT(x, ##__VA_ARGS__)))
-#define DUMP_LOG(x, ...) NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString(FMT(x, ##__VA_ARGS__)).get(), nullptr, nullptr, -1)
 
 using namespace mozilla::layers;
 
 namespace media {
 
 // Minimum update frequency is 1/120th of a second, i.e. half the
 // duration of a 60-fps frame.
 static const int64_t MIN_UPDATE_INTERVAL_US = 1000000 / (60 * 2);
@@ -468,23 +466,23 @@ VideoSink::MaybeResolveEndPromise()
   // All frames are rendered, Let's resolve the promise.
   if (VideoQueue().IsFinished() &&
       VideoQueue().GetSize() <= 1 &&
       !mVideoSinkEndRequest.Exists()) {
     mEndPromiseHolder.ResolveIfExists(true, __func__);
   }
 }
 
-void
-VideoSink::DumpDebugInfo()
+nsCString
+VideoSink::GetDebugInfo()
 {
   AssertOwnerThread();
-  DUMP_LOG(
+  return nsPrintfCString(
     "IsStarted=%d IsPlaying=%d, VideoQueue: finished=%d size=%d, "
     "mVideoFrameEndTime=%lld mHasVideo=%d mVideoSinkEndRequest.Exists()=%d "
-    "mEndPromiseHolder.IsEmpty()=%d",
+    "mEndPromiseHolder.IsEmpty()=%d\n",
     IsStarted(), IsPlaying(), VideoQueue().IsFinished(), VideoQueue().GetSize(),
-    mVideoFrameEndTime, mHasVideo, mVideoSinkEndRequest.Exists(), mEndPromiseHolder.IsEmpty());
-  mAudioSink->DumpDebugInfo();
+    mVideoFrameEndTime, mHasVideo, mVideoSinkEndRequest.Exists(), mEndPromiseHolder.IsEmpty())
+    + mAudioSink->GetDebugInfo();
 }
 
 } // namespace media
 } // namespace mozilla
--- a/dom/media/mediasink/VideoSink.h
+++ b/dom/media/mediasink/VideoSink.h
@@ -63,17 +63,17 @@ public:
   void Stop() override;
 
   bool IsStarted() const override;
 
   bool IsPlaying() const override;
 
   void Shutdown() override;
 
-  void DumpDebugInfo() override;
+  nsCString GetDebugInfo() override;
 
 private:
   virtual ~VideoSink();
 
   // VideoQueue listener related.
   void OnVideoQueuePushed(RefPtr<MediaData>&& aSample);
   void OnVideoQueueFinished();
   void ConnectListener();
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -31,25 +31,25 @@ skip-if = !e10s
 [browser_ConsoleAPITests.js]
 skip-if = e10s
 [browser_ConsoleStorageAPITests.js]
 [browser_ConsoleStoragePBTest_perwindowpb.js]
 [browser_focus_steal_from_chrome.js]
 [browser_focus_steal_from_chrome_during_mousedown.js]
 [browser_frame_elements.js]
 [browser_largeAllocation.js]
-skip-if = !e10s # Large-Allocation requires e10s
+skip-if = true || !e10s # Large-Allocation requires e10s, turned off for e10s-multi Bug 1315042
 [browser_localStorage_privatestorageevent.js]
 [browser_test__content.js]
 [browser_test_new_window_from_content.js]
 tags = openwindow
 skip-if = toolkit == 'android'  || (os == "linux" && debug) # see bug 1261495 for Linux debug time outs
 support-files =
   test_new_window_from_content_child.html
 [browser_test_toolbars_visibility.js]
 support-files =
   test_new_window_from_content_child.html
 [browser_xhr_sandbox.js]
 [browser_prerendering.js]
 support-files =
   prerender.html
   prerender_target.html
-skip-if = !e10s # Prerendering requires e10s
+skip-if = true || !e10s # Prerendering requires e10s, turned off for e10s-multi Bug 1315042
--- a/ipc/chromium/src/base/logging.cc
+++ b/ipc/chromium/src/base/logging.cc
@@ -56,17 +56,16 @@ Logger::printf(const char* fmt, ...)
 {
   va_list args;
   va_start(args, fmt);
   mMsg = PR_vsprintf_append(mMsg, fmt, args);
   va_end(args);
 }
 
 LazyLogModule Logger::gChromiumPRLog("chromium");
-} // namespace mozilla 
 
 mozilla::Logger&
 operator<<(mozilla::Logger& log, const char* s)
 {
   log.printf("%s", s);
   return log;
 }
 
@@ -92,8 +91,10 @@ operator<<(mozilla::Logger& log, const s
 }
 
 mozilla::Logger&
 operator<<(mozilla::Logger& log, void* p)
 {
   log.printf("%p", p);
   return log;
 }
+
+} // namespace mozilla
--- a/ipc/chromium/src/base/logging.h
+++ b/ipc/chromium/src/base/logging.h
@@ -71,30 +71,30 @@ private:
 
   DISALLOW_EVIL_CONSTRUCTORS(LogWrapper);
 };
 
 struct EmptyLog
 {
 };
 
-} // namespace mozilla
-
 mozilla::Logger& operator<<(mozilla::Logger& log, const char* s);
 mozilla::Logger& operator<<(mozilla::Logger& log, const std::string& s);
 mozilla::Logger& operator<<(mozilla::Logger& log, int i);
 mozilla::Logger& operator<<(mozilla::Logger& log, const std::wstring& s);
 mozilla::Logger& operator<<(mozilla::Logger& log, void* p);
 
 template<class T>
 const mozilla::EmptyLog& operator <<(const mozilla::EmptyLog& log, const T&)
 {
   return log;
 }
 
+} // namespace mozilla
+
 #ifdef NO_CHROMIUM_LOGGING
 #define CHROMIUM_LOG(info) std::stringstream()
 #define LOG_IF(info, condition) if (!(condition)) std::stringstream()
 #else
 #define CHROMIUM_LOG(info) mozilla::LogWrapper(mozilla::LOG_ ## info, __FILE__, __LINE__)
 #define LOG_IF(info, condition) \
   if (!(condition)) mozilla::LogWrapper(mozilla::LOG_ ## info, __FILE__, __LINE__)
 #endif
--- a/ipc/mscom/ActivationContext.h
+++ b/ipc/mscom/ActivationContext.h
@@ -2,32 +2,39 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_mscom_ActivationContext_h
 #define mozilla_mscom_ActivationContext_h
 
+#include "mozilla/Attributes.h"
+
 #include <windows.h>
 
 namespace mozilla {
 namespace mscom {
 
-class ActivationContext
+class MOZ_RAII ActivationContext
 {
 public:
   explicit ActivationContext(HMODULE aLoadFromModule);
   ~ActivationContext();
 
   explicit operator bool() const
   {
     return mActCtx != INVALID_HANDLE_VALUE;
   }
 
+  ActivationContext(const ActivationContext&) = delete;
+  ActivationContext(ActivationContext&&) = delete;
+  ActivationContext& operator=(const ActivationContext&) = delete;
+  ActivationContext& operator=(ActivationContext&&) = delete;
+
 private:
   HANDLE    mActCtx;
   ULONG_PTR mActivationCookie;
 };
 
 } // namespace mscom
 } // namespace mozilla
 
--- a/ipc/mscom/Registration.cpp
+++ b/ipc/mscom/Registration.cpp
@@ -27,45 +27,74 @@
 #include <oaidl.h>
 #include <objidl.h>
 #include <rpcproxy.h>
 #include <shlwapi.h>
 
 /* This code MUST NOT use any non-inlined internal Mozilla APIs, as it will be
    compiled into DLLs that COM may load into non-Mozilla processes! */
 
-namespace {
+extern "C" {
 
 // This function is defined in generated code for proxy DLLs but is not declared
-// in rpcproxy.h, so we need this typedef.
-typedef void (RPC_ENTRY *GetProxyDllInfoFnPtr)(const ProxyFileInfo*** aInfo,
-                                               const CLSID** aId);
+// in rpcproxy.h, so we need this declaration.
+void RPC_ENTRY GetProxyDllInfo(const ProxyFileInfo*** aInfo, const CLSID** aId);
 
-} // anonymous namespace
+#if defined(_MSC_VER)
+extern IMAGE_DOS_HEADER __ImageBase;
+#endif
+
+}
 
 namespace mozilla {
 namespace mscom {
 
+static HMODULE
+GetContainingModule()
+{
+  HMODULE thisModule = nullptr;
+#if defined(_MSC_VER)
+  thisModule = reinterpret_cast<HMODULE>(&__ImageBase);
+#else
+  if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                         GET_MODULE_HANDLE_EX_UNCHANGED_REFCOUNT,
+                         reinterpret_cast<LPCTSTR>(&GetContainingModule),
+                         &thisModule)) {
+    return nullptr;
+  }
+#endif
+  return thisModule;
+}
+
+static bool
+GetContainingLibPath(wchar_t* aBuffer, size_t aBufferLen)
+{
+  HMODULE thisModule = GetContainingModule();
+  if (!thisModule) {
+    return false;
+  }
+
+  DWORD fileNameResult = GetModuleFileName(thisModule, aBuffer, aBufferLen);
+  if (!fileNameResult || (fileNameResult == aBufferLen &&
+        ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
+    return false;
+  }
+
+  return true;
+}
+
 static bool
 BuildLibPath(RegistrationFlags aFlags, wchar_t* aBuffer, size_t aBufferLen,
              const wchar_t* aLeafName)
 {
   if (aFlags == RegistrationFlags::eUseBinDirectory) {
-    HMODULE thisModule = nullptr;
-    if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
-                           GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
-                           reinterpret_cast<LPCTSTR>(&RegisterProxy),
-                           &thisModule)) {
+    if (!GetContainingLibPath(aBuffer, aBufferLen)) {
       return false;
     }
-    DWORD fileNameResult = GetModuleFileName(thisModule, aBuffer, aBufferLen);
-    if (!fileNameResult || (fileNameResult == aBufferLen &&
-          ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
-      return false;
-    }
+
     if (!PathRemoveFileSpec(aBuffer)) {
       return false;
     }
   } else if (aFlags == RegistrationFlags::eUseSystemDirectory) {
     UINT result = GetSystemDirectoryW(aBuffer, static_cast<UINT>(aBufferLen));
     if (!result || result > aBufferLen) {
       return false;
     }
@@ -74,16 +103,84 @@ BuildLibPath(RegistrationFlags aFlags, w
   }
 
   if (!PathAppend(aBuffer, aLeafName)) {
     return false;
   }
   return true;
 }
 
+static bool
+RegisterPSClsids(const ProxyFileInfo** aProxyInfo, const CLSID* aProxyClsid)
+{
+  while (*aProxyInfo) {
+    const ProxyFileInfo& curInfo = **aProxyInfo;
+    for (unsigned short idx = 0, size = curInfo.TableSize; idx < size; ++idx) {
+      HRESULT hr = CoRegisterPSClsid(*(curInfo.pStubVtblList[idx]->header.piid),
+                                     *aProxyClsid);
+      if (FAILED(hr)) {
+        return false;
+      }
+    }
+    ++aProxyInfo;
+  }
+
+  return true;
+}
+
+UniquePtr<RegisteredProxy>
+RegisterProxy()
+{
+  const ProxyFileInfo** proxyInfo = nullptr;
+  const CLSID* proxyClsid = nullptr;
+  GetProxyDllInfo(&proxyInfo, &proxyClsid);
+  if (!proxyInfo || !proxyClsid) {
+    return nullptr;
+  }
+
+  IUnknown* classObject = nullptr;
+  HRESULT hr = DllGetClassObject(*proxyClsid, IID_IUnknown, (void**)&classObject);
+  if (FAILED(hr)) {
+    return nullptr;
+  }
+
+  DWORD regCookie;
+  hr = CoRegisterClassObject(*proxyClsid, classObject, CLSCTX_INPROC_SERVER,
+                             REGCLS_MULTIPLEUSE, &regCookie);
+  if (FAILED(hr)) {
+    classObject->lpVtbl->Release(classObject);
+    return nullptr;
+  }
+
+  wchar_t modulePathBuf[MAX_PATH + 1] = {0};
+  if (!GetContainingLibPath(modulePathBuf, ArrayLength(modulePathBuf))) {
+    CoRevokeClassObject(regCookie);
+    classObject->lpVtbl->Release(classObject);
+    return nullptr;
+  }
+
+  ITypeLib* typeLib = nullptr;
+  hr = LoadTypeLibEx(modulePathBuf, REGKIND_NONE, &typeLib);
+  MOZ_ASSERT(SUCCEEDED(hr));
+  if (FAILED(hr)) {
+    CoRevokeClassObject(regCookie);
+    classObject->lpVtbl->Release(classObject);
+    return nullptr;
+  }
+
+  // RegisteredProxy takes ownership of classObject and typeLib references
+  auto result(MakeUnique<RegisteredProxy>(classObject, regCookie, typeLib));
+
+  if (!RegisterPSClsids(proxyInfo, proxyClsid)) {
+    return nullptr;
+  }
+
+  return result;
+}
+
 UniquePtr<RegisteredProxy>
 RegisterProxy(const wchar_t* aLeafName, RegistrationFlags aFlags)
 {
   wchar_t modulePathBuf[MAX_PATH + 1] = {0};
   if (!BuildLibPath(aFlags, modulePathBuf, ArrayLength(modulePathBuf),
                     aLeafName)) {
     return nullptr;
   }
@@ -95,17 +192,17 @@ RegisterProxy(const wchar_t* aLeafName, 
 
   // Instantiate an activation context so that CoGetClassObject will use any
   // COM metadata embedded in proxyDll's manifest to resolve CLSIDs.
   ActivationContext actCtx(proxyDll);
   if (!actCtx) {
     return nullptr;
   }
 
-  auto GetProxyDllInfoFn = reinterpret_cast<GetProxyDllInfoFnPtr>(
+  auto GetProxyDllInfoFn = reinterpret_cast<decltype(&GetProxyDllInfo)>(
       GetProcAddress(proxyDll, "GetProxyDllInfo"));
   if (!GetProxyDllInfoFn) {
     return nullptr;
   }
 
   const ProxyFileInfo** proxyInfo = nullptr;
   const CLSID* proxyClsid = nullptr;
   GetProxyDllInfoFn(&proxyInfo, &proxyClsid);
@@ -139,26 +236,18 @@ RegisterProxy(const wchar_t* aLeafName, 
     return nullptr;
   }
 
   // RegisteredProxy takes ownership of proxyDll, classObject, and typeLib
   // references
   auto result(MakeUnique<RegisteredProxy>(reinterpret_cast<uintptr_t>(proxyDll.disown()),
                                           classObject, regCookie, typeLib));
 
-  while (*proxyInfo) {
-    const ProxyFileInfo& curInfo = **proxyInfo;
-    for (unsigned short i = 0, e = curInfo.TableSize; i < e; ++i) {
-      hr = CoRegisterPSClsid(*(curInfo.pStubVtblList[i]->header.piid),
-                             *proxyClsid);
-      if (FAILED(hr)) {
-        return nullptr;
-      }
-    }
-    ++proxyInfo;
+  if (!RegisterPSClsids(proxyInfo, proxyClsid)) {
+    return nullptr;
   }
 
   return result;
 }
 
 UniquePtr<RegisteredProxy>
 RegisterTypelib(const wchar_t* aLeafName, RegistrationFlags aFlags)
 {
@@ -187,16 +276,29 @@ RegisteredProxy::RegisteredProxy(uintptr
   , mTypeLib(aTypeLib)
   , mIsRegisteredInMTA(IsCurrentThreadMTA())
 {
   MOZ_ASSERT(aClassObject);
   MOZ_ASSERT(aTypeLib);
   AddToRegistry(this);
 }
 
+RegisteredProxy::RegisteredProxy(IUnknown* aClassObject, uint32_t aRegCookie,
+                                 ITypeLib* aTypeLib)
+  : mModule(0)
+  , mClassObject(aClassObject)
+  , mRegCookie(aRegCookie)
+  , mTypeLib(aTypeLib)
+  , mIsRegisteredInMTA(IsCurrentThreadMTA())
+{
+  MOZ_ASSERT(aClassObject);
+  MOZ_ASSERT(aTypeLib);
+  AddToRegistry(this);
+}
+
 // If we're initializing from a typelib, it doesn't matter which apartment we
 // run in, so mIsRegisteredInMTA may always be set to false in this case.
 RegisteredProxy::RegisteredProxy(ITypeLib* aTypeLib)
   : mModule(0)
   , mClassObject(nullptr)
   , mRegCookie(0)
   , mTypeLib(aTypeLib)
   , mIsRegisteredInMTA(false)
--- a/ipc/mscom/Registration.h
+++ b/ipc/mscom/Registration.h
@@ -23,16 +23,18 @@ namespace mscom {
  * (1) The DLL exports GetProxyDllInfo. This is not exported by default; it must
  *     be specified in the EXPORTS section of the DLL's module definition file.
  */
 class RegisteredProxy
 {
 public:
   RegisteredProxy(uintptr_t aModule, IUnknown* aClassObject,
                   uint32_t aRegCookie, ITypeLib* aTypeLib);
+  RegisteredProxy(IUnknown* aClassObject, uint32_t aRegCookie,
+                  ITypeLib* aTypeLib);
   explicit RegisteredProxy(ITypeLib* aTypeLib);
   RegisteredProxy(RegisteredProxy&& aOther);
   RegisteredProxy& operator=(RegisteredProxy&& aOther);
 
   ~RegisteredProxy();
 
   HRESULT GetTypeInfoForInterface(REFIID aIid, ITypeInfo** aOutTypeInfo) const;
 
@@ -58,16 +60,20 @@ private:
 };
 
 enum class RegistrationFlags
 {
   eUseBinDirectory,
   eUseSystemDirectory
 };
 
+// For our own DLL that we are currently executing in (ie, xul).
+// Assumes corresponding TLB is embedded in resources.
+UniquePtr<RegisteredProxy> RegisterProxy();
+
 // For DLL files. Assumes corresponding TLB is embedded in resources.
 UniquePtr<RegisteredProxy> RegisterProxy(const wchar_t* aLeafName,
                                          RegistrationFlags aFlags =
                                            RegistrationFlags::eUseBinDirectory);
 // For standalone TLB files.
 UniquePtr<RegisteredProxy> RegisterTypelib(const wchar_t* aLeafName,
                                            RegistrationFlags aFlags =
                                              RegistrationFlags::eUseBinDirectory);
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -248,18 +248,16 @@ IsMarkedBlack(NativeObject* obj);
 template <typename T>
 struct InternalBarrierMethods {};
 
 template <typename T>
 struct InternalBarrierMethods<T*>
 {
     static bool isMarkable(T* v) { return v != nullptr; }
 
-    static bool isMarkableTaggedPointer(T* v) { return !IsNullTaggedPointer(v); }
-
     static void preBarrier(T* v) { T::writeBarrierPre(v); }
 
     static void postBarrier(T** vp, T* prev, T* next) { T::writeBarrierPost(vp, prev, next); }
 
     static void readBarrier(T* v) { T::readBarrier(v); }
 };
 
 template <typename S> struct PreBarrierFunctor : public VoidDefaultAdaptor<S> {
@@ -269,17 +267,16 @@ template <typename S> struct PreBarrierF
 template <typename S> struct ReadBarrierFunctor : public VoidDefaultAdaptor<S> {
     template <typename T> void operator()(T* t);
 };
 
 template <>
 struct InternalBarrierMethods<Value>
 {
     static bool isMarkable(const Value& v) { return v.isGCThing(); }
-    static bool isMarkableTaggedPointer(const Value& v) { return isMarkable(v); }
 
     static void preBarrier(const Value& v) {
         DispatchTyped(PreBarrierFunctor<Value>(), v);
     }
 
     static void postBarrier(Value* vp, const Value& prev, const Value& next) {
         MOZ_ASSERT(!CurrentThreadIsIonCompiling());
         MOZ_ASSERT(vp);
@@ -305,18 +302,16 @@ struct InternalBarrierMethods<Value>
         DispatchTyped(ReadBarrierFunctor<Value>(), v);
     }
 };
 
 template <>
 struct InternalBarrierMethods<jsid>
 {
     static bool isMarkable(jsid id) { return JSID_IS_GCTHING(id); }
-    static bool isMarkableTaggedPointer(jsid id) { return isMarkable(id); }
-
     static void preBarrier(jsid id) { DispatchTyped(PreBarrierFunctor<jsid>(), id); }
     static void postBarrier(jsid* idp, jsid prev, jsid next) {}
 };
 
 // Base class of all barrier types.
 template <typename T>
 class BarrieredBase
 {
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -295,20 +295,16 @@ class TenuredCell : public Cell
 
     // Mark bit management.
     MOZ_ALWAYS_INLINE bool isMarked(uint32_t color = BLACK) const;
     // The return value indicates if the cell went from unmarked to marked.
     MOZ_ALWAYS_INLINE bool markIfUnmarked(uint32_t color = BLACK) const;
     MOZ_ALWAYS_INLINE void unmark(uint32_t color) const;
     MOZ_ALWAYS_INLINE void copyMarkBitsFrom(const TenuredCell* src);
 
-    // Note: this is in TenuredCell because JSObject subclasses are sometimes
-    // used tagged.
-    static MOZ_ALWAYS_INLINE bool isNullLike(const Cell* thing) { return !thing; }
-
     // Access to the arena.
     inline Arena* arena() const;
     inline AllocKind getAllocKind() const;
     inline JS::TraceKind getTraceKind() const;
     inline JS::Zone* zone() const;
     inline JS::Zone* zoneFromAnyThread() const;
     inline bool isInsideZone(JS::Zone* zone) const;
 
@@ -1280,17 +1276,17 @@ TenuredCell::isInsideZone(JS::Zone* zone
 {
     return zone == arena()->zone;
 }
 
 /* static */ MOZ_ALWAYS_INLINE void
 TenuredCell::readBarrier(TenuredCell* thing)
 {
     MOZ_ASSERT(!CurrentThreadIsIonCompiling());
-    MOZ_ASSERT(!isNullLike(thing));
+    MOZ_ASSERT(thing);
 
     // It would be good if barriers were never triggered during collection, but
     // at the moment this can happen e.g. when rekeying tables containing
     // read-barriered GC things after a moving GC.
     //
     // TODO: Fix this and assert we're not collecting if we're on the main
     // thread.
 
@@ -1313,17 +1309,16 @@ TenuredCell::readBarrier(TenuredCell* th
 
 void
 AssertSafeToSkipBarrier(TenuredCell* thing);
 
 /* static */ MOZ_ALWAYS_INLINE void
 TenuredCell::writeBarrierPre(TenuredCell* thing)
 {
     MOZ_ASSERT(!CurrentThreadIsIonCompiling());
-    MOZ_ASSERT_IF(thing, !isNullLike(thing));
     if (!thing)
         return;
 
 #ifdef JS_GC_ZEAL
     // When verifying pre barriers we need to switch on all barriers, even
     // those on the Atoms Zone. Normally, we never enter a parse task when
     // collecting in the atoms zone, so will filter out atoms below.
     // Unfortuantely, If we try that when verifying pre-barriers, we'd never be
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -497,17 +497,17 @@ js::TraceRoot(JSTracer* trc, ReadBarrier
     TraceRoot(trc, thingp->unsafeGet(), name);
 }
 
 template <typename T>
 void
 js::TraceNullableRoot(JSTracer* trc, T* thingp, const char* name)
 {
     AssertRootMarkingPhase(trc);
-    if (InternalBarrierMethods<T>::isMarkableTaggedPointer(*thingp))
+    if (InternalBarrierMethods<T>::isMarkable(*thingp))
         DispatchToTracer(trc, ConvertToBase(thingp), name);
 }
 
 template <typename T>
 void
 js::TraceNullableRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
 {
     TraceNullableRoot(trc, thingp->unsafeGet(), name);
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -409,24 +409,16 @@ ToMarkable(const Value& v)
 }
 
 inline Cell*
 ToMarkable(Cell* cell)
 {
     return cell;
 }
 
-// Return true if the pointer is nullptr, or if it is a tagged pointer to
-// nullptr.
-MOZ_ALWAYS_INLINE bool
-IsNullTaggedPointer(void* p)
-{
-    return uintptr_t(p) <= LargestTaggedNullCellPointer;
-}
-
 // Wrap a GC thing pointer into a new Value or jsid. The type system enforces
 // that the thing pointer is a wrappable type.
 template <typename S, typename T>
 struct RewrapTaggedPointer{};
 #define DECLARE_REWRAP(S, T, method, prefix) \
     template <> struct RewrapTaggedPointer<S, T> { \
         static S wrap(T* thing) { return method ( prefix thing ); } \
     }
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -300,17 +300,16 @@ class JSObject : public js::gc::Cell
     /* GC support. */
 
     void traceChildren(JSTracer* trc);
 
     void fixupAfterMovingGC();
 
     static const JS::TraceKind TraceKind = JS::TraceKind::Object;
     static const size_t MaxTagBits = 3;
-    static bool isNullLike(const JSObject* obj) { return uintptr_t(obj) < (1 << MaxTagBits); }
 
     MOZ_ALWAYS_INLINE JS::Zone* zone() const {
         return group_->zone();
     }
     MOZ_ALWAYS_INLINE JS::shadow::Zone* shadowZone() const {
         return JS::shadow::Zone::asShadowZone(zone());
     }
     MOZ_ALWAYS_INLINE JS::Zone* zoneFromAnyThread() const {
@@ -636,35 +635,31 @@ struct JSObject_Slots2 : JSObject { void
 struct JSObject_Slots4 : JSObject { void* data[3]; js::Value fslots[4]; };
 struct JSObject_Slots8 : JSObject { void* data[3]; js::Value fslots[8]; };
 struct JSObject_Slots12 : JSObject { void* data[3]; js::Value fslots[12]; };
 struct JSObject_Slots16 : JSObject { void* data[3]; js::Value fslots[16]; };
 
 /* static */ MOZ_ALWAYS_INLINE void
 JSObject::readBarrier(JSObject* obj)
 {
-    MOZ_ASSERT_IF(obj, !isNullLike(obj));
     if (obj && obj->isTenured())
         obj->asTenured().readBarrier(&obj->asTenured());
 }
 
 /* static */ MOZ_ALWAYS_INLINE void
 JSObject::writeBarrierPre(JSObject* obj)
 {
-    MOZ_ASSERT_IF(obj, !isNullLike(obj));
     if (obj && obj->isTenured())
         obj->asTenured().writeBarrierPre(&obj->asTenured());
 }
 
 /* static */ MOZ_ALWAYS_INLINE void
 JSObject::writeBarrierPost(void* cellp, JSObject* prev, JSObject* next)
 {
     MOZ_ASSERT(cellp);
-    MOZ_ASSERT_IF(next, !IsNullTaggedPointer(next));
-    MOZ_ASSERT_IF(prev, !IsNullTaggedPointer(prev));
 
     // If the target needs an entry, add it.
     js::gc::StoreBuffer* buffer;
     if (next && (buffer = next->storeBuffer())) {
         // If we know that the prev has already inserted an entry, we can skip
         // doing the lookup to add the new entry. Note that we cannot safely
         // assert the presence of the entry because it may have been added
         // via a different store buffer.
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -518,17 +518,17 @@ class JSString : public js::gc::TenuredC
     static MOZ_ALWAYS_INLINE void readBarrier(JSString* thing) {
         if (thing->isPermanentAtom())
             return;
 
         TenuredCell::readBarrier(thing);
     }
 
     static MOZ_ALWAYS_INLINE void writeBarrierPre(JSString* thing) {
-        if (isNullLike(thing) || thing->isPermanentAtom())
+        if (!thing || thing->isPermanentAtom())
             return;
 
         TenuredCell::writeBarrierPre(thing);
     }
 
   private:
     JSString() = delete;
     JSString(const JSString& other) = delete;
--- a/js/src/vm/TaggedProto.h
+++ b/js/src/vm/TaggedProto.h
@@ -64,20 +64,16 @@ template <>
 struct InternalBarrierMethods<TaggedProto>
 {
     static void preBarrier(TaggedProto& proto);
 
     static void postBarrier(TaggedProto* vp, TaggedProto prev, TaggedProto next);
 
     static void readBarrier(const TaggedProto& proto);
 
-    static bool isMarkableTaggedPointer(const TaggedProto& proto) {
-        return proto.isObject();
-    }
-
     static bool isMarkable(const TaggedProto& proto) {
         return proto.isObject();
     }
 };
 
 template <class Wrapper>
 class WrappedPtrOperations<TaggedProto, Wrapper>
 {
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -2154,17 +2154,17 @@ class MOZ_STACK_CLASS ModuleValidator
         if (!globalMap_.putNew(name, global))
             return false;
         *func = validationLifo_.new_<Func>(name, firstUse, funcIndex);
         return *func && functions_.append(*func);
     }
     bool declareFuncPtrTable(Sig&& sig, PropertyName* name, uint32_t firstUse, uint32_t mask,
                              uint32_t* index)
     {
-        if (mask > MaxTableLength)
+        if (mask > MaxTableInitialLength)
             return failCurrentOffset("function pointer table too big");
         uint32_t sigIndex;
         if (!newSig(Move(sig), &sigIndex))
             return false;
         if (!mg_.initSigTableLength(sigIndex, mask + 1))
             return false;
         Global* global = validationLifo_.new_<Global>(Global::FuncPtrTable);
         if (!global)
--- a/js/src/wasm/WasmBinaryConstants.h
+++ b/js/src/wasm/WasmBinaryConstants.h
@@ -450,21 +450,22 @@ static const unsigned InitialGlobalDataB
 
 static const unsigned MaxTypes               =  1000000;
 static const unsigned MaxFuncs               =  1000000;
 static const unsigned MaxImports             =   100000;
 static const unsigned MaxExports             =   100000;
 static const unsigned MaxGlobals             =  1000000;
 static const unsigned MaxDataSegments        =   100000;
 static const unsigned MaxElemSegments        = 10000000;
-static const unsigned MaxTableLength         = 10000000;
+static const unsigned MaxTableInitialLength  = 10000000;
 static const unsigned MaxStringBytes         =   100000;
 static const unsigned MaxLocals              =    50000;
 static const unsigned MaxParams              =     1000;
 static const unsigned MaxBrTableElems        =  1000000;
+static const unsigned MaxMemoryInitialBytes  = 1024 * 1024 * 1024;
 static const unsigned MaxModuleBytes         = 1024 * 1024 * 1024;
 static const unsigned MaxFunctionBytes       =         128 * 1024;
 
 // To be able to assign function indices during compilation while the number of
 // imports is still unknown, asm.js sets a maximum number of imports so it can
 // immediately start handing out function indices starting at the maximum + 1.
 // this means that there is a "hole" between the last import and the first
 // definition, but that's fine.
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -209,16 +209,21 @@ CodeSegment::create(JSContext* cx,
                     const LinkData& linkData,
                     const Metadata& metadata,
                     HandleWasmMemoryObject memory)
 {
     MOZ_ASSERT(bytecode.length() % gc::SystemPageSize() == 0);
     MOZ_ASSERT(linkData.globalDataLength % gc::SystemPageSize() == 0);
     MOZ_ASSERT(linkData.functionCodeLength < bytecode.length());
 
+    // These should always exist and should never be first in the code segment.
+    MOZ_ASSERT(linkData.interruptOffset != 0);
+    MOZ_ASSERT(linkData.outOfBoundsOffset != 0);
+    MOZ_ASSERT(linkData.unalignedAccessOffset != 0);
+
     auto cs = cx->make_unique<CodeSegment>();
     if (!cs)
         return nullptr;
 
     cs->bytes_ = AllocateCodeSegment(cx, bytecode.length() + linkData.globalDataLength);
     if (!cs->bytes_)
         return nullptr;
 
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -623,16 +623,17 @@ ModuleGenerator::finishCodegen()
         return false;
 
     debugTrapStub.offsetBy(offsetInWhole);
     if (!metadata_->codeRanges.emplaceBack(CodeRange::DebugTrap, debugTrapStub))
         return false;
 
     // Fill in LinkData with the offsets of these stubs.
 
+    linkData_.unalignedAccessOffset = unalignedAccessExit.begin;
     linkData_.outOfBoundsOffset = outOfBoundsExit.begin;
     linkData_.interruptOffset = interruptExit.begin;
 
     // Now that all other code has been emitted, patch all remaining callsites
     // then far jumps. Patching callsites can generate far jumps so there is an
     // ordering dependency.
 
     if (!patchCallSites(&trapExits))
@@ -1079,17 +1080,17 @@ ModuleGenerator::finishFuncDefs()
     return true;
 }
 
 bool
 ModuleGenerator::initSigTableLength(uint32_t sigIndex, uint32_t length)
 {
     MOZ_ASSERT(isAsmJS());
     MOZ_ASSERT(length != 0);
-    MOZ_ASSERT(length <= MaxTableLength);
+    MOZ_ASSERT(length <= MaxTableInitialLength);
 
     MOZ_ASSERT(env_->asmJSSigToTableIndex[sigIndex] == 0);
     env_->asmJSSigToTableIndex[sigIndex] = numTables_;
 
     TableDesc& table = env_->tables[numTables_++];
     table.kind = TableKind::TypedFunction;
     table.limits.initial = length;
     table.limits.maximum = Some(length);
--- a/js/src/wasm/WasmSignalHandlers.cpp
+++ b/js/src/wasm/WasmSignalHandlers.cpp
@@ -1167,16 +1167,20 @@ HandleFault(int signum, siginfo_t* info,
 #endif
     } else {
         if (!IsHeapAccessAddress(*instance, faultingAddress))
             return false;
     }
 
 #ifdef JS_CODEGEN_ARM
     if (signal == Signal::BusError) {
+        // TODO: We may see a bus error for something that is an unaligned access that
+        // partly overlaps the end of the heap.  In this case, it is an out-of-bounds
+        // error and we should signal that properly, but to do so we must inspect
+        // the operand of the failed access.
         *ppc = instance->codeSegment().unalignedAccessCode();
         return true;
     }
 #endif
 
     HandleMemoryAccess(context, pc, faultingAddress, *instance, ppc);
     return true;
 }
--- a/js/src/wasm/WasmTable.cpp
+++ b/js/src/wasm/WasmTable.cpp
@@ -145,17 +145,17 @@ Table::grow(uint32_t delta, JSContext* c
     // onMovingGrowTable does not fire when length == maximum.
     if (!delta)
         return length_;
 
     uint32_t oldLength = length_;
 
     CheckedInt<uint32_t> newLength = oldLength;
     newLength += delta;
-    if (!newLength.isValid() || newLength.value() > MaxTableLength)
+    if (!newLength.isValid())
         return -1;
 
     if (maximum_ && newLength.value() > maximum_.value())
         return -1;
 
     MOZ_ASSERT(movingGrowable());
 
     JSRuntime* rt = cx;  // Use JSRuntime's MallocProvider to avoid throwing.
--- a/js/src/wasm/WasmValidate.cpp
+++ b/js/src/wasm/WasmValidate.cpp
@@ -868,17 +868,17 @@ DecodeTableLimits(Decoder& d, TableDescV
 
     if (elementType != uint32_t(TypeCode::AnyFunc))
         return d.fail("expected 'anyfunc' element type");
 
     Limits limits;
     if (!DecodeLimits(d, &limits))
         return false;
 
-    if (limits.initial > MaxTableLength)
+    if (limits.initial > MaxTableInitialLength)
         return d.fail("too many table elements");
 
     if (tables->length())
         return d.fail("already have default table");
 
     return tables->emplaceBack(TableKind::AnyFunction, limits);
 }
 
@@ -928,17 +928,17 @@ DecodeMemoryLimits(Decoder& d, ModuleEnv
         return d.fail("already have default memory");
 
     Limits memory;
     if (!DecodeLimits(d, &memory))
         return false;
 
     CheckedInt<uint32_t> initialBytes = memory.initial;
     initialBytes *= PageSize;
-    if (!initialBytes.isValid() || initialBytes.value() > uint32_t(INT32_MAX))
+    if (!initialBytes.isValid() || initialBytes.value() > MaxMemoryInitialBytes)
         return d.fail("initial memory size too big");
 
     memory.initial = initialBytes.value();
 
     if (memory.maximum) {
         CheckedInt<uint32_t> maximumBytes = *memory.maximum;
         maximumBytes *= PageSize;
         if (!maximumBytes.isValid())
@@ -1413,17 +1413,17 @@ DecodeElemSection(Decoder& d, ModuleEnvi
         InitExpr offset;
         if (!DecodeInitializerExpression(d, env->globals, ValType::I32, &offset))
             return false;
 
         uint32_t numElems;
         if (!d.readVarU32(&numElems))
             return d.fail("expected segment size");
 
-        if (numElems > MaxTableLength)
+        if (numElems > MaxTableInitialLength)
             return d.fail("too many table elements");
 
         Uint32Vector elemFuncIndices;
         if (!elemFuncIndices.resize(numElems))
             return false;
 
         for (uint32_t i = 0; i < numElems; i++) {
             if (!d.readVarU32(&elemFuncIndices[i]))
@@ -1559,16 +1559,19 @@ DecodeDataSection(Decoder& d, ModuleEnvi
 
         DataSegment seg;
         if (!DecodeInitializerExpression(d, env->globals, ValType::I32, &seg.offset))
             return false;
 
         if (!d.readVarU32(&seg.length))
             return d.fail("expected segment size");
 
+        if (seg.length > MaxMemoryInitialBytes)
+            return d.fail("segment size too big");
+
         seg.bytecodeOffset = d.currentOffset();
 
         if (!d.readBytes(seg.length))
             return d.fail("data segment shorter than declared");
 
         if (!env->dataSegments.append(seg))
             return false;
     }
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
@@ -105,19 +105,20 @@ public:
     return NS_OK;
   }
 
 private:
   virtual ~PeerConnectionCtxObserver()
     {
       nsCOMPtr<nsIObserverService> observerService =
         services::GetObserverService();
-      if (observerService)
+      if (observerService) {
         observerService->RemoveObserver(this, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
         observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+      }
     }
 };
 
 NS_IMPL_ISUPPORTS(PeerConnectionCtxObserver, nsIObserver);
 }
 
 namespace mozilla {
 
@@ -335,17 +336,17 @@ PeerConnectionCtx::EverySecondTelemetryC
   }
   MOZ_ASSERT(stsThread);
 
   nsAutoPtr<RTCStatsQueries> queries(new RTCStatsQueries);
   for (auto p = ctx->mPeerConnections.begin();
         p != ctx->mPeerConnections.end(); ++p) {
     if (p->second->HasMedia()) {
       if (!queries->append(nsAutoPtr<RTCStatsQuery>(new RTCStatsQuery(true)))) {
-	return;
+        return;
       }
       if (NS_WARN_IF(NS_FAILED(p->second->BuildStatsQuery_m(nullptr, // all tracks
                                                             queries->back())))) {
         queries->popBack();
       } else {
         MOZ_ASSERT(queries->back()->report);
       }
     }
--- a/mfbt/Maybe.h
+++ b/mfbt/Maybe.h
@@ -11,16 +11,17 @@
 
 #include "mozilla/Alignment.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Move.h"
 #include "mozilla/TypeTraits.h"
 
 #include <new>  // for placement new
+#include <ostream>
 #include <type_traits>
 
 namespace mozilla {
 
 struct Nothing { };
 
 /*
  * Maybe is a container class which contains either zero or one elements. It
@@ -447,16 +448,27 @@ public:
    */
   template<typename... Args>
   void emplace(Args&&... aArgs)
   {
     MOZ_ASSERT(!mIsSome);
     ::new (mStorage.addr()) T(Forward<Args>(aArgs)...);
     mIsSome = true;
   }
+
+  friend std::ostream&
+  operator<<(std::ostream& aStream, const Maybe<T>& aMaybe)
+  {
+    if (aMaybe) {
+      aStream << aMaybe.ref();
+    } else {
+      aStream << "<Nothing>";
+    }
+    return aStream;
+  }
 };
 
 /*
  * Some() creates a Maybe<T> value containing the provided T value. If T has a
  * move constructor, it's used to make this as efficient as possible.
  *
  * Some() selects the type of Maybe it returns by removing any const, volatile,
  * or reference qualifiers from the type of the value you pass to it. This gives
--- a/mobile/android/chrome/content/config.xhtml
+++ b/mobile/android/chrome/content/config.xhtml
@@ -11,16 +11,17 @@
 <!ENTITY % configDTD SYSTEM "chrome://browser/locale/config.dtd">
 %configDTD;
 ]>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
 
 <head>
     <meta name="viewport" content="width=device-width; user-scalable=0" />
+    <meta charset="UTF-8" />
 
     <link rel="stylesheet" href="chrome://browser/skin/config.css" type="text/css"/>
     <script type="text/javascript;version=1.8" src="chrome://browser/content/config.js"></script>
 </head>
 
 <body dir="&locale.dir;" onload="NewPrefDialog.init(); AboutConfig.init();"
                          onunload="AboutConfig.uninit();">
 
--- a/mobile/android/config/tooltool-manifests/android-gradle-dependencies/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android-gradle-dependencies/releng.manifest
@@ -10,19 +10,19 @@
 "size": 573952124,
 "visibility": "internal",
 "digest": "1d495d7a7386af3f27b14982e0ff7b0963fd1a63a08040b9b1db0e94c9681fa3704c195ba8be23b5f73e15101b2b767293bc8f96e0584e17867ef13b074e5038",
 "algorithm": "sha512",
 "filename": "android-sdk-linux.tar.xz",
 "unpack": true
 },
 {
-"version": "rustc 1.15.0-beta.2 (519656798 2016-12-30) repack",
-"size": 110451636,
-"digest": "a7b34249eb4981b3b553b319515d3f333245cc0e38a631e8d0de35e130b001270783c0dd6fb58f0bf7900e3694be49453c8c23e6589996123ebddc7308d3039d",
+"version": "rustc 1.15.0-beta.4 (ad78c04a9 2017-01-18) repack",
+"size": 92947272,
+"digest": "9fdc415d422ca7fb3b8e7044e4656b60cba6697ee609f8a704423fa2fc7e5de4b7d1ce52b1abfae51d8ecc3e1a4df0a8dbae6a43c5357e3a0b6e0b055178186c",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
 "version": "sccache rev b21198a7183a2fe226ff49348b1c0b51bae9f4f8",
 "algorithm": "sha512",
 "visibility": "public",
--- a/mobile/android/config/tooltool-manifests/android-x86/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android-x86/releng.manifest
@@ -43,19 +43,19 @@
 "version": "gcc 4.9.4 + PR64905",
 "size": 101297752,
 "digest": "42aa2e3fdd232b5e390472a788e7f7db71a1fee4221e260b6cb58c9a1d73e6cdd10afcbac137f7844290169cd6b561b424ecc92b159e9726b0ad5de3f478a8be",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"version": "rustc 1.15.0-beta.2 (519656798 2016-12-30) repack",
-"size": 110451636,
-"digest": "a7b34249eb4981b3b553b319515d3f333245cc0e38a631e8d0de35e130b001270783c0dd6fb58f0bf7900e3694be49453c8c23e6589996123ebddc7308d3039d",
+"version": "rustc 1.15.0-beta.4 (ad78c04a9 2017-01-18) repack",
+"size": 92947272,
+"digest": "9fdc415d422ca7fb3b8e7044e4656b60cba6697ee609f8a704423fa2fc7e5de4b7d1ce52b1abfae51d8ecc3e1a4df0a8dbae6a43c5357e3a0b6e0b055178186c",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
 "algorithm": "sha512",
 "visibility": "public",
 "filename": "jcentral.tar.xz",
--- a/mobile/android/config/tooltool-manifests/android/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android/releng.manifest
@@ -68,19 +68,19 @@
 "algorithm": "sha512",
 "visibility": "public",
 "filename": "gradle-dist.tar.xz",
 "unpack": true,
 "digest": "e3cfe7f8259ad97722243d4e873d5a05c014bfc24d637427f89d804bf5073290229c778ea303142cf06c2dc79e0492f23521f57d3a73825f55b8db587317646f",
 "size": 51753660
 },
 {
-"version": "rustc 1.15.0-beta.2 (519656798 2016-12-30) repack",
-"size": 110451636,
-"digest": "a7b34249eb4981b3b553b319515d3f333245cc0e38a631e8d0de35e130b001270783c0dd6fb58f0bf7900e3694be49453c8c23e6589996123ebddc7308d3039d",
+"version": "rustc 1.15.0-beta.4 (ad78c04a9 2017-01-18) repack",
+"size": 92947272,
+"digest": "9fdc415d422ca7fb3b8e7044e4656b60cba6697ee609f8a704423fa2fc7e5de4b7d1ce52b1abfae51d8ecc3e1a4df0a8dbae6a43c5357e3a0b6e0b055178186c",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
 },
 {
 "algorithm": "sha512",
 "visibility": "public",
 "filename": "dotgradle.tar.xz",
--- a/mobile/android/themes/core/jar.mn
+++ b/mobile/android/themes/core/jar.mn
@@ -49,16 +49,17 @@ chrome.jar:
   skin/images/blocked-warning.png           (images/blocked-warning.png)
   skin/images/checkbox_checked.png          (images/checkbox_checked.png)
   skin/images/checkbox_checked_disabled.png (images/checkbox_checked_disabled.png)
   skin/images/checkbox_checked_pressed.png  (images/checkbox_checked_pressed.png)
   skin/images/checkbox_unchecked.png          (images/checkbox_unchecked.png)
   skin/images/checkbox_unchecked_disabled.png (images/checkbox_unchecked_disabled.png)
   skin/images/checkbox_unchecked_pressed.png  (images/checkbox_unchecked_pressed.png)
   skin/images/chevron.png                   (images/chevron.png)
+  skin/images/chevron-rtl.png               (images/chevron-rtl.png)
   skin/images/dropmarker.svg                (images/dropmarker.svg)
   skin/images/dropmarker-right.svg          (images/dropmarker-right.svg)
   skin/images/errorpage-warning.png         (images/errorpage-warning.png)
   skin/images/exitfullscreen.svg            (images/exitfullscreen.svg)
   skin/images/fullscreen.svg                (images/fullscreen.svg)
   skin/images/grey-caution.svg              (images/grey-caution.svg)
   skin/images/certerror-warning.png         (images/certerror-warning.png)
   skin/images/throbber.png                  (images/throbber.png)
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1220,16 +1220,20 @@ pref("content.sink.pending_event_mode", 
 // Disable popups from plugins by default
 //   0 = openAllowed
 //   1 = openControlled
 //   2 = openAbused
 pref("privacy.popups.disable_from_plugins", 2);
 
 // send "do not track" HTTP header, disabled by default
 pref("privacy.donottrackheader.enabled",    false);
+// If true, close buton will be shown on permission prompts
+// and for all PopupNotifications, the secondary action of
+// the popup will be called when the popup is dismissed.
+pref("privacy.permissionPrompts.showCloseButton", false);
 // Enforce tracking protection in all modes
 pref("privacy.trackingprotection.enabled",  false);
 // Enforce tracking protection in Private Browsing mode
 pref("privacy.trackingprotection.pbmode.enabled",  true);
 // Annotate channels based on the tracking protection list in all modes
 pref("privacy.trackingprotection.annotate_channels",  false);
 // Lower the priority of network loads for resources on the tracking protection list.
 // Note that this requires the privacy.trackingprotection.annotate_channels pref to be on in order to have any effect.
@@ -2880,17 +2884,21 @@ pref("dom.ipc.plugins.asyncInit.enabled"
 
 #ifdef RELEASE_OR_BETA
 pref("dom.ipc.plugins.asyncdrawing.enabled", false);
 #else
 // Allow the AsyncDrawing mode to be used for plugins in dev channels.
 pref("dom.ipc.plugins.asyncdrawing.enabled", true);
 #endif
 
+#ifdef NIGHTLY_BUILD
+pref("dom.ipc.processCount", 2);
+#else
 pref("dom.ipc.processCount", 1);
+#endif
 
 // Disable support for SVG
 pref("svg.disabled", false);
 
 // Override default dom.ipc.processCount for some remote content process types.
 pref("dom.ipc.processCount.webLargeAllocation", 2);
 
 // Pref to control whether we use separate content processes for top-level load
--- a/mozglue/misc/TimeStamp.h
+++ b/mozglue/misc/TimeStamp.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 mozilla_TimeStamp_h
 #define mozilla_TimeStamp_h
 
 #include <stdint.h>
 #include <algorithm>  // for std::min, std::max
+#include <ostream>
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/Types.h"
 
 namespace IPC {
 template<typename T> struct ParamTraits;
@@ -274,16 +275,21 @@ public:
   {
     return mValue == 0;
   }
   explicit operator bool() const
   {
     return mValue != 0;
   }
 
+  friend std::ostream& operator<<(std::ostream& aStream,
+                                  const BaseTimeDuration& aDuration) {
+    return aStream << aDuration.ToMilliseconds() << " ms";
+  }
+
   // Return a best guess at the system's current timing resolution,
   // which might be variable.  BaseTimeDurations below this order of
   // magnitude are meaningless, and those at the same order of
   // magnitude or just above are suspect.
   static BaseTimeDuration Resolution() {
     return FromTicks(BaseTimeDurationPlatformUtils::ResolutionInTicks());
   }
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -8340,35 +8340,16 @@ nsHttpChannel::ReportNetVSCacheTelemetry
         Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_NOTREVALIDATED, onStopDiff);
     }
 
     if (mDidReval) {
         // We don't report revalidated probes as the data would be skewed.
         return;
     }
 
-    uint32_t diskStorageSizeK = 0;
-    rv = mCacheEntry->GetDiskStorageSizeInKB(&diskStorageSizeK);
-    if (NS_FAILED(rv)) {
-        return;
-    }
-
-    nsAutoCString contentType;
-    if (mResponseHead && mResponseHead->HasContentType()) {
-        mResponseHead->ContentType(contentType);
-    }
-    bool isImage = StringBeginsWith(contentType, NS_LITERAL_CSTRING("image/"));
-    if (isImage) {
-        Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_ISIMG, onStartDiff);
-        Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_ISIMG, onStopDiff);
-    } else {
-        Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_NOTIMG, onStartDiff);
-        Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_NOTIMG, onStopDiff);
-    }
-
     if (mCacheOpenWithPriority) {
         if (mCacheQueueSizeWhenOpen < 5) {
             Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_QSMALL_HIGHPRI, onStartDiff);
             Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_QSMALL_HIGHPRI, onStopDiff);
         } else if (mCacheQueueSizeWhenOpen < 10) {
             Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_QMED_HIGHPRI, onStartDiff);
             Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_QMED_HIGHPRI, onStopDiff);
         } else {
@@ -8383,37 +8364,24 @@ nsHttpChannel::ReportNetVSCacheTelemetry
             Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_QMED_NORMALPRI, onStartDiff);
             Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_QMED_NORMALPRI, onStopDiff);
         } else {
             Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_QBIG_NORMALPRI, onStartDiff);
             Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_QBIG_NORMALPRI, onStopDiff);
         }
     }
 
-    if (diskStorageSizeK < 32) {
-        if (mCacheOpenWithPriority) {
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_SMALL_HIGHPRI, onStartDiff);
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_SMALL_HIGHPRI, onStopDiff);
-        } else {
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_SMALL_NORMALPRI, onStartDiff);
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_SMALL_NORMALPRI, onStopDiff);
-        }
-    } else if (diskStorageSizeK < 256) {
-        if (mCacheOpenWithPriority) {
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_MED_HIGHPRI, onStartDiff);
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_MED_HIGHPRI, onStopDiff);
-        } else {
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_MED_NORMALPRI, onStartDiff);
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_MED_NORMALPRI, onStopDiff);
-        }
+    uint32_t diskStorageSizeK = 0;
+    rv = mCacheEntry->GetDiskStorageSizeInKB(&diskStorageSizeK);
+    if (NS_FAILED(rv)) {
+        return;
+    }
+
+    // No significant difference was observed between different sizes for |onStartDiff|
+    if (diskStorageSizeK < 256) {
+        Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_SMALL, onStopDiff);
     } else {
-        if (mCacheOpenWithPriority) {
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_LARGE_HIGHPRI, onStartDiff);
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_LARGE_HIGHPRI, onStopDiff);
-        } else {
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTART_LARGE_NORMALPRI, onStartDiff);
-            Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_LARGE_NORMALPRI, onStopDiff);
-        }
+        Telemetry::Accumulate(Telemetry::HTTP_NET_VS_CACHE_ONSTOP_LARGE, onStopDiff);
     }
 }
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -34,16 +34,18 @@
 #include "nsIEventTarget.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIInputStream.h"
 #include "nsIThrottledInputChannel.h"
 #include "nsITransport.h"
 #include "nsIOService.h"
 #include "nsIRequestContext.h"
 #include "nsIHttpAuthenticator.h"
+#include "NSSErrorsService.h"
+#include "sslerr.h"
 #include <algorithm>
 
 #ifdef MOZ_WIDGET_GONK
 #include "NetStatistics.h"
 #endif
 
 //-----------------------------------------------------------------------------
 
@@ -938,17 +940,19 @@ nsHttpTransaction::Close(nsresult reason
     // Never restart transactions that are marked as sticky to their conenction.
     // We use that capability to identify transactions bound to connection based
     // authentication.  Reissuing them on a different connections will break
     // this bondage.  Major issue may arise when there is an NTLM message auth
     // header on the transaction and we send it to a different NTLM authenticated
     // connection.  It will break that connection and also confuse the channel's
     // auth provider, beliving the cached credentials are wrong and asking for
     // the password mistakenly again from the user.
-    if ((reason == NS_ERROR_NET_RESET || reason == NS_OK) &&
+    if ((reason == NS_ERROR_NET_RESET ||
+         reason == NS_OK ||
+         reason == psm::GetXPCOMFromNSSError(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA)) &&
         !(mCaps & NS_HTTP_STICKY_CONNECTION)) {
 
         if (mForceRestart && NS_SUCCEEDED(Restart())) {
             if (mResponseHead) {
                 mResponseHead->Reset();
             }
             mContentRead = 0;
             mContentLength = -1;
@@ -967,19 +971,20 @@ nsHttpTransaction::Close(nsresult reason
         }
 
         // reallySentData is meant to separate the instances where data has
         // been sent by this transaction but buffered at a higher level while
         // a TLS session (perhaps via a tunnel) is setup.
         bool reallySentData =
             mSentData && (!mConnection || mConnection->BytesWritten());
 
-        if (!mReceivedData &&
+        if (reason == psm::GetXPCOMFromNSSError(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA) ||
+            (!mReceivedData &&
             ((mRequestHead && mRequestHead->IsSafeMethod()) ||
-             !reallySentData || connReused)) {
+             !reallySentData || connReused))) {
             // if restarting fails, then we must proceed to close the pipe,
             // which will notify the channel that the transaction failed.
 
             if (mPipelinePosition) {
                 gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
                     mConnInfo, nsHttpConnectionMgr::RedCanceledPipeline,
                     nullptr, 0);
             }
--- a/python/mozbuild/mozbuild/artifacts.py
+++ b/python/mozbuild/mozbuild/artifacts.py
@@ -434,17 +434,17 @@ class WinArtifactJob(ArtifactJob):
                                  patterns=self.artifact_patterns))
 
 # Keep the keys of this map in sync with the |mach artifact| --job
 # options.  The keys of this map correspond to entries at
 # https://tools.taskcluster.net/index/artifacts/#gecko.v2.mozilla-central.latest/gecko.v2.mozilla-central.latest
 # The values correpsond to a pair of (<package regex>, <test archive regex>).
 JOB_DETAILS = {
     'android-api-15-opt': (AndroidArtifactJob, (r'(public/build/fennec-(.*)\.android-arm.apk|public/build/target\.apk)',
-                                                r'public/build/fennec-(.*)\.common\.tests\.zip|public/build/target-(.*)\.common\.tests\.zip')),
+                                                r'public/build/fennec-(.*)\.common\.tests\.zip|public/build/target\.common\.tests\.zip')),
     'android-api-15-debug': (AndroidArtifactJob, (r'public/build/target\.apk',
                                                   r'public/build/target\.common\.tests\.zip')),
     'android-x86-opt': (AndroidArtifactJob, (r'public/build/target\.apk',
                                              r'public/build/target\.common\.tests\.zip')),
     'linux-opt': (LinuxArtifactJob, (r'public/build/target\.tar\.bz2',
                                      r'public/build/target\.common\.tests\.zip')),
     'linux-debug': (LinuxArtifactJob, (r'public/build/target\.tar\.bz2',
                                        r'public/build/target\.common\.tests\.zip')),
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -1024,16 +1024,17 @@ BookmarksTracker.prototype = {
       return;
     }
 
     this._log.trace("onItemRemoved: " + itemId);
     this._upScore();
   },
 
   _ensureMobileQuery: function _ensureMobileQuery() {
+    Services.prefs.setBoolPref("browser.bookmarks.showMobileBookmarks", true);
     let find = val =>
       PlacesUtils.annotations.getItemsWithAnnotation(ORGANIZERQUERY_ANNO, {}).filter(
         id => PlacesUtils.annotations.getItemAnnotation(id, ORGANIZERQUERY_ANNO) == val
       );
 
     // Don't continue if the Library isn't ready
     let all = find(ALLBOOKMARKS_ANNO);
     if (all.length == 0)
--- a/services/sync/moz.build
+++ b/services/sync/moz.build
@@ -40,17 +40,17 @@ EXTRA_JS_MODULES['services-sync'] += [
     'modules/util.js',
 ]
 
 EXTRA_PP_JS_MODULES['services-sync'] += [
     'modules/constants.js',
 ]
 
 # Definitions used by constants.js
-DEFINES['weave_version'] = '1.55.0'
+DEFINES['weave_version'] = '1.56.0'
 DEFINES['weave_id'] = '{340c2bbc-ce74-4362-90b5-7c26312808ef}'
 
 EXTRA_JS_MODULES['services-sync'].engines += [
     'modules/engines/addons.js',
     'modules/engines/bookmarks.js',
     'modules/engines/clients.js',
     'modules/engines/extension-storage.js',
     'modules/engines/forms.js',
--- a/taskcluster/ci/build/android.yml
+++ b/taskcluster/ci/build/android.yml
@@ -101,17 +101,17 @@ android-api-15/opt:
 
 android-api-15-nightly/opt:
     description: "Android 4.0 API15+ Nightly"
     attributes:
         nightly: true
     index:
         product: mobile
         job-name: android-api-15-opt
-        type: nightly
+        type: nightly-with-multi-l10n
     treeherder:
         platform: android-4-0-armv7-api15/opt
         symbol: tc(N)
     worker-type: aws-provisioner-v1/gecko-{level}-b-android
     worker:
         implementation: docker-worker
         max-run-time: 7200
     run:
--- a/taskcluster/ci/test/test-platforms.yml
+++ b/taskcluster/ci/test/test-platforms.yml
@@ -33,16 +33,17 @@ linux64/debug:
         - web-platform-tests
 linux64/opt:
     build-platform: linux64/opt
     test-sets:
         - common-tests
         - external-media-tests
         - web-platform-tests
         - opt-only-tests
+        - desktop-screenshot-capture
         - talos
 
 # TODO: use 'pgo' and 'asan' labels here, instead of -pgo/opt
 linux64-pgo/opt:
     build-platform: linux64-pgo/opt
     test-sets:
         - common-tests
         - external-media-tests
--- a/taskcluster/ci/test/test-sets.yml
+++ b/taskcluster/ci/test/test-sets.yml
@@ -182,16 +182,19 @@ linux32-tests:
     - web-platform-tests
     - web-platform-tests-reftests
     - xpcshell
 
 linux32-opt-tests:
     # mochitest-dt is too slow on linux32/debug
     - mochitest-devtools-chrome
 
+desktop-screenshot-capture:
+    - mochitest-browser-screenshots
+
 android-common-tests:
     - cppunit
     - crashtest
     - jsreftest
     - mochitest
     - mochitest-chrome
     - mochitest-clipboard
     - mochitest-gpu
--- a/taskcluster/ci/test/tests.yml
+++ b/taskcluster/ci/test/tests.yml
@@ -428,16 +428,45 @@ mochitest-browser-chrome:
     # Bug 1281241: migrating to m3.large instances
     instance-size:
         by-test-platform:
             linux64-jsdcov/opt: xlarge
             linux64-ccov/opt: xlarge
             default: legacy
     allow-software-gl-layers: false
 
+mochitest-browser-screenshots:
+    description: "Mochitest Browser Screenshots"
+    suite: mochitest/browser-chrome-screenshots
+    treeherder-symbol: tc-M(ss)
+    loopback-video: true
+    run-on-projects:
+        by-test-platform:
+            linux64/opt: ['mozilla-central', 'try']
+            default: []
+    e10s: true
+    max-run-time: 3600
+    mozharness:
+        script: desktop_unittest.py
+        no-read-buildbot-config: true
+        config:
+            by-test-platform:
+                windows.*:
+                    - unittests/win_taskcluster_unittest.py
+                macosx.*:
+                    - remove_executables.py
+                    - unittests/mac_unittest.py
+                linux.*:
+                    - unittests/linux_unittest.py
+                    - remove_executables.py
+        extra-options:
+            - --mochitest-suite=browser-chrome-screenshots
+    instance-size: legacy
+    allow-software-gl-layers: false
+
 mochitest-chrome:
     description: "Mochitest chrome run"
     suite: mochitest/chrome
     treeherder-symbol: tc-M(c)
     loopback-video: true
     instance-size:
         by-test-platform:
             android.*: xlarge
--- a/taskcluster/docker/rust-build/VERSION
+++ b/taskcluster/docker/rust-build/VERSION
@@ -1,1 +1,1 @@
-0.4.1
+0.4.2
--- a/taskcluster/docker/rust-build/repack_rust.py
+++ b/taskcluster/docker/rust-build/repack_rust.py
@@ -52,16 +52,19 @@ def fetch(url):
         ])
 
 
 def install(filename, target):
     '''Run a package's installer script against the given target directory.'''
     print(' Unpacking %s...' % filename)
     subprocess.check_call(['tar', 'xf', filename])
     basename = filename.split('.tar')[0]
+    # Work around bad tarball naming in 1.15 cargo packages.
+    basename = basename.replace('cargo-beta', 'cargo-nightly')
+    basename = basename.replace('cargo-0.16', 'cargo-nightly')
     print(' Installing %s...' % basename)
     install_cmd = [os.path.join(basename, 'install.sh')]
     install_cmd += ['--prefix=' + os.path.abspath(target)]
     install_cmd += ['--disable-ldconfig']
     subprocess.check_call(install_cmd)
     print(' Cleaning %s...' % basename)
     subprocess.check_call(['rm', '-rf', basename])
 
@@ -190,9 +193,9 @@ win64 = "x86_64-pc-windows-msvc"
 win32 = "i686-pc-windows-msvc"
 
 if __name__ == '__main__':
     repack(mac64, [mac64, mac32])
     repack(win32, [win32])
     repack(win64, [win64])
     repack(linux64, [linux64, linux32])
     repack(linux64, [linux64, mac64, mac32], suffix='mac-cross')
-    repack(linux64, [linux64, android, android_x86], suffix='android-cross')
+    repack(linux64, [linux64, android, android_x86], channel='beta', suffix='android-cross')
--- a/taskcluster/taskgraph/transforms/task.py
+++ b/taskcluster/taskgraph/transforms/task.py
@@ -88,17 +88,17 @@ task_description_schema = Schema({
     Optional('index'): {
         # the name of the product this build produces
         'product': Any('firefox', 'mobile', 'static-analysis'),
 
         # the names to use for this job in the TaskCluster index
         'job-name': basestring,
 
         # Type of gecko v2 index to use
-        'type': Any('generic', 'nightly', 'l10n'),
+        'type': Any('generic', 'nightly', 'l10n', 'nightly-with-multi-l10n'),
 
         # The rank that the task will receive in the TaskCluster
         # index.  A newly completed task supercedes the currently
         # indexed task iff it has a higher rank.  If unspecified,
         # 'by-tier' behavior will be used.
         'rank': Any(
             # Rank is equal the timestamp of the build_date for tier-1
             # tasks, and zero for non-tier-1.  This sorts tier-{2,3}
@@ -656,37 +656,51 @@ def add_nightly_index_routes(config, tas
                                             time.gmtime(config.params['build_date']))
     subs['build_date'] = time.strftime("%Y.%m.%d",
                                        time.gmtime(config.params['build_date']))
     subs['product'] = index['product']
 
     for tpl in V2_NIGHTLY_TEMPLATES:
         routes.append(tpl.format(**subs))
 
+    # Also add routes for en-US
+    task = add_l10n_index_routes(config, task, force_locale="en-US")
+
+    return task
+
+
+@index_builder('nightly-with-multi-l10n')
+def add_nightly_multi_index_routes(config, task):
+    task = add_nightly_index_routes(config, task)
+    task = add_l10n_index_routes(config, task, force_locale="multi")
     return task
 
 
 @index_builder('l10n')
-def add_l10n_index_routes(config, task):
+def add_l10n_index_routes(config, task, force_locale=None):
     index = task.get('index')
     routes = task.setdefault('routes', [])
 
     job_name = index['job-name']
     if job_name not in JOB_NAME_WHITELIST:
         raise Exception(JOB_NAME_WHITELIST_ERROR.format(job_name))
 
     subs = config.params.copy()
     subs['job-name'] = job_name
     subs['build_date_long'] = time.strftime("%Y.%m.%d.%Y%m%d%H%M%S",
                                             time.gmtime(config.params['build_date']))
     subs['product'] = index['product']
 
     locales = task['attributes'].get('chunk_locales',
                                      task['attributes'].get('all_locales'))
 
+    if force_locale:
+        # Used for en-US and multi-locale
+        locales = [force_locale]
+
     if not locales:
         raise Exception("Error: Unable to use l10n index for tasks without locales")
 
     # If there are too many locales, we can't write a route for all of them
     # See Bug 1323792
     if len(locales) > 18:  # 18 * 3 = 54, max routes = 64
         return task
 
--- a/testing/firefox-ui/tests/functional/security/manifest.ini
+++ b/testing/firefox-ui/tests/functional/security/manifest.ini
@@ -6,16 +6,17 @@ tags = remote
 tags = local
 [test_ev_certificate.py]
 [test_mixed_content_page.py]
 [test_mixed_script_content_blocking.py]
 [test_no_certificate.py]
 tags = local
 [test_safe_browsing_initial_download.py]
 [test_safe_browsing_notification.py]
+skip-if = e10s # Bug 1315042
 [test_safe_browsing_warning_pages.py]
 [test_security_notification.py]
 [test_ssl_disabled_error_page.py]
 [test_ssl_status_after_restart.py]
 skip-if = (os == "win" && os_version == "5.1") # Bug 1167179: Fails to open popups after restart
 [test_submit_unencrypted_info_warning.py]
 [test_unknown_issuer.py]
 [test_untrusted_connection_error_page.py]
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_click_scrolling.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_click_scrolling.py
@@ -1,16 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from marionette_driver.by import By
 from marionette_driver.errors import MoveTargetOutOfBoundsException
 
-from marionette_harness import MarionetteTestCase, skip
+from marionette_harness import MarionetteTestCase, skip, skip_if_mobile
 
 
 class TestClickScrolling(MarionetteTestCase):
 
 
     def test_clicking_on_anchor_scrolls_page(self):
         scrollScript = """
             var pageY;
@@ -92,16 +92,17 @@ class TestClickScrolling(MarionetteTestC
             self.assertNotEqual(scroll_y, self.marionette.execute_script("return window.scrollY;"))
 
         for s in ["left", "right"]:
             self.marionette.navigate(test_html)
             scroll_x = self.marionette.execute_script("return window.scrollX;")
             self.marionette.find_element(By.ID, "{}-70".format(s)).click()
             self.assertNotEqual(scroll_x, self.marionette.execute_script("return window.scrollX;"))
 
+    @skip_if_mobile("Bug 1293855 - Lists differ: [70, 70] != [70, 120]")
     def test_should_not_scroll_elements_if_click_point_is_in_view(self):
         test_html = self.marionette.absolute_url("element_outside_viewport.html")
 
         for s in ["top", "right", "bottom", "left"]:
             for p in ["50", "30"]:
                 self.marionette.navigate(test_html)
                 scroll = self.marionette.execute_script("return [window.scrollX, window.scrollY];")
                 self.marionette.find_element(By.ID, "{0}-{1}".format(s, p)).click()
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_text.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_text.py
@@ -1,16 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from marionette_driver.by import By
 from marionette_driver.keys import Keys
 
-from marionette_harness import MarionetteTestCase
+from marionette_harness import MarionetteTestCase, skip_if_mobile
 
 
 class TestText(MarionetteTestCase):
     def test_getText(self):
         test_html = self.marionette.absolute_url("test.html")
         self.marionette.navigate(test_html)
         l = self.marionette.find_element(By.ID, "mozLink")
         self.assertEqual("Click me!", l.text)
@@ -48,35 +48,35 @@ class TestText(MarionetteTestCase):
 
     def test_should_fire_key_press_events(self):
         test_html = self.marionette.absolute_url("javascriptPage.html")
         self.marionette.navigate(test_html)
         key_reporter = self.marionette.find_element(By.ID, "keyReporter")
         key_reporter.send_keys("a")
 
         result = self.marionette.find_element(By.ID, "result")
-        self.assertTrue("press:" in result.text)
+        self.assertIn("press:", result.text)
 
     def test_should_fire_key_down_events(self):
         test_html = self.marionette.absolute_url("javascriptPage.html")
         self.marionette.navigate(test_html)
         key_reporter = self.marionette.find_element(By.ID, "keyReporter")
         key_reporter.send_keys("a")
 
         result = self.marionette.find_element(By.ID, "result")
-        self.assertTrue("down:" in result.text)
+        self.assertIn("down:", result.text)
 
     def test_should_fire_key_up_events(self):
         test_html = self.marionette.absolute_url("javascriptPage.html")
         self.marionette.navigate(test_html)
         key_reporter = self.marionette.find_element(By.ID, "keyReporter")
         key_reporter.send_keys("a")
 
         result = self.marionette.find_element(By.ID, "result")
-        self.assertTrue("up:" in result.text)
+        self.assertIn("up:", result.text)
 
     def test_should_type_lowercase_characters(self):
         test_html = self.marionette.absolute_url("javascriptPage.html")
         self.marionette.navigate(test_html)
         key_reporter = self.marionette.find_element(By.ID, "keyReporter")
         key_reporter.send_keys("abc def")
 
         self.assertEqual("abc def", key_reporter.get_property("value"))
@@ -178,36 +178,37 @@ class TestText(MarionetteTestCase):
         element = self.marionette.find_element(By.ID, "keyPressArea")
         element.send_keys("I like cheese")
 
         result = self.marionette.find_element(By.ID, "result")
         # Because the key down gets the result before the input element is
         # filled, we're a letter short here
         self.assertEqual(result.text, "I like chees")
 
+    @skip_if_mobile("Bug 1333069 - Assertion: 'down: 40' not found in u''")
     def test_should_report_key_code_of_arrow_keys_up_down_events(self):
         test_html = self.marionette.absolute_url("javascriptPage.html")
         self.marionette.navigate(test_html)
         result = self.marionette.find_element(By.ID, "result")
         element = self.marionette.find_element(By.ID, "keyReporter")
         element.send_keys(Keys.ARROW_DOWN)
-        self.assertTrue("down: 40" in result.text.strip())
-        self.assertTrue("up: 40" in result.text.strip())
+        self.assertIn("down: 40", result.text.strip())
+        self.assertIn("up: 40", result.text.strip())
 
         element.send_keys(Keys.ARROW_UP)
-        self.assertTrue("down: 38" in result.text.strip())
-        self.assertTrue("up: 38" in result.text.strip())
+        self.assertIn("down: 38", result.text.strip())
+        self.assertIn("up: 38", result.text.strip())
 
         element.send_keys(Keys.ARROW_LEFT)
-        self.assertTrue("down: 37" in result.text.strip())
-        self.assertTrue("up: 37" in result.text.strip())
+        self.assertIn("down: 37", result.text.strip())
+        self.assertIn("up: 37", result.text.strip())
 
         element.send_keys(Keys.ARROW_RIGHT)
-        self.assertTrue("down: 39" in result.text.strip())
-        self.assertTrue("up: 39" in result.text.strip())
+        self.assertIn("down: 39", result.text.strip())
+        self.assertIn("up: 39", result.text.strip())
 
         #  And leave no rubbish/printable keys in the "keyReporter"
         self.assertEqual("", element.get_property("value"))
 
     def testNumericNonShiftKeys(self):
         test_html = self.marionette.absolute_url("javascriptPage.html")
         self.marionette.navigate(test_html)
         element = self.marionette.find_element(By.ID, "keyReporter")
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -317,16 +317,17 @@ def call(*args, **kwargs):
 
 def killPid(pid, log):
     # see also https://bugzilla.mozilla.org/show_bug.cgi?id=911249#c58
     try:
         os.kill(pid, getattr(signal, "SIGKILL", signal.SIGTERM))
     except Exception as e:
         log.info("Failed to kill process %d: %s" % (pid, str(e)))
 
+
 if mozinfo.isWin:
     import ctypes.wintypes
 
     def isPidAlive(pid):
         STILL_ACTIVE = 259
         PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
         pHandle = ctypes.windll.kernel32.OpenProcess(
             PROCESS_QUERY_LIMITED_INFORMATION,
@@ -820,17 +821,16 @@ class MochitestDesktop(object):
         self.countpass = 0
         self.countfail = 0
         self.counttodo = 0
 
         self.expectedError = {}
         self.result = {}
 
         self.start_script = os.path.join(here, 'start_desktop.js')
-        self.disable_leak_checking = False
 
     def update_mozinfo(self):
         """walk up directories to find mozinfo.json update the info"""
         # TODO: This should go in a more generic place, e.g. mozinfo
 
         path = SCRIPT_DIR
         dirs = set()
         while path != os.path.expanduser('~'):
@@ -1503,18 +1503,17 @@ toolbar#nav-bar {
                 dict(
                     parseKeyValue(
                         options.environment,
                         context='--setenv')))
         except KeyValueParseError as e:
             self.log.error(str(e))
             return None
 
-        if not self.disable_leak_checking:
-            browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
+        browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
 
         try:
             gmp_path = self.getGMPPluginPath(options)
             if gmp_path is not None:
                 browserEnv["MOZ_GMP_PATH"] = gmp_path
         except EnvironmentError:
             self.log.error('Could not find path to gmp-fake plugin!')
             return None
@@ -1947,23 +1946,22 @@ toolbar#nav-bar {
             cmd = os.path.abspath(app)
             args = list(extraArgs)
             args.append('-marionette')
             # TODO: mozrunner should use -foreground at least for mac
             # https://bugzilla.mozilla.org/show_bug.cgi?id=916512
             args.append('-foreground')
             self.start_script_kwargs['testUrl'] = testUrl or 'about:blank'
 
-            if detectShutdownLeaks and not self.disable_leak_checking:
+            if detectShutdownLeaks:
                 shutdownLeaks = ShutdownLeaks(self.log)
             else:
                 shutdownLeaks = None
 
-            if mozinfo.info["asan"] and (mozinfo.isLinux or mozinfo.isMac) \
-                    and not self.disable_leak_checking:
+            if mozinfo.info["asan"] and (mozinfo.isLinux or mozinfo.isMac):
                 lsanLeaks = LSANLeaks(self.log)
             else:
                 lsanLeaks = None
 
             # create an instance to process the output
             outputHandler = self.OutputHandler(
                 harness=self,
                 utilityPath=utilityPath,
@@ -2225,38 +2223,16 @@ toolbar#nav-bar {
             return self.runMochitests(options, testsToRun)
 
         # code for --run-by-dir
         dirs = self.getDirectories(options)
 
         result = 1  # default value, if no tests are run.
         for d in dirs:
             print("dir: %s" % d)
-
-            # BEGIN LEAKCHECK HACK
-            # Leak checking was broken in mochitest unnoticed for a length of time. During
-            # this time, several leaks slipped through. The leak checking was fixed by bug
-            # 1325148, but it couldn't land until all the regressions were also fixed or
-            # backed out. Rather than waiting and risking new regressions, in the meantime
-            # this code will selectively disable leak checking on flavors/directories where
-            # known regressions exist. At least this way we can prevent further damage while
-            # they get fixed.
-
-            skip_leak_conditions = []
-
-            for condition, reason in skip_leak_conditions:
-                if condition:
-                    self.log.warning('WARNING | disabling leakcheck due to {}'.format(reason))
-                    self.disable_leak_checking = True
-                    break
-            else:
-                self.disable_leak_checking = False
-
-            # END LEAKCHECK HACK
-
             tests_in_dir = [t for t in testsToRun if os.path.dirname(t) == d]
 
             # If we are using --run-by-dir, we should not use the profile path (if) provided
             # by the user, since we need to create a new directory for each run. We would face
             # problems if we use the directory provided by the user.
             result = self.runMochitests(options, tests_in_dir)
 
             # Dump the logging buffer
@@ -2353,16 +2329,17 @@ toolbar#nav-bar {
 
         if self.browserEnv is None:
             return 1
 
         if self.mozLogs:
             self.browserEnv["MOZ_LOG_FILE"] = "{}/moz-pid=%PID-uid={}.log".format(
                 self.browserEnv["MOZ_UPLOAD_DIR"], str(uuid.uuid4()))
 
+        status = 0
         try:
             self.startServers(options, debuggerInfo)
 
             if options.immersiveMode:
                 options.browserArgs.extend(('-firefoxpath', options.app))
                 options.app = self.immersiveHelperPath
 
             if options.jsdebugger:
@@ -2412,33 +2389,35 @@ toolbar#nav-bar {
                 testURL = self.buildTestURL(options, scheme=scheme)
 
                 self.buildURLOptions(options, self.browserEnv)
                 if self.urlOpts:
                     testURL += "?" + "&".join(self.urlOpts)
 
                 self.log.info("runtests.py | Running with e10s: {}".format(options.e10s))
                 self.log.info("runtests.py | Running tests: start.\n")
-                status = self.runApp(testURL,
-                                     self.browserEnv,
-                                     options.app,
-                                     profile=self.profile,
-                                     extraArgs=options.browserArgs,
-                                     utilityPath=options.utilityPath,
-                                     debuggerInfo=debuggerInfo,
-                                     valgrindPath=valgrindPath,
-                                     valgrindArgs=valgrindArgs,
-                                     valgrindSuppFiles=valgrindSuppFiles,
-                                     symbolsPath=options.symbolsPath,
-                                     timeout=timeout,
-                                     detectShutdownLeaks=detectShutdownLeaks,
-                                     screenshotOnFail=options.screenshotOnFail,
-                                     bisectChunk=options.bisectChunk,
-                                     marionette_args=marionette_args,
-                                     )
+                ret = self.runApp(
+                    testURL,
+                    self.browserEnv,
+                    options.app,
+                    profile=self.profile,
+                    extraArgs=options.browserArgs,
+                    utilityPath=options.utilityPath,
+                    debuggerInfo=debuggerInfo,
+                    valgrindPath=valgrindPath,
+                    valgrindArgs=valgrindArgs,
+                    valgrindSuppFiles=valgrindSuppFiles,
+                    symbolsPath=options.symbolsPath,
+                    timeout=timeout,
+                    detectShutdownLeaks=detectShutdownLeaks,
+                    screenshotOnFail=options.screenshotOnFail,
+                    bisectChunk=options.bisectChunk,
+                    marionette_args=marionette_args,
+                )
+                status = ret or status
         except KeyboardInterrupt:
             self.log.info("runtests.py | Received keyboard interrupt.\n")
             status = -1
         except:
             traceback.print_exc()
             self.log.error(
                 "Automation Error: Received unexpected exception while running application\n")
             status = 1
@@ -2730,10 +2709,11 @@ def cli(args=sys.argv[1:]):
     parser = MochitestArgumentParser(app='generic')
     options = parser.parse_args(args)
     if options is None:
         # parsing error
         sys.exit(1)
 
     return run_test_harness(parser, options)
 
+
 if __name__ == "__main__":
     sys.exit(cli())
--- a/testing/mozharness/external_tools/robustcheckout.py
+++ b/testing/mozharness/external_tools/robustcheckout.py
@@ -10,32 +10,34 @@ times and storage efficiency.
 """
 
 from __future__ import absolute_import
 
 import contextlib
 import errno
 import functools
 import os
+import random
 import re
+import time
 
 from mercurial.i18n import _
 from mercurial.node import hex
 from mercurial import (
     commands,
     error,
     exchange,
     extensions,
     cmdutil,
     hg,
     scmutil,
     util,
 )
 
-testedwith = '3.6 3.7 3.8 3.9'
+testedwith = '3.7 3.8 3.9 4.0'
 minimumhgversion = '3.7'
 
 cmdtable = {}
 command = cmdutil.command(cmdtable)
 
 
 if os.name == 'nt':
     import ctypes
@@ -111,21 +113,23 @@ def purgewrapper(orig, ui, *args, **kwar
 
 
 @command('robustcheckout', [
     ('', 'upstream', '', 'URL of upstream repo to clone from'),
     ('r', 'revision', '', 'Revision to check out'),
     ('b', 'branch', '', 'Branch to check out'),
     ('', 'purge', False, 'Whether to purge the working directory'),
     ('', 'sharebase', '', 'Directory where shared repos should be placed'),
+    ('', 'networkattempts', 3, 'Maximum number of attempts for network '
+                               'operations'),
     ],
     '[OPTION]... URL DEST',
     norepo=True)
 def robustcheckout(ui, url, dest, upstream=None, revision=None, branch=None,
-                   purge=False, sharebase=None):
+                   purge=False, sharebase=None, networkattempts=None):
     """Ensure a working copy has the specified revision checked out."""
     if not revision and not branch:
         raise error.Abort('must specify one of --revision or --branch')
 
     if revision and branch:
         raise error.Abort('cannot specify both --revision and --branch')
 
     # Require revision to look like a SHA-1.
@@ -151,22 +155,26 @@ def robustcheckout(ui, url, dest, upstre
     # otherwise we're at the whim of whatever configs are used in automation.
     ui.setconfig('progress', 'delay', 1.0)
     ui.setconfig('progress', 'refresh', 1.0)
     ui.setconfig('progress', 'assume-tty', True)
 
     sharebase = os.path.realpath(sharebase)
 
     return _docheckout(ui, url, dest, upstream, revision, branch, purge,
-                       sharebase)
+                       sharebase, networkattempts)
 
-def _docheckout(ui, url, dest, upstream, revision, branch, purge, sharebase):
+def _docheckout(ui, url, dest, upstream, revision, branch, purge, sharebase,
+                networkattemptlimit, networkattempts=None):
+    if not networkattempts:
+        networkattempts = [1]
+
     def callself():
         return _docheckout(ui, url, dest, upstream, revision, branch, purge,
-                           sharebase)
+                           sharebase, networkattemptlimit, networkattempts)
 
     ui.write('ensuring %s@%s is available at %s\n' % (url, revision or branch,
                                                       dest))
 
     destvfs = scmutil.vfs(dest, audit=False, realpath=True)
 
     if destvfs.exists() and not destvfs.exists('.hg'):
         raise error.Abort('destination exists but no .hg directory')
@@ -212,16 +220,55 @@ def _docheckout(ui, url, dest, upstream,
 
             ui.warn('(attempting checkout from beginning)\n')
             return callself()
 
         raise
 
     # At this point we either have an existing working directory using
     # shared, pooled storage or we have nothing.
+
+    def handlepullabort(e):
+        """Handle an error.Abort raised during a pull.
+
+        Returns True if caller should call ``callself()`` to retry.
+        """
+        if e.args[0] == _('repository is unrelated'):
+            ui.warn('(repository is unrelated; deleting)\n')
+            destvfs.rmtree(forcibly=True)
+            return True
+        elif e.args[0].startswith(_('stream ended unexpectedly')):
+            ui.warn('%s\n' % e.args[0])
+            if networkattempts[0] < networkattemptlimit:
+                ui.warn('(retrying after network failure on attempt %d of %d)\n' %
+                        (networkattempts[0], networkattemptlimit))
+
+                # Do a backoff on retries to mitigate the thundering herd
+                # problem. This is an exponential backoff with a multipler
+                # plus random jitter thrown in for good measure.
+                # With the default settings, backoffs will be:
+                # 1) 2.5 - 6.5
+                # 2) 5.5 - 9.5
+                # 3) 11.5 - 15.5
+                backoff = (2 ** networkattempts[0] - 1) * 1.5
+                jittermin = ui.configint('robustcheckout', 'retryjittermin', 1000)
+                jittermax = ui.configint('robustcheckout', 'retryjittermax', 5000)
+                backoff += float(random.randint(jittermin, jittermax)) / 1000.0
+                ui.warn('(waiting %.2fs before retry)\n' % backoff)
+                time.sleep(backoff)
+
+                networkattempts[0] += 1
+
+                return True
+            else:
+                raise error.Abort('reached maximum number of network attempts; '
+                                  'giving up\n')
+
+        return False
+
     created = False
 
     if not destvfs.exists():
         # Ensure parent directories of destination exist.
         # Mercurial 3.8 removed ensuredirs and made makedirs race safe.
         if util.safehasattr(util, 'ensuredirs'):
             makedirs = util.ensuredirs
         else:
@@ -232,16 +279,20 @@ def _docheckout(ui, url, dest, upstream,
 
         if upstream:
             ui.write('(cloning from upstream repo %s)\n' % upstream)
         cloneurl = upstream or url
 
         try:
             res = hg.clone(ui, {}, cloneurl, dest=dest, update=False,
                            shareopts={'pool': sharebase, 'mode': 'identity'})
+        except error.Abort as e:
+            if handlepullabort(e):
+                return callself()
+            raise
         except error.RepoError as e:
             return handlerepoerror(e)
         except error.RevlogError as e:
             ui.warn('(repo corruption: %s; deleting shared store)\n' % e.message)
             deletesharedstore()
             return callself()
 
         # TODO retry here.
@@ -288,21 +339,18 @@ def _docheckout(ui, url, dest, upstream,
 
             if checkoutrevision in repo:
                 ui.warn('(revision already present locally; not pulling)\n')
             else:
                 pullop = exchange.pull(repo, remote, heads=pullrevs)
                 if not pullop.rheads:
                     raise error.Abort('unable to pull requested revision')
         except error.Abort as e:
-            if e.message == _('repository is unrelated'):
-                ui.warn('(repository is unrelated; deleting)\n')
-                destvfs.rmtree(forcibly=True)
+            if handlepullabort(e):
                 return callself()
-
             raise
         except error.RepoError as e:
             return handlerepoerror(e)
         except error.RevlogError as e:
             ui.warn('(repo corruption: %s; deleting shared store)\n' % e.message)
             deletesharedstore()
             return callself()
         finally:
--- a/toolkit/components/extensions/test/mochitest/test_ext_cookies.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_cookies.html
@@ -83,17 +83,18 @@ add_task(function* test_cookies() {
     browser.test.assertEq(null, cookie, "removed cookie not found");
 
     let stores = await browser.cookies.getAllCookieStores();
     browser.test.assertEq(1, stores.length, "expected number of stores returned");
     browser.test.assertEq(STORE_ID, stores[0].id, "expected store id returned");
     browser.test.assertEq(1, stores[0].tabIds.length, "one tabId returned for store");
     browser.test.assertEq("number", typeof stores[0].tabIds[0], "tabId is a number");
 
-    {
+    // This part causes intermittent failures see Bug 1309637.
+    if (false) {
       let privateWindow = await browser.windows.create({incognito: true});
       let stores = await browser.cookies.getAllCookieStores();
 
       browser.test.assertEq(2, stores.length, "expected number of stores returned");
       browser.test.assertEq(STORE_ID, stores[0].id, "expected store id returned");
       browser.test.assertEq(1, stores[0].tabIds.length, "one tab returned for store");
       browser.test.assertEq(PRIVATE_STORE_ID, stores[1].id, "expected private store id returned");
       browser.test.assertEq(1, stores[0].tabIds.length, "one tab returned for private store");
@@ -174,17 +175,18 @@ add_task(function* test_cookies() {
     details = await browser.cookies.remove({url: TEST_URL, name: "name1"});
     assertExpected({url: TEST_URL, name: "name1", storeId: STORE_ID}, details);
 
     cookie = await browser.cookies.set({url: TEST_URL});
     browser.test.assertEq("", cookie.name, "default name set");
     browser.test.assertEq("", cookie.value, "default value set");
     browser.test.assertEq(true, cookie.session, "no expiry date created session cookie");
 
-    {
+    // This part causes intermittent failures see Bug 1309637.
+    if (false) {
       let privateWindow = await browser.windows.create({incognito: true});
 
       // Hacky work-around for bugzil.la/1309637
       await new Promise(resolve => setTimeout(resolve, 700));
 
       let cookie = await browser.cookies.set({url: TEST_URL, name: "store", value: "private", expirationDate: THE_FUTURE, storeId: PRIVATE_STORE_ID});
       browser.test.assertEq("private", cookie.value, "set the private cookie");
 
--- a/toolkit/components/formautofill/test/browser/browser_ui_requestAutocomplete.js
+++ b/toolkit/components/formautofill/test/browser/browser_ui_requestAutocomplete.js
@@ -2,16 +2,22 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /*
  * Tests the requestAutocomplete user interface.
  */
 
 "use strict";
 
+add_task(function* setup() {
+  yield SpecialPowers.pushPrefEnv({
+    set: [["dom.ipc.processCount", 1]]
+  });
+});
+
 /**
  * Open the requestAutocomplete UI and test that selecting a profile results in
  * the correct data being sent back to the opener.
  */
 add_task(function* test_select_profile() {
   // Request an e-mail address.
   let { uiWindow, promiseResult } = yield FormAutofillTest.showUI(
                                           TestData.requestEmailOnly);
--- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
+++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
@@ -1008,17 +1008,17 @@ LoginManagerPrompter.prototype = {
       promptMsg,
       "password-notification-icon",
       mainAction,
       secondaryActions,
       {
         timeout: Date.now() + 10000,
         persistWhileVisible: true,
         passwordNotificationType: type,
-        hideClose: true,
+        hideClose: !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton"),
         eventCallback(topic) {
           switch (topic) {
             case "showing":
               currentNotification = this;
               chromeDoc.getElementById("password-notification-password")
                        .removeAttribute("focused");
               chromeDoc.getElementById("password-notification-username")
                        .removeAttribute("focused");
--- a/toolkit/components/passwordmgr/test/browser/browser.ini
+++ b/toolkit/components/passwordmgr/test/browser/browser.ini
@@ -40,16 +40,17 @@ support-files =
 support-files =
   subtst_notifications_change_p.html
 [browser_DOMFormHasPassword.js]
 [browser_DOMInputPasswordAdded.js]
 [browser_exceptions_dialog.js]
 [browser_formless_submit_chrome.js]
 [browser_hasInsecureLoginForms.js]
 [browser_hasInsecureLoginForms_streamConverter.js]
+skip-if = e10s # Bug 1315042
 [browser_http_autofill.js]
 [browser_insecurePasswordWarning.js]
 [browser_notifications.js]
 [browser_notifications_username.js]
 [browser_notifications_password.js]
 [browser_notifications_2.js]
 skip-if = os == "linux" # Bug 1272849 Main action button disabled state intermittent
 [browser_passwordmgr_editing.js]
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -1733,52 +1733,16 @@
   "HTTP_RESPONSE_STATUS_CODE": {
     "alert_emails": ["ckerschbaumer@mozilla.com"],
     "bug_numbers": [1272345, 1296287],
     "expires_in_version": "56",
     "kind": "enumerated",
     "n_values": 12,
     "description": "Whether the URL gets redirected?  (0=200, 1=301, 2=302, 3=304, 4=307, 5=308, 6=400, 7=401, 8=403, 9=404, 10=500, 11=other)"
   },
-  "HTTP_NET_VS_CACHE_ONSTART_ISIMG": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStartRequest) difference (ms) for images. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTART_NOTIMG": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStartRequest) difference (ms) for non-images. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTOP_ISIMG": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStopRequest) difference (ms) for images. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTOP_NOTIMG": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStopRequest) difference (ms) for non-images. Offset by 500 ms."
-  },
   "HTTP_NET_VS_CACHE_ONSTART_QSMALL_NORMALPRI": {
     "expires_in_version": "58",
       "alert_emails": ["necko@mozilla.com"],
       "bug_numbers": [1313095],
       "kind": "linear",
       "high": 1000,
       "n_buckets": 100,
       "description": "Network vs cache time load (OnStartRequest) difference (ms) for requests with a normal priority and small queue. Offset by 500 ms."
@@ -1877,123 +1841,33 @@
     "expires_in_version": "58",
       "alert_emails": ["necko@mozilla.com"],
       "bug_numbers": [1313095],
       "kind": "linear",
       "high": 1000,
       "n_buckets": 100,
       "description": "Network vs cache time load (OnStopRequest) difference (ms) for requests with a high priority and large queue. Offset by 500 ms."
   },
-  "HTTP_NET_VS_CACHE_ONSTART_SMALL_NORMALPRI": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStartRequest) difference (ms) for cache files with a small size (<32K) and normal priority. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTART_MED_NORMALPRI": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStartRequest) difference (ms) for cache files with a medium size (<256K) and normal priority. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTART_LARGE_NORMALPRI": {
+  "HTTP_NET_VS_CACHE_ONSTOP_SMALL": {
     "expires_in_version": "58",
       "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStartRequest) difference (ms) for cache files with a large size (>256K) and normal priority. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTART_SMALL_HIGHPRI": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStartRequest) difference (ms) for cache files with a small size (<32K) and high priority. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTART_MED_HIGHPRI": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStartRequest) difference (ms) for cache files with a medium size (<256K) and high priority. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTART_LARGE_HIGHPRI": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
+      "bug_numbers": [1325090],
       "kind": "linear",
       "high": 1000,
       "n_buckets": 100,
-      "description": "Network vs cache time load (OnStartRequest) difference (ms) for cache files with a large size (>256K) and high priority. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTOP_SMALL_NORMALPRI": {
+      "description": "Network vs cache time load (OnStopRequest) difference (ms) for cache files with a small size (<256K). Offset by 500 ms."
+  },
+  "HTTP_NET_VS_CACHE_ONSTOP_LARGE": {
     "expires_in_version": "58",
       "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStopRequest) difference (ms) for cache files with a small size (<32K) and normal priority. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTOP_MED_NORMALPRI": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStopRequest) difference (ms) for cache files with a medium size (<256K) and normal priority. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTOP_LARGE_NORMALPRI": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
+      "bug_numbers": [1325090],
       "kind": "linear",
       "high": 1000,
       "n_buckets": 100,
-      "description": "Network vs cache time load (OnStopRequest) difference (ms) for cache files with a large size (>256K) and normal priority. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTOP_SMALL_HIGHPRI": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStopRequest) difference (ms) for cache files with a small size (<32K) and high priority. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTOP_MED_HIGHPRI": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStopRequest) difference (ms) for cache files with a medium size (<256K) and high priority. Offset by 500 ms."
-  },
-  "HTTP_NET_VS_CACHE_ONSTOP_LARGE_HIGHPRI": {
-    "expires_in_version": "58",
-      "alert_emails": ["necko@mozilla.com"],
-      "bug_numbers": [1313095],
-      "kind": "linear",
-      "high": 1000,
-      "n_buckets": 100,
-      "description": "Network vs cache time load (OnStopRequest) difference (ms) for cache files with a large size (>256K) and high priority. Offset by 500 ms."
+      "description": "Network vs cache time load (OnStopRequest) difference (ms) for cache files with a large size (>=256K). Offset by 500 ms."
   },
   "HTTP_NET_VS_CACHE_ONSTART_REVALIDATED": {
     "expires_in_version": "58",
       "alert_emails": ["necko@mozilla.com"],
       "bug_numbers": [1313095],
       "kind": "linear",
       "high": 1000,
       "n_buckets": 100,
--- a/toolkit/components/url-classifier/Classifier.cpp
+++ b/toolkit/components/url-classifier/Classifier.cpp
@@ -463,45 +463,43 @@ Classifier::Check(const nsACString& aSpe
       nsAutoCString checking;
       lookupHash.ToHexString(checking);
       LOG(("Checking fragment %s, hash %s (%X)", fragments[i].get(),
            checking.get(), lookupHash.ToUint32()));
     }
 
     for (uint32_t i = 0; i < cacheArray.Length(); i++) {
       LookupCache *cache = cacheArray[i];
-      bool has, complete;
+      bool has, fromCache;
       uint32_t matchLength;
 
-      rv = cache->Has(lookupHash, &has, &complete, &matchLength);
+      rv = cache->Has(lookupHash, &has, &matchLength, &fromCache);
       NS_ENSURE_SUCCESS(rv, rv);
       if (has) {
         LookupResult *result = aResults.AppendElement();
         if (!result)
           return NS_ERROR_OUT_OF_MEMORY;
 
-        int64_t age;
-        bool found = mTableFreshness.Get(cache->TableName(), &age);
-        if (!found) {
-          age = 24 * 60 * 60; // just a large number
-        } else {
-          int64_t now = (PR_Now() / PR_USEC_PER_SEC);
-          age = now - age;
+        // For V2, there is no TTL for caching, so we use table freshness to
+        // decide if matching a completion should trigger a gethash request or not.
+        // For V4, this is done by Positive Caching & Negative Caching mechanism.
+        bool confirmed = false;
+        if (fromCache) {
+          cache->IsHashEntryConfirmed(lookupHash, mTableFreshness,
+                                      aFreshnessGuarantee, &confirmed);
         }
 
-        LOG(("Found a result in %s: %s (Age: %Lds)",
+        LOG(("Found a result in %s: %s",
              cache->TableName().get(),
-             complete ? "complete." : "Not complete.",
-             age));
+             confirmed ? "confirmed." : "Not confirmed."));
 
         result->hash.complete = lookupHash;
-        result->mComplete = complete;
-        result->mFresh = (age < aFreshnessGuarantee);
+        result->mConfirmed = confirmed;
         result->mTableName.Assign(cache->TableName());
-        result->mPartialHashLength = matchLength;
+        result->mPartialHashLength = confirmed ? COMPLETE_SIZE : matchLength;
 
         if (LookupCache::Cast<LookupCacheV4>(cache)) {
           matchingStatistics |= PrefixMatch::eMatchV4Prefix;
         } else {
           matchingStatistics |= PrefixMatch::eMatchV2Prefix;
         }
       }
     }
--- a/toolkit/components/url-classifier/Classifier.h
+++ b/toolkit/components/url-classifier/Classifier.h
@@ -153,17 +153,17 @@ private:
   // Used for atomically updating the other dirs.
   nsCOMPtr<nsIFile> mBackupDirectory;
   nsCOMPtr<nsIFile> mToDeleteDirectory;
   nsCOMPtr<nsICryptoHash> mCryptoHash;
   nsTArray<LookupCache*> mLookupCaches;
   nsTArray<nsCString> mActiveTablesCache;
   uint32_t mHashKey;
   // Stores the last time a given table was updated (seconds).
-  nsDataHashtable<nsCStringHashKey, int64_t> mTableFreshness;
+  TableFreshnessMap mTableFreshness;
 
   // In-memory cache for the result of TableRequest. See
   // nsIUrlClassifierDBService.getTables for the format.
   nsCString mTableRequestResult;
 
   // Whether mTableRequestResult is outdated and needs to
   // be reloaded from disk.
   bool mIsTableRequestResultOutdated;
--- a/toolkit/components/url-classifier/Entries.h
+++ b/toolkit/components/url-classifier/Entries.h
@@ -11,16 +11,17 @@
 #define SBEntries_h__
 
 #include "nsTArray.h"
 #include "nsString.h"
 #include "nsICryptoHash.h"
 #include "nsNetUtil.h"
 #include "nsIOutputStream.h"
 #include "nsClassHashtable.h"
+#include "nsDataHashtable.h"
 
 #if DEBUG
 #include "plbase64.h"
 #endif
 
 namespace mozilla {
 namespace safebrowsing {
 
@@ -311,12 +312,14 @@ WriteTArray(nsIOutputStream* aStream, ns
   uint32_t written;
   return aStream->Write(reinterpret_cast<char*>(aArray.Elements()),
                         aArray.Length() * sizeof(T),
                         &written);
 }
 
 typedef nsClassHashtable<nsUint32HashKey, nsCString> PrefixStringMap;
 
+typedef nsDataHashtable<nsCStringHashKey, int64_t> TableFreshnessMap;
+
 } // namespace safebrowsing
 } // namespace mozilla
 
 #endif // SBEntries_h__
--- a/toolkit/components/url-classifier/LookupCache.cpp
+++ b/toolkit/components/url-classifier/LookupCache.cpp
@@ -416,20 +416,20 @@ void
 LookupCacheV2::ClearAll()
 {
   LookupCache::ClearAll();
   mUpdateCompletions.Clear();
 }
 
 nsresult
 LookupCacheV2::Has(const Completion& aCompletion,
-                   bool* aHas, bool* aComplete,
-                   uint32_t* aMatchLength)
+                   bool* aHas, uint32_t* aMatchLength,
+                   bool* aFromCache)
 {
-  *aHas = *aComplete = false;
+  *aHas = *aFromCache = false;
   *aMatchLength = 0;
 
   uint32_t prefix = aCompletion.ToUint32();
 
   bool found;
   nsresult rv = mPrefixSet->Contains(prefix, &found);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -438,24 +438,43 @@ LookupCacheV2::Has(const Completion& aCo
   if (found) {
     *aHas = true;
     *aMatchLength = PREFIX_SIZE;
   }
 
   if ((mGetHashCache.BinaryIndexOf(aCompletion) != nsTArray<Completion>::NoIndex) ||
       (mUpdateCompletions.BinaryIndexOf(aCompletion) != nsTArray<Completion>::NoIndex)) {
     LOG(("Complete in %s", mTableName.get()));
-    *aComplete = true;
+    *aFromCache = true;
     *aHas = true;
     *aMatchLength = COMPLETE_SIZE;
   }
 
   return NS_OK;
 }
 
+void
+LookupCacheV2::IsHashEntryConfirmed(const Completion& aEntry,
+                                    const TableFreshnessMap& aTableFreshness,
+                                    uint32_t aFreshnessGuarantee,
+                                    bool* aConfirmed)
+{
+  int64_t age; // in seconds
+  bool found = aTableFreshness.Get(mTableName, &age);
+  if (!found) {
+    *aConfirmed = false;
+  } else {
+    int64_t now = (PR_Now() / PR_USEC_PER_SEC);
+    MOZ_ASSERT(age <= now);
+
+    // Considered completion as unsafe if its table is up-to-date.
+    *aConfirmed = (now - age) < aFreshnessGuarantee;
+  }
+}
+
 nsresult
 LookupCacheV2::Build(AddPrefixArray& aAddPrefixes,
                      AddCompleteArray& aAddCompletes)
 {
   Telemetry::Accumulate(Telemetry::URLCLASSIFIER_LC_COMPLETIONS,
                         static_cast<uint32_t>(aAddCompletes.Length()));
 
   mUpdateCompletions.Clear();
--- a/toolkit/components/url-classifier/LookupCache.h
+++ b/toolkit/components/url-classifier/LookupCache.h
@@ -20,19 +20,18 @@
 namespace mozilla {
 namespace safebrowsing {
 
 #define MAX_HOST_COMPONENTS 5
 #define MAX_PATH_COMPONENTS 4
 
 class LookupResult {
 public:
-  LookupResult() : mComplete(false), mNoise(false),
-                   mFresh(false), mProtocolConfirmed(false),
-                   mPartialHashLength(0) {}
+  LookupResult() : mNoise(false), mProtocolConfirmed(false),
+                   mPartialHashLength(0), mConfirmed(false) {}
 
   // The fragment that matched in the LookupCache
   union {
     Prefix fixedLengthPrefix;
     Completion complete;
   } hash;
 
   const Completion &CompleteHash() {
@@ -48,37 +47,36 @@ public:
   nsCString PartialHashHex() {
     nsAutoCString hex;
     for (size_t i = 0; i < mPartialHashLength; i++) {
       hex.AppendPrintf("%.2X", hash.complete.buf[i]);
     }
     return hex;
   }
 
-  bool Confirmed() const { return (mComplete && mFresh) || mProtocolConfirmed; }
-  bool Complete() const { return mComplete; }
+  bool Confirmed() const { return mConfirmed || mProtocolConfirmed; }
 
   // True if we have a complete match for this hash in the table.
-  bool mComplete;
+  bool Complete() const { return mPartialHashLength == COMPLETE_SIZE; }
 
   // True if this is a noise entry, i.e. an extra entry
   // that is inserted to mask the true URL we are requesting.
   // Noise entries will not have a complete 256-bit hash as
   // they are fetched from the local 32-bit database and we
   // don't know the corresponding full URL.
   bool mNoise;
 
-  // True if we've updated this table recently-enough.
-  bool mFresh;
-
   bool mProtocolConfirmed;
 
   nsCString mTableName;
 
   uint32_t mPartialHashLength;
+
+  // True as long as this lookup is complete and hasn't expired.
+  bool mConfirmed;
 };
 
 typedef nsTArray<LookupResult> LookupResultArray;
 
 struct CacheResult {
   AddComplete entry;
   nsCString table;
 
@@ -134,18 +132,23 @@ public:
 #if DEBUG
   void DumpCache();
 #endif
 
   virtual nsresult Open();
   virtual nsresult Init() = 0;
   virtual nsresult ClearPrefixes() = 0;
   virtual nsresult Has(const Completion& aCompletion,
-                       bool* aHas, bool* aComplete,
-                       uint32_t* aMatchLength) = 0;
+                       bool* aHas, uint32_t* aMatchLength,
+                       bool* aFromCache) = 0;
+
+  virtual void IsHashEntryConfirmed(const Completion& aEntry,
+                                    const TableFreshnessMap& aTableFreshness,
+                                    uint32_t aFreshnessGuarantee,
+                                    bool* aConfirmed) = 0;
 
   virtual void ClearAll();
 
   template<typename T>
   static T* Cast(LookupCache* aThat) {
     return ((aThat && T::VER == aThat->Ver()) ? reinterpret_cast<T*>(aThat) : nullptr);
   }
 
@@ -181,18 +184,23 @@ public:
                          nsIFile* aStoreFile)
     : LookupCache(aTableName, aProvider, aStoreFile) {}
   ~LookupCacheV2() {}
 
   virtual nsresult Init() override;
   virtual nsresult Open() override;
   virtual void ClearAll() override;
   virtual nsresult Has(const Completion& aCompletion,
-                       bool* aHas, bool* aComplete,
-                       uint32_t* aMatchLength) override;
+                       bool* aHas, uint32_t* aMatchLength,
+                       bool* aFromCache) override;
+
+  virtual void IsHashEntryConfirmed(const Completion& aEntry,
+                                    const TableFreshnessMap& aTableFreshness,
+                                    uint32_t aFreshnessGuarantee,
+                                    bool* aConfirmed) override;
 
   nsresult Build(AddPrefixArray& aAddPrefixes,
                  AddCompleteArray& aAddCompletes);
 
   nsresult GetPrefixes(FallibleTArray<uint32_t>& aAddPrefixes);
 
 #if DEBUG
   void DumpCompletions();
--- a/toolkit/components/url-classifier/LookupCacheV4.cpp
+++ b/toolkit/components/url-classifier/LookupCacheV4.cpp
@@ -75,42 +75,53 @@ LookupCacheV4::Init()
   nsresult rv = mVLPrefixSet->Init(mTableName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 LookupCacheV4::Has(const Completion& aCompletion,
-                   bool* aHas, bool* aComplete,
-                   uint32_t* aMatchLength)
+                   bool* aHas, uint32_t* aMatchLength,
+                   bool* aFromCache)
 {
-  *aHas = *aComplete = false;
+  *aHas = *aFromCache = false;
   *aMatchLength = 0;
 
   uint32_t length = 0;
   nsDependentCSubstring fullhash;
   fullhash.Rebind((const char *)aCompletion.buf, COMPLETE_SIZE);
 
   nsresult rv = mVLPrefixSet->Matches(fullhash, &length);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aHas = length >= PREFIX_SIZE;
-  *aComplete = length == COMPLETE_SIZE;
   *aMatchLength = length;
 
   if (LOG_ENABLED()) {
     uint32_t prefix = aCompletion.ToUint32();
     LOG(("Probe in V4 %s: %X, found %d, complete %d", mTableName.get(),
-          prefix, *aHas, *aComplete));
+          prefix, *aHas, length == COMPLETE_SIZE));
   }
 
+  // TODO : Bug 1311935 - Implement v4 caching
+
   return NS_OK;
 }
 
+void
+LookupCacheV4::IsHashEntryConfirmed(const Completion& aEntry,
+                                    const TableFreshnessMap& aTableFreshness,
+                                    uint32_t aFreshnessGuarantee,
+                                    bool* aConfirmed)
+{
+  // TODO : Bug 1311935 - Implement v4 caching
+  *aConfirmed = true;
+}
+
 nsresult
 LookupCacheV4::Build(PrefixStringMap& aPrefixMap)
 {
   return mVLPrefixSet->SetPrefixes(aPrefixMap);
 }
 
 nsresult
 LookupCacheV4::GetPrefixes(PrefixStringMap& aPrefixMap)
--- a/toolkit/components/url-classifier/LookupCacheV4.h
+++ b/toolkit/components/url-classifier/LookupCacheV4.h
@@ -20,18 +20,23 @@ public:
   explicit LookupCacheV4(const nsACString& aTableName,
                          const nsACString& aProvider,
                          nsIFile* aStoreFile)
     : LookupCache(aTableName, aProvider, aStoreFile) {}
   ~LookupCacheV4() {}
 
   virtual nsresult Init() override;
   virtual nsresult Has(const Completion& aCompletion,
-                       bool* aHas, bool* aComplete,
-                       uint32_t* aMatchLength) override;
+                       bool* aHas, uint32_t* aMatchLength,
+                       bool* aFromCache) override;
+
+  virtual void IsHashEntryConfirmed(const Completion& aEntry,
+                                    const TableFreshnessMap& aTableFreshness,
+                                    uint32_t aFreshnessGuarantee,
+                                    bool* aConfirmed) override;
 
   nsresult Build(PrefixStringMap& aPrefixMap);
 
   nsresult GetPrefixes(PrefixStringMap& aPrefixMap);
 
   // ApplyUpdate will merge data stored in aTableUpdate with prefixes in aInputMap.
   nsresult ApplyUpdate(TableUpdateV4* aTableUpdate,
                        PrefixStringMap& aInputMap,
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -1007,20 +1007,19 @@ nsUrlClassifierLookupCallback::LookupCom
                                           gethashUrl,
                                           result.mTableName,
                                           this);
         if (NS_SUCCEEDED(rv)) {
           mPendingCompletions++;
         }
       } else {
         // For tables with no hash completer, a complete hash match is
-        // good enough, we'll consider it fresh, even if it hasn't been updated
-        // in 45 minutes.
+        // good enough, we'll consider it is valid.
         if (result.Complete()) {
-          result.mFresh = true;
+          result.mConfirmed = true;
           LOG(("Skipping completion in a table without a valid completer (%s).",
                result.mTableName.get()));
         } else {
           NS_WARNING("Partial match in a table without a valid completer, ignoring partial match.");
         }
       }
     }
   }
--- a/toolkit/components/url-classifier/tests/gtest/TestLookupCacheV4.cpp
+++ b/toolkit/components/url-classifier/tests/gtest/TestLookupCacheV4.cpp
@@ -55,23 +55,23 @@ TestHasPrefix(const _Fragment& aFragment
 
   RunTestInNewThread([&] () -> void {
     UniquePtr<LookupCache> cache = SetupLookupCacheV4(array);
 
     Completion lookupHash;
     nsCOMPtr<nsICryptoHash> cryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID);
     lookupHash.FromPlaintext(aFragment, cryptoHash);
 
-    bool has, complete;
+    bool has, fromCache;
     uint32_t matchLength;
-    nsresult rv = cache->Has(lookupHash, &has, &complete, &matchLength);
+    nsresult rv = cache->Has(lookupHash, &has, &matchLength, &fromCache);
 
     EXPECT_EQ(rv, NS_OK);
     EXPECT_EQ(has, aExpectedHas);
-    EXPECT_EQ(complete, aExpectedComplete);
+    EXPECT_EQ(matchLength == COMPLETE_SIZE, aExpectedComplete);
 
     cache->ClearAll();
   });
 
 }
 
 TEST(LookupCacheV4, HasComplete)
 {
--- a/toolkit/modules/PopupNotifications.jsm
+++ b/toolkit/modules/PopupNotifications.jsm
@@ -711,17 +711,21 @@ PopupNotifications.prototype = {
       if (popupnotification)
         gNotificationParents.set(popupnotification, popupnotification.parentNode);
       else
         popupnotification = doc.createElementNS(XUL_NS, "popupnotification");
 
       popupnotification.setAttribute("label", n.message);
       popupnotification.setAttribute("id", popupnotificationID);
       popupnotification.setAttribute("popupid", n.id);
-      popupnotification.setAttribute("closebuttoncommand", `PopupNotifications._dismiss(event, ${TELEMETRY_STAT_DISMISSAL_CLOSE_BUTTON});`);
+      if (Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton")) {
+        popupnotification.setAttribute("closebuttoncommand", "PopupNotifications._onButtonEvent(event, 'secondarybuttoncommand');");
+      } else {
+        popupnotification.setAttribute("closebuttoncommand", `PopupNotifications._dismiss(event, ${TELEMETRY_STAT_DISMISSAL_CLOSE_BUTTON});`);
+      }
       if (n.mainAction) {
         popupnotification.setAttribute("buttonlabel", n.mainAction.label);
         popupnotification.setAttribute("buttonaccesskey", n.mainAction.accessKey);
         popupnotification.setAttribute("buttoncommand", "PopupNotifications._onButtonEvent(event, 'buttoncommand');");
         popupnotification.setAttribute("dropmarkerpopupshown", "PopupNotifications._onButtonEvent(event, 'dropmarkerpopupshown');");
         popupnotification.setAttribute("learnmoreclick", "PopupNotifications._onButtonEvent(event, 'learnmoreclick');");
         popupnotification.setAttribute("menucommand", "PopupNotifications._onMenuCommand(event);");
       } else {
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -601,19 +601,27 @@ def check_minimum_llvm_config_version(ll
 
         To compile Stylo, please install at least version {} of
         Clang + LLVM and ensure that the 'llvm-config' from that
         installation is first on your path.
 
         You can verify this by typing 'llvm-config --version'.
         '''.format(version, min_version)))
 
-@depends(llvm_config, '--with-libclang-path', '--with-clang-path')
+@depends('--enable-stylo', '--enable-stylo-build-bindgen',
+         llvm_config, '--with-libclang-path', '--with-clang-path')
 @imports(_from='textwrap', _import='dedent')
-def bindgen_config_paths(llvm_config, libclang_path, clang_path):
+def bindgen_config_paths(stylo_enabled, bindgen_enabled,
+                         llvm_config, libclang_path, clang_path):
+    if not stylo_enabled:
+        return None
+
+    if not bindgen_enabled:
+        return None
+
     if not libclang_path and not clang_path:
         # We must have LLVM_CONFIG in this case.
         if not llvm_config:
             return None
 
         check_minimum_llvm_config_version(llvm_config)
         return namespace(
             libclang_path=invoke_llvm_config(llvm_config, '--libdir'),
--- a/toolkit/mozapps/extensions/test/browser/browser-common.ini
+++ b/toolkit/mozapps/extensions/test/browser/browser-common.ini
@@ -60,8 +60,9 @@ skip-if = os == 'win' # Disabled on Wind
 [browser_inlinesettings_info.js]
 [browser_tabsettings.js]
 [browser_pluginprefs.js]
 skip-if = buildapp == 'mulet'
 [browser_CTP_plugins.js]
 skip-if = buildapp == 'mulet'
 [browser_webext_options.js]
 tags = webextensions
+skip-if = e10s # Bug 1315042
--- a/toolkit/themes/shared/media/videocontrols.css
+++ b/toolkit/themes/shared/media/videocontrols.css
@@ -480,21 +480,16 @@ audio > xul|videocontrols {
 
 /* For high contrast theme in Windows */
 %ifdef XP_WIN
 .controlsSpacer,
 .clickToPlay {
   background-color: transparent;
 }
 
-.controlsSpacer:hover {
-  background-color: rgb(254,255,255);
-  opacity: .4;
-}
-
 @media (-moz-windows-default-theme) {
   .controlsSpacer {
     background-color: rgba(255,255,255,.4);
   }
 
   .clickToPlay {
     background-color: #1a1a1a;
   }
--- a/xpcom/components/Module.h
+++ b/xpcom/components/Module.h
@@ -17,17 +17,17 @@ namespace mozilla {
 /**
  * A module implements one or more XPCOM components. This structure is used
  * for both binary and script modules, but the registration members
  * (cids/contractids/categoryentries) are unused for modules which are loaded
  * via a module loader.
  */
 struct Module
 {
-  static const unsigned int kVersion = 53;
+  static const unsigned int kVersion = 54;
 
   struct CIDEntry;
 
   typedef already_AddRefed<nsIFactory> (*GetFactoryProcPtr)(
     const Module& module, const CIDEntry& entry);
 
   typedef nsresult (*ConstructorProcPtr)(nsISupports* aOuter,
                                          const nsIID& aIID,
--- a/xpcom/threads/MozPromise.h
+++ b/xpcom/threads/MozPromise.h
@@ -992,55 +992,87 @@ public:
       mMonitor->AssertCurrentThreadOwns();
     }
 
     RefPtr<typename PromiseType::Private> p = mPromise;
     mPromise = nullptr;
     return p.forget();
   }
 
-  void Resolve(typename PromiseType::ResolveValueType aResolveValue,
+  void Resolve(const typename PromiseType::ResolveValueType& aResolveValue,
                const char* aMethodName)
   {
     if (mMonitor) {
       mMonitor->AssertCurrentThreadOwns();
     }
     MOZ_ASSERT(mPromise);
     mPromise->Resolve(aResolveValue, aMethodName);
     mPromise = nullptr;
   }
-
+  void Resolve(typename PromiseType::ResolveValueType&& aResolveValue,
+               const char* aMethodName)
+  {
+    if (mMonitor) {
+      mMonitor->AssertCurrentThreadOwns();
+    }
+    MOZ_ASSERT(mPromise);
+    mPromise->Resolve(Move(aResolveValue), aMethodName);
+    mPromise = nullptr;
+  }
 
-  void ResolveIfExists(typename PromiseType::ResolveValueType aResolveValue,
+  void ResolveIfExists(const typename PromiseType::ResolveValueType& aResolveValue,
                        const char* aMethodName)
   {
     if (!IsEmpty()) {
       Resolve(aResolveValue, aMethodName);
     }
   }
+  void ResolveIfExists(typename PromiseType::ResolveValueType&& aResolveValue,
+                       const char* aMethodName)
+  {
+    if (!IsEmpty()) {
+      Resolve(Move(aResolveValue), aMethodName);
+    }
+  }
 
-  void Reject(typename PromiseType::RejectValueType aRejectValue,
+  void Reject(const typename PromiseType::RejectValueType& aRejectValue,
               const char* aMethodName)
   {
     if (mMonitor) {
       mMonitor->AssertCurrentThreadOwns();
     }
     MOZ_ASSERT(mPromise);
     mPromise->Reject(aRejectValue, aMethodName);
     mPromise = nullptr;
   }
-
+  void Reject(typename PromiseType::RejectValueType&& aRejectValue,
+              const char* aMethodName)
+  {
+    if (mMonitor) {
+      mMonitor->AssertCurrentThreadOwns();
+    }
+    MOZ_ASSERT(mPromise);
+    mPromise->Reject(Move(aRejectValue), aMethodName);
+    mPromise = nullptr;
+  }
 
-  void RejectIfExists(typename PromiseType::RejectValueType aRejectValue,
+  void RejectIfExists(const typename PromiseType::RejectValueType& aRejectValue,
                       const char* aMethodName)
   {
     if (!IsEmpty()) {
       Reject(aRejectValue, aMethodName);
     }
   }
+  void RejectIfExists(typename PromiseType::RejectValueType&& aRejectValue,
+                      const char* aMethodName)
+  {
+    if (!IsEmpty()) {
+      Reject(Move(aRejectValue), aMethodName);
+    }
+  }
 
 private:
   Monitor* mMonitor;
   RefPtr<typename PromiseType::Private> mPromise;
 };
 
 /*
  * Class to encapsulate a MozPromise::Request reference. Use this as the member