Merge mozilla-inbound to mozilla-central r=merge a=merge
authorCosmin Sabou <csabou@mozilla.com>
Wed, 20 Dec 2017 23:42:30 +0200
changeset 397027 62dd5404cf55e29412d5fff8fe9105076b1ca437
parent 396994 1fc9f886516a3c96edcedda5d9e17183bebd6f8b (current diff)
parent 397026 47eabc18d2945fa94e0f5aed76c877b9ad3427dd (diff)
child 397043 7c7b2f1d488aed629c0f8bdc7c3a38a29a84b540
child 397089 1b3de2d3ea462004aff9ae62bd9c3511ef397b84
push id33122
push usercsabou@mozilla.com
push dateWed, 20 Dec 2017 21:42:56 +0000
treeherdermozilla-central@62dd5404cf55 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone59.0a1
first release with
nightly linux32
62dd5404cf55 / 59.0a1 / 20171220220602 / files
nightly linux64
62dd5404cf55 / 59.0a1 / 20171220220602 / files
nightly mac
62dd5404cf55 / 59.0a1 / 20171220220602 / files
nightly win32
62dd5404cf55 / 59.0a1 / 20171220220602 / files
nightly win64
62dd5404cf55 / 59.0a1 / 20171220220602 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central r=merge a=merge
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/execorder.html.ini
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html.ini
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html.ini
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html.ini
testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html.ini
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1208,16 +1208,35 @@ var gBrowserInit = {
       if (linkedBrowser) {
         remoteType = linkedBrowser.remoteType;
         isRemote = remoteType != E10SUtils.NOT_REMOTE;
         sameProcessAsFrameLoader = linkedBrowser.frameLoader;
       }
       initBrowser.removeAttribute("blank");
     }
 
+    // Set a sane starting width/height for all resolutions on new profiles.
+    if (Services.prefs.getBoolPref("privacy.resistFingerprinting")) {
+      // When the fingerprinting resistance is enabled, making sure that we don't
+      // have a maximum window to interfere with generating rounded window dimensions.
+      document.documentElement.setAttribute("sizemode", "normal");
+    } else if (!document.documentElement.hasAttribute("width")) {
+      const TARGET_WIDTH = 1280;
+      const TARGET_HEIGHT = 1040;
+      let width = Math.min(screen.availWidth * .9, TARGET_WIDTH);
+      let height = Math.min(screen.availHeight * .9, TARGET_HEIGHT);
+
+      document.documentElement.setAttribute("width", width);
+      document.documentElement.setAttribute("height", height);
+
+      if (width < TARGET_WIDTH && height < TARGET_HEIGHT) {
+        document.documentElement.setAttribute("sizemode", "maximized");
+      }
+    }
+
     gBrowser.updateBrowserRemoteness(initBrowser, isRemote, {
       remoteType, sameProcessAsFrameLoader
     });
   },
 
   onLoad() {
     gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver);
 
@@ -1270,37 +1289,16 @@ var gBrowserInit = {
     Services.obs.notifyObservers(window, "browser-window-before-show");
 
     gUIDensity.init();
 
     if (AppConstants.CAN_DRAW_IN_TITLEBAR) {
       gDragSpaceObserver.init();
     }
 
-    let isResistFingerprintingEnabled = Services.prefs.getBoolPref("privacy.resistFingerprinting");
-
-    // Set a sane starting width/height for all resolutions on new profiles.
-    if (isResistFingerprintingEnabled) {
-      // When the fingerprinting resistance is enabled, making sure that we don't
-      // have a maximum window to interfere with generating rounded window dimensions.
-      document.documentElement.setAttribute("sizemode", "normal");
-    } else if (!document.documentElement.hasAttribute("width")) {
-      const TARGET_WIDTH = 1280;
-      const TARGET_HEIGHT = 1040;
-      let width = Math.min(screen.availWidth * .9, TARGET_WIDTH);
-      let height = Math.min(screen.availHeight * .9, TARGET_HEIGHT);
-
-      document.documentElement.setAttribute("width", width);
-      document.documentElement.setAttribute("height", height);
-
-      if (width < TARGET_WIDTH && height < TARGET_HEIGHT) {
-        document.documentElement.setAttribute("sizemode", "maximized");
-      }
-    }
-
     if (!window.toolbar.visible) {
       // adjust browser UI for popups
       gURLBar.setAttribute("readonly", "true");
     }
 
     // Misc. inits.
     TabletModeUpdater.init();
     CombinedStopReload.ensureInitialized();
--- a/browser/base/content/test/performance/browser.ini
+++ b/browser/base/content/test/performance/browser.ini
@@ -23,12 +23,13 @@ skip-if = !e10s
 [browser_tabopen_reflows.js]
 [browser_tabopen_squeeze_reflows.js]
 [browser_tabstrip_overflow_underflow_reflows.js]
 [browser_tabswitch_reflows.js]
 [browser_toolbariconcolor_restyles.js]
 [browser_urlbar_keyed_search_reflows.js]
 skip-if = (os == 'linux') || (os == 'win' && debug) # Disabled on Linux and Windows debug due to perma failures. Bug 1392320.
 [browser_urlbar_search_reflows.js]
+skip-if = debug && (os == 'linux' || os == 'win') # Disabled on Linux and Windows debug due to intermittent timeouts. Bug 1414126.
 [browser_windowclose_reflows.js]
 [browser_windowopen_flicker.js]
 skip-if = (debug && os == 'win') # Disabled on windows debug for intermittent leaks
 [browser_windowopen_reflows.js]
--- a/browser/base/content/test/performance/browser_startup_flicker.js
+++ b/browser/base/content/test/performance/browser_startup_flicker.js
@@ -43,37 +43,23 @@ add_task(async function() {
         {name: "bug 1403648 - urlbar down arrow shouldn't flicker",
          condition: r => // 5x9px area, sometimes less at the end of the opacity transition
                          inRange(r.h, 3, 5) && inRange(r.w, 7, 9) &&
                          inRange(r.y1, 40, 80) && // in the toolbar
                          // at ~80% of the window width
                          inRange(r.x1, width * .75, width * .9)
         },
 
-        {name: "bug 1394914 - sidebar toolbar icon should be visible at first paint",
-         condition: r => r.h == 13 && inRange(r.w, 14, 16) && // icon size
-                         inRange(r.y1, 40, 80) && // in the toolbar
-                         // near the right end of screen
-                         inRange(r.x1, width - 100, width - 50)
-        },
-
         {name: "bug 1403648 - urlbar should be focused at first paint",
          condition: r => inRange(r.y2, 60, 80) && // in the toolbar
                          // taking 50% to 75% of the window width
                          inRange(r.w, width * .5, width * .75) &&
                          // starting at 15 to 25% of the window width
                          inRange(r.x1, width * .15, width * .25)
         },
-
-        {name: "bug 1421460 - restore icon should be visible at first paint",
-         condition: r => r.w == 9 && r.h == 9 && // 9x9 icon
-                         AppConstants.platform == "win" &&
-                         // near the right end of the screen
-                         inRange(r.x1, width - 80, width - 70)
-        },
       ];
 
       let rectText = `${rect.toSource()}, window width: ${width}`;
       for (let e of exceptions) {
         if (e.condition(rect)) {
           todo(false, e.name + ", " + rectText);
           return false;
         }
--- a/browser/base/content/test/performance/browser_windowopen_flicker.js
+++ b/browser/base/content/test/performance/browser_windowopen_flicker.js
@@ -93,23 +93,16 @@ add_task(async function() {
         {name: "bug 1403648 - urlbar down arrow shouldn't flicker",
          condition: r => // 5x9px area, sometimes less at the end of the opacity transition
                          inRange(r.h, 3, 5) && inRange(r.w, 7, 9) &&
                          inRange(r.y1, 40, 80) && // in the toolbar
                          // at ~80% of the window width
                          inRange(r.x1, width * .75, width * .9)
         },
 
-        {name: "bug 1394914 - sidebar toolbar icon should be visible at first paint",
-         condition: r => r.h == 13 && inRange(r.w, 14, 16) && // icon size
-                         inRange(r.y1, 40, 80) && // in the toolbar
-                         // near the right end of screen
-                         inRange(r.x1, width - 100, width - 50)
-        },
-
         {name: "bug 1403648 - urlbar should be focused at first paint",
          condition: r => inRange(r.y2, 60, 80) && // in the toolbar
                          // taking 50% to 75% of the window width
                          inRange(r.w, width * .5, width * .75) &&
                          // starting at 15 to 25% of the window width
                          inRange(r.x1, width * .15, width * .25)
         },
 
--- a/browser/base/content/test/performance/browser_windowopen_reflows.js
+++ b/browser/base/content/test/performance/browser_windowopen_reflows.js
@@ -7,17 +7,27 @@
  * WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
  * is a whitelist that should slowly go away as we improve the performance of
  * the front-end. Instead of adding more reflows to the whitelist, you should
  * be modifying your code to avoid the reflow.
  *
  * See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
  * for tips on how to do that.
  */
-const EXPECTED_REFLOWS = [];
+const EXPECTED_REFLOWS = [
+  {
+    stack: [
+      "onOverflow@resource:///modules/CustomizableUI.jsm",
+      "init@resource:///modules/CustomizableUI.jsm",
+      "observe@resource:///modules/CustomizableUI.jsm",
+      "_delayedStartup@chrome://browser/content/browser.js",
+    ],
+    times: 2, // This number should only ever go down - never up.
+  },
+];
 
 if (Services.appinfo.OS == "WINNT") {
   EXPECTED_REFLOWS.push(
     {
       stack: [
         "verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
         "_update@chrome://browser/content/browser-tabsintitlebar.js",
         "init@chrome://browser/content/browser-tabsintitlebar.js",
--- a/browser/components/customizableui/content/toolbar.xml
+++ b/browser/components/customizableui/content/toolbar.xml
@@ -13,43 +13,24 @@
       <stylesheet src="chrome://global/skin/toolbar.css"/>
     </resources>
     <implementation>
       <field name="overflowedDuringConstruction">null</field>
 
       <constructor><![CDATA[
           let scope = {};
           Cu.import("resource:///modules/CustomizableUI.jsm", scope);
+          let CustomizableUI = scope.CustomizableUI;
           // Add an early overflow event listener that will mark if the
           // toolbar overflowed during construction.
-          if (scope.CustomizableUI.isAreaOverflowable(this.id)) {
+          if (CustomizableUI.isAreaOverflowable(this.id)) {
             this.addEventListener("overflow", this);
             this.addEventListener("underflow", this);
           }
 
-          if (document.readyState == "complete") {
-            this._init();
-          } else {
-            // Need to wait until XUL overlays are loaded. See bug 554279.
-            let self = this;
-            document.addEventListener("readystatechange", function onReadyStateChange() {
-              if (document.readyState != "complete")
-                return;
-              document.removeEventListener("readystatechange", onReadyStateChange);
-              self._init();
-            });
-          }
-      ]]></constructor>
-
-      <method name="_init">
-        <body><![CDATA[
-          let scope = {};
-          Cu.import("resource:///modules/CustomizableUI.jsm", scope);
-          let CustomizableUI = scope.CustomizableUI;
-
           // Bug 989289: Forcibly set the now unsupported "mode" and "iconsize"
           // attributes, just in case they accidentally get restored from
           // persistence from a user that's been upgrading and downgrading.
           if (CustomizableUI.isBuiltinToolbar(this.id)) {
             const kAttributes = new Map([["mode", "icons"], ["iconsize", "small"]]);
             for (let [attribute, value] of kAttributes) {
               if (this.getAttribute(attribute) != value) {
                 this.setAttribute(attribute, value);
@@ -78,18 +59,17 @@
             }
           }
 
           // pass the current set of children for comparison with placements:
           let children = Array.from(this.childNodes)
                               .filter(node => node.getAttribute("skipintoolbarset") != "true" && node.id)
                               .map(node => node.id);
           CustomizableUI.registerToolbarNode(this, children);
-        ]]></body>
-      </method>
+      ]]></constructor>
 
       <method name="handleEvent">
         <parameter name="aEvent"/>
         <body><![CDATA[
           if (aEvent.type == "overflow" && aEvent.detail > 0) {
             if (this.overflowable && this.overflowable.initialized) {
               this.overflowable.onOverflow(aEvent);
             } else {
--- a/browser/config/tooltool-manifests/linux64/jsshell.manifest
+++ b/browser/config/tooltool-manifests/linux64/jsshell.manifest
@@ -1,9 +1,9 @@
 [
   {
-    "size": 996696,
-    "digest": "7c09f6144c84a6dd9bdb8d817e7957b432e72138ecb4a2adf6f5754b7ef2a2bd5c53ba113659283644f510a1aab87a1efc09851bc07457978eb0c0a63f4c29a4",
+    "size": 2156788,
+    "digest": "8e3b50c4879f1321655a7b2b613dc6c981580fb5e14af585eda1f79020e98378f67bfdf46bf49c060635b283b1892d0e5ca23ab219af83de0456fbee3e276983",
     "algorithm": "sha512",
     "filename": "breakpad-tools.tar.xz",
     "unpack": true
   }
 ]
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -1012,17 +1012,17 @@ def compiler(language, host_or_target, c
                 log.warning('The value of %s is not used by this build system.'
                             % linker_var)
 
         if host_or_target == target:
             @depends(valid_compiler)
             def is_msvc(compiler):
                 return compiler.type == 'msvc'
 
-            imply_option('LINK', linker, reason='LD', when=is_msvc)
+            imply_option('LINKER', linker, reason='LD', when=is_msvc)
 
     return valid_compiler
 
 
 c_compiler = compiler('C', target)
 cxx_compiler = compiler('C++', target, c_compiler=c_compiler)
 host_c_compiler = compiler('C', host, other_compiler=c_compiler)
 host_cxx_compiler = compiler('C++', host, c_compiler=host_c_compiler,
--- a/build/moz.configure/windows.configure
+++ b/build/moz.configure/windows.configure
@@ -424,19 +424,19 @@ def valid_mt(path):
     except subprocess.CalledProcessError:
         pass
     raise FatalCheckError('%s is not Microsoft Manifest Tool')
 
 
 set_config('MSMANIFEST_TOOL', depends(valid_mt)(lambda x: bool(x)))
 
 
-link = check_prog('LINK', ('link.exe',), paths=vc_compiler_path)
+link = check_prog('LINKER', ('link.exe',), paths=vc_compiler_path)
 
-add_old_configure_assignment('LINK', link)
+add_old_configure_assignment('LINKER', link)
 
 
 # Normally, we'd just have CC, etc. set to absolute paths, but the build system
 # doesn't currently handle properly the case where the paths contain spaces.
 # Additionally, there's the issue described in toolchain.configure, in
 # valid_compiler().
 @depends(sdk_bin_path)
 @imports('os')
--- a/config/config.mk
+++ b/config/config.mk
@@ -413,17 +413,17 @@ CREATE_PRECOMPLETE_CMD = $(PYTHON) $(abs
 # MDDEPDIR is the subdirectory where dependency files are stored
 MDDEPDIR := .deps
 
 EXPAND_LIBS_EXEC = $(PYTHON) $(MOZILLA_DIR)/config/expandlibs_exec.py
 EXPAND_LIBS_GEN = $(PYTHON) $(MOZILLA_DIR)/config/expandlibs_gen.py
 EXPAND_AR = $(EXPAND_LIBS_EXEC) --extract -- $(AR)
 EXPAND_CC = $(EXPAND_LIBS_EXEC) --uselist -- $(CC)
 EXPAND_CCC = $(EXPAND_LIBS_EXEC) --uselist -- $(CCC)
-EXPAND_LINK = $(EXPAND_LIBS_EXEC) --uselist -- $(LINK)
+EXPAND_LINK = $(EXPAND_LIBS_EXEC) --uselist -- $(LINKER)
 EXPAND_MKSHLIB_ARGS = --uselist
 ifdef SYMBOL_ORDER
 EXPAND_MKSHLIB_ARGS += --symbol-order $(SYMBOL_ORDER)
 endif
 EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) $(EXPAND_MKSHLIB_ARGS) -- $(MKSHLIB)
 
 # $(call CHECK_SYMBOLS,lib,PREFIX,dep_name,test)
 # Checks that the given `lib` doesn't contain dependency on symbols with a
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -586,17 +586,17 @@ ifdef ENABLE_STRIP
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
 endif
 
 $(HOST_PROGRAM): $(HOST_PROGOBJS) $(HOST_LIBS) $(HOST_EXTRA_DEPS) $(GLOBAL_DEPS)
 	$(REPORT_BUILD)
 ifeq (_WINNT,$(GNU_CC)_$(HOST_OS_ARCH))
-	$(EXPAND_LIBS_EXEC) -- $(LINK) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $(HOST_OBJS) $(WIN32_EXE_LDFLAGS) $(HOST_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
+	$(EXPAND_LIBS_EXEC) -- $(LINKER) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $(HOST_OBJS) $(WIN32_EXE_LDFLAGS) $(HOST_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
 ifdef MSMANIFEST_TOOL
 	@if test -f $@.manifest; then \
 		if test -f '$(srcdir)/$@.manifest'; then \
 			echo 'Embedding manifest from $(srcdir)/$@.manifest and $@.manifest'; \
 			$(MT) -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' $@.manifest -OUTPUTRESOURCE:$@\;1; \
 		else \
 			echo 'Embedding manifest from $@.manifest'; \
 			$(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
@@ -645,17 +645,17 @@ ifdef ENABLE_STRIP
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
 endif
 
 $(HOST_SIMPLE_PROGRAMS): host_%$(HOST_BIN_SUFFIX): host_%.$(OBJ_SUFFIX) $(HOST_LIBS) $(HOST_EXTRA_DEPS) $(GLOBAL_DEPS)
 	$(REPORT_BUILD)
 ifeq (WINNT_,$(HOST_OS_ARCH)_$(GNU_CC))
-	$(EXPAND_LIBS_EXEC) -- $(LINK) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
+	$(EXPAND_LIBS_EXEC) -- $(LINKER) -NOLOGO -OUT:$@ -PDB:$(HOST_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(HOST_LIBS) $(HOST_EXTRA_LIBS)
 else
 ifneq (,$(HOST_CPPSRCS)$(USE_HOST_CXX))
 	$(EXPAND_LIBS_EXEC) -- $(HOST_CXX) $(HOST_OUTOPTION)$@ $(HOST_CXX_LDFLAGS) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS)
 else
 	$(EXPAND_LIBS_EXEC) -- $(HOST_CC) $(HOST_OUTOPTION)$@ $(HOST_C_LDFLAGS) $< $(HOST_LIBS) $(HOST_EXTRA_LIBS)
 endif
 endif
 ifndef CROSS_COMPILE
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -15217,17 +15217,17 @@ nsDocShell::ShouldPrepareForIntercept(ns
 
   if (!aIsNonSubresourceRequest) {
     nsCOMPtr<nsIDocument> doc = GetDocument();
     if (!doc) {
       return NS_ERROR_NOT_AVAILABLE;
     }
 
     ErrorResult rv;
-    *aShouldIntercept = swm->IsControlled(doc, rv);
+    *aShouldIntercept = doc->GetController().isSome();
     if (NS_WARN_IF(rv.Failed())) {
       return rv.StealNSResult();
     }
 
     return NS_OK;
   }
 
   // If the user has set a cookie policy that restricts cookies, then
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -43,16 +43,17 @@
 #include "nsWidgetsCID.h"
 #include "nsIDOMNode.h"
 #include "mozAutoDocUpdate.h"
 #include "nsIWebNavigation.h"
 #include "nsGenericHTMLElement.h"
 #include "nsHTMLDNSPrefetch.h"
 #include "nsIObserverService.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/ServiceWorkerDescriptor.h"
 #include "mozilla/dom/ScriptLoader.h"
 #include "nsParserConstants.h"
 #include "nsSandboxFlags.h"
 #include "Link.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -1104,17 +1105,17 @@ nsContentSink::ProcessOfflineManifest(co
   // Don't bother processing offline manifest for documents
   // without a docshell
   if (!mDocShell) {
     return;
   }
 
   // If this document has been interecepted, let's skip the processing of the
   // manifest.
-  if (nsContentUtils::IsControlledByServiceWorker(mDocument)) {
+  if (mDocument->GetController().isSome()) {
     return;
   }
 
   // If the docshell's in private browsing mode, we don't want to do any
   // manifest processing.
   nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(mDocShell);
   if (loadContext->UsePrivateBrowsing()) {
     return;
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -1974,46 +1974,24 @@ nsContentUtils::ParseLegacyFontSize(cons
       value = 3 + value;
     }
   }
 
   return clamped(value, 1, 7);
 }
 
 /* static */
-bool
-nsContentUtils::IsControlledByServiceWorker(nsIDocument* aDocument)
-{
-  if (nsContentUtils::IsInPrivateBrowsing(aDocument)) {
-    return false;
-  }
-
-  RefPtr<workers::ServiceWorkerManager> swm =
-    workers::ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
-
-  ErrorResult rv;
-  bool controlled = swm->IsControlled(aDocument, rv);
-  if (NS_WARN_IF(rv.Failed())) {
-    rv.SuppressException();
-    return false;
-  }
-
-  return controlled;
-}
-
-/* static */
 void
 nsContentUtils::GetOfflineAppManifest(nsIDocument *aDocument, nsIURI **aURI)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aDocument);
   *aURI = nullptr;
 
-  if (IsControlledByServiceWorker(aDocument)) {
+  if (aDocument->GetController().isSome()) {
     return;
   }
 
   Element* docElement = aDocument->GetRootElement();
   if (!docElement) {
     return;
   }
 
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2392,21 +2392,16 @@ public:
    * Returns true if the <style scoped> enabling pref is true.
    */
   static bool IsScopedStylePrefEnabled()
   {
     return sIsScopedStyleEnabled;
   }
 
   /**
-   * Return true if this doc is controlled by a ServiceWorker.
-   */
-  static bool IsControlledByServiceWorker(nsIDocument* aDocument);
-
-  /**
    * Fire mutation events for changes caused by parsing directly into a
    * context node.
    *
    * @param aDoc the document of the node
    * @param aDest the destination node that got stuff appended to it
    * @param aOldChildCount the number of children the node had before parsing
    */
   static void FireMutationEventsForDirectParsing(nsIDocument* aDoc,
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -207,29 +207,32 @@
 
 #include "imgILoader.h"
 #include "imgRequestProxy.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsSandboxFlags.h"
 #include "mozilla/dom/AnimatableBinding.h"
 #include "mozilla/dom/AnonymousContent.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/ClientInfo.h"
+#include "mozilla/dom/ClientState.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/DocumentTimeline.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/HTMLBodyElement.h"
 #include "mozilla/dom/HTMLInputElement.h"
 #include "mozilla/dom/ImageTracker.h"
 #include "mozilla/dom/MediaQueryList.h"
 #include "mozilla/dom/NodeFilterBinding.h"
 #include "mozilla/OwningNonNull.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/WebComponentsBinding.h"
 #include "mozilla/dom/CustomElementRegistryBinding.h"
 #include "mozilla/dom/CustomElementRegistry.h"
+#include "mozilla/dom/ServiceWorkerDescriptor.h"
 #include "mozilla/dom/TimeoutManager.h"
 #include "mozilla/ExtensionPolicyService.h"
 #include "nsFrame.h"
 #include "nsDOMCaretPosition.h"
 #include "nsViewportInfo.h"
 #include "mozilla/StaticPtr.h"
 #include "nsITextControlElement.h"
 #include "nsIDOMNSEditableElement.h"
@@ -5047,17 +5050,17 @@ nsDocument::SetScriptGlobalObject(nsIScr
         loadGroup->RemoveRequest(mOnloadBlocker, nullptr, NS_OK);
       }
     }
 
     using mozilla::dom::workers::ServiceWorkerManager;
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     if (swm) {
       ErrorResult error;
-      if (swm->IsControlled(this, error)) {
+      if (GetController().isSome()) {
         imgLoader* loader = nsContentUtils::GetImgLoaderForDocument(this);
         if (loader) {
           loader->ClearCacheForControlledDocument(this);
         }
 
         // We may become controlled again if this document comes back out
         // of bfcache.  Clear our state to allow that to happen.  Only
         // clear this flag if we are actually controlled, though, so pages
@@ -5837,16 +5840,46 @@ nsIDocument::GetAnonRootIfInAnonymousCon
       return child->IsElement() ? child->AsElement() : nullptr;
     }
     child = parent;
     parent = child->GetParentNode();
   }
   return nullptr;
 }
 
+Maybe<ClientInfo>
+nsIDocument::GetClientInfo() const
+{
+  nsPIDOMWindowInner* inner = GetInnerWindow();
+  if (inner) {
+    return Move(inner->GetClientInfo());
+  }
+  return Move(Maybe<ClientInfo>());
+}
+
+Maybe<ClientState>
+nsIDocument::GetClientState() const
+{
+  nsPIDOMWindowInner* inner = GetInnerWindow();
+  if (inner) {
+    return Move(inner->GetClientState());
+  }
+  return Move(Maybe<ClientState>());
+}
+
+Maybe<ServiceWorkerDescriptor>
+nsIDocument::GetController() const
+{
+  nsPIDOMWindowInner* inner = GetInnerWindow();
+  if (inner) {
+    return Move(inner->GetController());
+  }
+  return Move(Maybe<ServiceWorkerDescriptor>());
+}
+
 //
 // nsIDOMDocument interface
 //
 DocumentType*
 nsIDocument::GetDoctype() const
 {
   for (nsIContent* child = GetFirstChild();
        child;
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -7407,27 +7407,28 @@ nsGlobalWindowInner::InitWasOffline()
 int16_t
 nsGlobalWindowInner::Orientation(CallerType aCallerType) const
 {
   return nsContentUtils::ResistFingerprinting(aCallerType) ?
            0 : WindowOrientationObserver::OrientationAngle();
 }
 #endif
 
-Console*
+already_AddRefed<Console>
 nsGlobalWindowInner::GetConsole(ErrorResult& aRv)
 {
   if (!mConsole) {
     mConsole = Console::Create(this, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   }
 
-  return mConsole;
+  RefPtr<Console> console = mConsole;
+  return console.forget();
 }
 
 bool
 nsGlobalWindowInner::IsSecureContext() const
 {
   return JS_GetIsSecureContext(js::GetObjectCompartment(GetWrapperPreserveColor()));
 }
 
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -679,17 +679,17 @@ public:
   nsIDOMNavigator* GetNavigator() override;
   nsIDOMOfflineResourceList* GetApplicationCache(mozilla::ErrorResult& aError);
   already_AddRefed<nsIDOMOfflineResourceList> GetApplicationCache() override;
 
 #if defined(MOZ_WIDGET_ANDROID)
   int16_t Orientation(mozilla::dom::CallerType aCallerType) const;
 #endif
 
-  mozilla::dom::Console* GetConsole(mozilla::ErrorResult& aRv);
+  already_AddRefed<mozilla::dom::Console> GetConsole(mozilla::ErrorResult& aRv);
 
   // https://w3c.github.io/webappsec-secure-contexts/#dom-window-issecurecontext
   bool IsSecureContext() const;
 
   void GetSidebar(mozilla::dom::OwningExternalOrWindowProxy& aResult,
                   mozilla::ErrorResult& aRv);
   already_AddRefed<mozilla::dom::External> GetExternal(mozilla::ErrorResult& aRv);
 
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -123,16 +123,18 @@ class ImageLoader;
 class Rule;
 } // namespace css
 
 namespace dom {
 class Animation;
 class AnonymousContent;
 class Attr;
 class BoxObject;
+class ClientInfo;
+class ClientState;
 class CDATASection;
 class Comment;
 struct CustomElementDefinition;
 class DocGroup;
 class DocumentFragment;
 class DocumentTimeline;
 class DocumentType;
 class DOMImplementation;
@@ -154,16 +156,17 @@ class MediaQueryList;
 class GlobalObject;
 class NodeFilter;
 class NodeIterator;
 enum class OrientationType : uint8_t;
 class ProcessingInstruction;
 class Promise;
 class ScriptLoader;
 class Selection;
+class ServiceWorkerDescriptor;
 class StyleSheetList;
 class SVGDocument;
 class SVGSVGElement;
 class Touch;
 class TouchList;
 class TreeWalker;
 class XPathEvaluator;
 class XPathExpression;
@@ -1119,16 +1122,20 @@ public:
    */
   virtual void ScheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG) = 0;
   // Unschedule an element scheduled by ScheduleFrameRequestCallback (e.g. for when it is destroyed)
   virtual void UnscheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG) = 0;
 
   // Resolve all SVG pres attrs scheduled in ScheduleSVGForPresAttrEvaluation
   virtual void ResolveScheduledSVGPresAttrs() = 0;
 
+  mozilla::Maybe<mozilla::dom::ClientInfo> GetClientInfo() const;
+  mozilla::Maybe<mozilla::dom::ClientState> GetClientState() const;
+  mozilla::Maybe<mozilla::dom::ServiceWorkerDescriptor> GetController() const;
+
 protected:
   virtual Element *GetRootElementInternal() const = 0;
 
   void SetPageUnloadingEventTimeStamp()
   {
     MOZ_ASSERT(!mPageUnloadingEventTimeStamp);
     mPageUnloadingEventTimeStamp = mozilla::TimeStamp::NowLoRes();
   }
--- a/dom/clients/manager/ClientInfo.cpp
+++ b/dom/clients/manager/ClientInfo.cpp
@@ -6,16 +6,18 @@
 
 #include "ClientInfo.h"
 
 #include "mozilla/dom/ClientIPCTypes.h"
 
 namespace mozilla {
 namespace dom {
 
+using mozilla::ipc::PrincipalInfo;
+
 ClientInfo::ClientInfo(const nsID& aId,
                        ClientType aType,
                        const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
                        const TimeStamp& aCreationTime)
   : mData(MakeUnique<IPCClientInfo>(aId, aType, aPrincipalInfo, aCreationTime,
                                     EmptyCString(),
                                     mozilla::dom::FrameType::None))
 {
@@ -105,10 +107,36 @@ ClientInfo::SetFrameType(mozilla::dom::F
 }
 
 const IPCClientInfo&
 ClientInfo::ToIPC() const
 {
   return *mData;
 }
 
+bool
+ClientInfo::IsPrivateBrowsing() const
+{
+  switch(PrincipalInfo().type()) {
+    case PrincipalInfo::TContentPrincipalInfo:
+    {
+      auto& p = PrincipalInfo().get_ContentPrincipalInfo();
+      return p.attrs().mPrivateBrowsingId != 0;
+    }
+    case PrincipalInfo::TSystemPrincipalInfo:
+    {
+      return false;
+    }
+    case PrincipalInfo::TNullPrincipalInfo:
+    {
+      auto& p = PrincipalInfo().get_NullPrincipalInfo();
+      return p.attrs().mPrivateBrowsingId != 0;
+    }
+    default:
+    {
+      // clients should never be expanded principals
+      MOZ_CRASH("unexpected principal type!");
+    }
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientInfo.h
+++ b/dom/clients/manager/ClientInfo.h
@@ -86,14 +86,18 @@ public:
   // Set the frame type for the global.  This should only happen once the
   // global has become execution ready.
   void
   SetFrameType(mozilla::dom::FrameType aFrameType);
 
   // Convert to the ipdl generated type.
   const IPCClientInfo&
   ToIPC() const;
+
+  // Determine if the client is in private browsing mode.
+  bool
+  IsPrivateBrowsing() const;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // _mozilla_dom_ClientInfo_h
--- a/dom/clients/manager/ClientOpenWindowUtils.cpp
+++ b/dom/clients/manager/ClientOpenWindowUtils.cpp
@@ -75,25 +75,18 @@ public:
     nsresult rv = securityManager->CheckSameOriginURI(doc->GetOriginalURI(),
                                                       mBaseURI, false);
     if (NS_FAILED(rv)) {
       mPromise->Resolve(NS_OK, __func__);
       mPromise = nullptr;
       return NS_OK;
     }
 
-    nsPIDOMWindowInner* innerWindow = doc->GetInnerWindow();
-    if (NS_WARN_IF(!innerWindow)) {
-      mPromise->Reject(NS_ERROR_FAILURE, __func__);
-      mPromise = nullptr;
-      return NS_OK;
-    }
-
-    Maybe<ClientInfo> info = innerWindow->GetClientInfo();
-    Maybe<ClientState> state = innerWindow->GetClientState();
+    Maybe<ClientInfo> info(doc->GetClientInfo());
+    Maybe<ClientState> state(doc->GetClientState());
 
     if (NS_WARN_IF(info.isNothing() || state.isNothing())) {
       mPromise->Reject(NS_ERROR_FAILURE, __func__);
       mPromise = nullptr;
       return NS_OK;
     }
 
     mPromise->Resolve(ClientInfoAndState(info.ref().ToIPC(), state.ref().ToIPC()),
--- a/dom/clients/manager/ClientSource.cpp
+++ b/dom/clients/manager/ClientSource.cpp
@@ -350,16 +350,21 @@ ClientSource::WorkerSyncPing(WorkerPriva
   GetActor()->SendWorkerSyncPing();
 }
 
 void
 ClientSource::SetController(const ServiceWorkerDescriptor& aServiceWorker)
 {
   NS_ASSERT_OWNINGTHREAD(ClientSource);
 
+  // A client in private browsing mode should never be controlled by
+  // a service worker.  The principal origin attributes should guarantee
+  // this invariant.
+  MOZ_DIAGNOSTIC_ASSERT(!mClientInfo.IsPrivateBrowsing());
+
   if (mController.isSome() && mController.ref() == aServiceWorker) {
     return;
   }
 
   mController.reset();
   mController.emplace(aServiceWorker);
 
   RefPtr<ServiceWorkerContainer> swc;
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -812,19 +812,18 @@ Console::Create(nsPIDOMWindowInner* aWin
   return console.forget();
 }
 
 Console::Console(nsPIDOMWindowInner* aWindow)
   : mWindow(aWindow)
   , mOuterID(0)
   , mInnerID(0)
   , mStatus(eUnknown)
+  , mCreationTimeStamp(TimeStamp::Now())
 {
-  MOZ_ASSERT_IF(NS_IsMainThread(), aWindow);
-
   if (mWindow) {
     mInnerID = mWindow->WindowID();
 
     // Without outerwindow any console message coming from this object will not
     // shown in the devtools webconsole. But this should be fine because
     // probably we are shutting down, or the window is CCed/GCed.
     nsPIDOMWindowOuter* outerWindow = mWindow->GetOuterWindow();
     if (outerWindow) {
@@ -850,19 +849,21 @@ Console::Initialize(ErrorResult& aRv)
 
   if (NS_IsMainThread()) {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (NS_WARN_IF(!obs)) {
       aRv.Throw(NS_ERROR_FAILURE);
       return;
     }
 
-    aRv = obs->AddObserver(this, "inner-window-destroyed", true);
-    if (NS_WARN_IF(aRv.Failed())) {
-      return;
+    if (mWindow) {
+      aRv = obs->AddObserver(this, "inner-window-destroyed", true);
+      if (NS_WARN_IF(aRv.Failed())) {
+        return;
+      }
     }
 
     aRv = obs->AddObserver(this, "memory-pressure", true);
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
   }
 
@@ -1218,46 +1219,48 @@ Console::MethodInternal(JSContext* aCx, 
 
   if (NS_WARN_IF(!callData->Initialize(aCx, aMethodName, aMethodString,
                                        aData, this))) {
     return;
   }
 
   OriginAttributes oa;
 
-  if (mWindow) {
-    // Save the principal's OriginAttributes in the console event data
-    // so that we will be able to filter messages by origin attributes.
-    nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
-    if (NS_WARN_IF(!sop)) {
-      return;
-    }
-
-    nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
-    if (NS_WARN_IF(!principal)) {
-      return;
-    }
-
-    oa = principal->OriginAttributesRef();
-    callData->SetAddonId(principal);
+  if (NS_IsMainThread()) {
+    if (mWindow) {
+      // Save the principal's OriginAttributes in the console event data
+      // so that we will be able to filter messages by origin attributes.
+      nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
+      if (NS_WARN_IF(!sop)) {
+        return;
+      }
+
+      nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
+      if (NS_WARN_IF(!principal)) {
+        return;
+      }
+
+      oa = principal->OriginAttributesRef();
+      callData->SetAddonId(principal);
 
 #ifdef DEBUG
-    if (!nsContentUtils::IsSystemPrincipal(principal)) {
-      nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(mWindow);
-      if (webNav) {
-        nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
-        MOZ_ASSERT(loadContext);
-
-        bool pb;
-        if (NS_SUCCEEDED(loadContext->GetUsePrivateBrowsing(&pb))) {
-          MOZ_ASSERT(pb == !!oa.mPrivateBrowsingId);
+      if (!nsContentUtils::IsSystemPrincipal(principal)) {
+        nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(mWindow);
+        if (webNav) {
+          nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
+          MOZ_ASSERT(loadContext);
+
+          bool pb;
+          if (NS_SUCCEEDED(loadContext->GetUsePrivateBrowsing(&pb))) {
+            MOZ_ASSERT(pb == !!oa.mPrivateBrowsingId);
+          }
         }
       }
+#endif
     }
-#endif
   } else {
     WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(workerPrivate);
     oa = workerPrivate->GetOriginAttributes();
   }
 
   callData->SetOriginAttributes(oa);
 
@@ -1285,77 +1288,21 @@ Console::MethodInternal(JSContext* aCx, 
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
   }
 
   DOMHighResTimeStamp monotonicTimer;
 
   // Monotonic timer for 'time' and 'timeEnd'
-  if (aMethodName == MethodTime ||
-      aMethodName == MethodTimeEnd ||
-      aMethodName == MethodTimeStamp) {
-    if (mWindow) {
-      nsGlobalWindowInner *win = nsGlobalWindowInner::Cast(mWindow);
-      MOZ_ASSERT(win);
-
-      RefPtr<Performance> performance = win->GetPerformance();
-      if (!performance) {
-        return;
-      }
-
-      monotonicTimer = performance->Now();
-
-      nsDocShell* docShell = static_cast<nsDocShell*>(mWindow->GetDocShell());
-      RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
-      bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
-
-      // The 'timeStamp' recordings do not need an argument; use empty string
-      // if no arguments passed in.
-      if (isTimelineRecording && aMethodName == MethodTimeStamp) {
-        JS::Rooted<JS::Value> value(aCx, aData.Length() == 0
-          ? JS_GetEmptyStringValue(aCx)
-          : aData[0]);
-        JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
-        if (!jsString) {
-          return;
-        }
-
-        nsAutoJSString key;
-        if (!key.init(aCx, jsString)) {
-          return;
-        }
-
-        timelines->AddMarkerForDocShell(docShell, Move(
-          MakeUnique<TimestampTimelineMarker>(key)));
-      }
-      // For `console.time(foo)` and `console.timeEnd(foo)`.
-      else if (isTimelineRecording && aData.Length() == 1) {
-        JS::Rooted<JS::Value> value(aCx, aData[0]);
-        JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
-        if (!jsString) {
-          return;
-        }
-
-        nsAutoJSString key;
-        if (!key.init(aCx, jsString)) {
-          return;
-        }
-
-        timelines->AddMarkerForDocShell(docShell, Move(
-          MakeUnique<ConsoleTimelineMarker>(
-            key, aMethodName == MethodTime ? MarkerTracingType::START
-                                           : MarkerTracingType::END)));
-      }
-    } else {
-      WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
-      MOZ_ASSERT(workerPrivate);
-
-      monotonicTimer = workerPrivate->TimeStampToDOMHighRes(TimeStamp::Now());
-    }
+  if ((aMethodName == MethodTime ||
+       aMethodName == MethodTimeEnd ||
+       aMethodName == MethodTimeStamp) &&
+      !MonotonicTimer(aCx, aMethodName, aData, &monotonicTimer)) {
+    return;
   }
 
   if (aMethodName == MethodTime && !aData.IsEmpty()) {
     callData->mStartTimerStatus = StartTimer(aCx, aData[0],
                                              monotonicTimer,
                                              callData->mStartTimerLabel,
                                              &callData->mStartTimerValue);
   }
@@ -1370,17 +1317,27 @@ Console::MethodInternal(JSContext* aCx, 
   else if (aMethodName == MethodCount) {
     callData->mCountValue = IncreaseCounter(aCx, aData, callData->mCountLabel);
     if (!callData->mCountValue) {
       return;
     }
   }
 
   if (NS_IsMainThread()) {
-    callData->SetIDs(mOuterID, mInnerID);
+    if (mWindow) {
+      callData->SetIDs(mOuterID, mInnerID);
+    } else {
+      nsAutoString filename;
+      if (callData->mTopStackFrame.isSome()) {
+        filename = callData->mTopStackFrame->mFilename;
+      }
+
+      callData->SetIDs(NS_LITERAL_STRING("jsm"), filename);
+    }
+
     ProcessCallData(aCx, callData, aData);
 
     // Just because we don't want to expose
     // retrieveConsoleEvents/setConsoleEventHandler to main-thread, we can
     // cleanup the mCallDataStorage:
     UnstoreCallData(callData);
     return;
   }
@@ -2431,34 +2388,42 @@ Console::GetConsole(const GlobalObject& 
 
   if (console->IsShuttingDown()) {
     return nullptr;
   }
 
   return console.forget();
 }
 
-/* static */ Console*
+/* static */ already_AddRefed<Console>
 Console::GetConsoleInternal(const GlobalObject& aGlobal, ErrorResult& aRv)
 {
   // Worklet
   if (NS_IsMainThread()) {
     nsCOMPtr<WorkletGlobalScope> workletScope =
       do_QueryInterface(aGlobal.GetAsSupports());
     if (workletScope) {
       return workletScope->GetConsole(aRv);
     }
   }
 
   // Window
   if (NS_IsMainThread()) {
     nsCOMPtr<nsPIDOMWindowInner> innerWindow =
       do_QueryInterface(aGlobal.GetAsSupports());
-    if (NS_WARN_IF(!innerWindow)) {
-      return nullptr;
+
+    // we are probably running a chrome script.
+    if (!innerWindow) {
+      RefPtr<Console> console = new Console(nullptr);
+      console->Initialize(aRv);
+      if (NS_WARN_IF(aRv.Failed())) {
+        return nullptr;
+      }
+
+      return console.forget();
     }
 
     nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(innerWindow);
     return window->GetConsole(aRv);
   }
 
   // Workers
   MOZ_ASSERT(!NS_IsMainThread());
@@ -2487,10 +2452,90 @@ Console::GetConsoleInternal(const Global
       workerPrivate->DebuggerGlobalScope();
     MOZ_ASSERT(debuggerScope);
     MOZ_ASSERT(debuggerScope == global, "Which kind of global do we have?");
 
     return debuggerScope->GetConsole(aRv);
   }
 }
 
+bool
+Console::MonotonicTimer(JSContext* aCx, MethodName aMethodName,
+                        const Sequence<JS::Value>& aData,
+                        DOMHighResTimeStamp* aTimeStamp)
+{
+  if (mWindow) {
+    nsGlobalWindowInner *win = nsGlobalWindowInner::Cast(mWindow);
+    MOZ_ASSERT(win);
+
+    RefPtr<Performance> performance = win->GetPerformance();
+    if (!performance) {
+      return false;
+    }
+
+    *aTimeStamp = performance->Now();
+
+    nsDocShell* docShell = static_cast<nsDocShell*>(mWindow->GetDocShell());
+    RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
+    bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
+
+    // The 'timeStamp' recordings do not need an argument; use empty string
+    // if no arguments passed in.
+    if (isTimelineRecording && aMethodName == MethodTimeStamp) {
+      JS::Rooted<JS::Value> value(aCx, aData.Length() == 0
+        ? JS_GetEmptyStringValue(aCx)
+        : aData[0]);
+      JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
+      if (!jsString) {
+        return false;
+      }
+
+      nsAutoJSString key;
+      if (!key.init(aCx, jsString)) {
+        return false;
+      }
+
+      timelines->AddMarkerForDocShell(docShell, Move(
+        MakeUnique<TimestampTimelineMarker>(key)));
+    }
+    // For `console.time(foo)` and `console.timeEnd(foo)`.
+    else if (isTimelineRecording && aData.Length() == 1) {
+      JS::Rooted<JS::Value> value(aCx, aData[0]);
+      JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
+      if (!jsString) {
+        return false;
+      }
+
+      nsAutoJSString key;
+      if (!key.init(aCx, jsString)) {
+        return false;
+      }
+
+      timelines->AddMarkerForDocShell(docShell, Move(
+        MakeUnique<ConsoleTimelineMarker>(
+          key, aMethodName == MethodTime ? MarkerTracingType::START
+                                         : MarkerTracingType::END)));
+    }
+
+    return true;
+  }
+
+  if (NS_IsMainThread()) {
+    double duration = (TimeStamp::Now() - mCreationTimeStamp).ToMilliseconds();
+
+    // Round down to the nearest 5us, because if the timer is too accurate
+    // people can do nasty timing attacks with it.  See similar code in the
+    // worker Performance implementation.
+    const double maxResolutionMs = 0.005;
+    return nsRFPService::ReduceTimePrecisionAsMSecs(
+      floor(duration / maxResolutionMs) * maxResolutionMs);
+    return true;
+  }
+
+  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
+
+  *aTimeStamp = workerPrivate->TimeStampToDOMHighRes(TimeStamp::Now());
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/console/Console.h
+++ b/dom/console/Console.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Console_h
 #define mozilla_dom_Console_h
 
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/JSObjectHolder.h"
+#include "mozilla/TimeStamp.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsPIDOMWindow.h"
 
@@ -154,17 +155,17 @@ private:
     MethodAssert,
     MethodCount,
     MethodClear
   };
 
   static already_AddRefed<Console>
   GetConsole(const GlobalObject& aGlobal);
 
-  static Console*
+  static already_AddRefed<Console>
   GetConsoleInternal(const GlobalObject& aGlobal, ErrorResult &aRv);
 
   static void
   ProfileMethod(const GlobalObject& aGlobal, const nsAString& aAction,
                 const Sequence<JS::Value>& aData);
 
   void
   ProfileMethodInternal(JSContext* aCx, const nsAString& aAction,
@@ -365,16 +366,21 @@ private:
   GetOrCreateSandbox(JSContext* aCx, nsIPrincipal* aPrincipal);
 
   void
   AssertIsOnOwningThread() const;
 
   bool
   IsShuttingDown() const;
 
+  bool
+  MonotonicTimer(JSContext* aCx, MethodName aMethodName,
+                 const Sequence<JS::Value>& aData,
+                 DOMHighResTimeStamp* aTimeStamp);
+
   // All these nsCOMPtr are touched on main thread only.
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   nsCOMPtr<nsIConsoleAPIStorage> mStorage;
   RefPtr<JSObjectHolder> mSandbox;
 
   // Touched on the owner thread.
   nsDataHashtable<nsStringHashKey, DOMHighResTimeStamp> mTimerRegistry;
   nsDataHashtable<nsStringHashKey, uint32_t> mCounterRegistry;
@@ -401,16 +407,20 @@ private:
   uint64_t mInnerID;
 
   enum {
     eUnknown,
     eInitialized,
     eShuttingDown
   } mStatus;
 
+  // This is used when Console is created and it's used only for JSM custom
+  // console instance.
+  mozilla::TimeStamp mCreationTimeStamp;
+
   friend class ConsoleCallData;
   friend class ConsoleRunnable;
   friend class ConsoleCallDataRunnable;
   friend class ConsoleProfileRunnable;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/console/moz.build
+++ b/dom/console/moz.build
@@ -39,10 +39,11 @@ LOCAL_INCLUDES += [
     '/docshell/base',
     '/dom/base',
     '/dom/workers',
     '/js/xpconnect/src',
 ]
 
 MOCHITEST_MANIFESTS += [ 'tests/mochitest.ini' ]
 MOCHITEST_CHROME_MANIFESTS += [ 'tests/chrome.ini' ]
+XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
 
 FINAL_LIBRARY = 'xul'
--- a/dom/console/tests/chrome.ini
+++ b/dom/console/tests/chrome.ini
@@ -1,6 +1,8 @@
 [DEFAULT]
 skip-if = os == 'android'
 support-files =
   file_empty.html
+  console.jsm
 
 [test_console.xul]
+[test_jsm.xul]
new file mode 100644
--- /dev/null
+++ b/dom/console/tests/console.jsm
@@ -0,0 +1,11 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+this.EXPORTED_SYMBOLS = [ "ConsoleTest" ];
+
+this.ConsoleTest = {
+  go: function() {
+    console.log("Hello world!");
+  }
+};
new file mode 100644
--- /dev/null
+++ b/dom/console/tests/test_jsm.xul
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<window title="Console + JSM"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="test();">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+  <script type="application/javascript">
+  <![CDATA[
+
+const JSM = "chrome://mochitests/content/chrome/dom/console/tests/console.jsm";
+
+function consoleListener() {
+  SpecialPowers.addObserver(this, "console-api-log-event");
+}
+
+consoleListener.prototype  = {
+  observe: function(aSubject, aTopic, aData) {
+    if (aTopic == "console-api-log-event") {
+      var obj = aSubject.wrappedJSObject;
+      if (obj.innerID == JSM) {
+        is(obj.ID, "jsm", "ID and InnerID are correctly set.");
+        is (obj.arguments[0], "Hello world!", "Message matches");
+
+        SpecialPowers.removeObserver(this, "console-api-log-event");
+        SimpleTest.finish();
+      }
+    }
+  }
+}
+function test() {
+  SimpleTest.waitForExplicitFinish();
+
+  var cl = new consoleListener();
+  Components.utils.import(JSM);
+  ConsoleTest.go();
+}
+
+  ]]>
+  </script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  </body>
+</window>
new file mode 100644
--- /dev/null
+++ b/dom/console/tests/xpcshell/test_basic.js
@@ -0,0 +1,31 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+add_task(async function() {
+  do_check_true("console" in this);
+
+  let p = new Promise(resolve => {
+    function consoleListener() {
+      Services.obs.addObserver(this, "console-api-log-event");
+    }
+
+    consoleListener.prototype  = {
+      observe: function(aSubject, aTopic, aData) {
+        let obj = aSubject.wrappedJSObject;
+        do_check_true(obj.arguments[0] === 42, "Message received!");
+        do_check_true(obj.ID === "jsm", "The ID is JSM");
+        do_check_true(obj.innerID.endsWith("test_basic.js"), "The innerID matches");
+
+        Services.obs.removeObserver(this, "console-api-log-event");
+        resolve();
+      }
+    };
+
+    new consoleListener();
+  });
+
+  console.log(42);
+  await p;
+});
new file mode 100644
--- /dev/null
+++ b/dom/console/tests/xpcshell/xpcshell.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+head =
+support-files =
+
+[test_basic.js]
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -285,16 +285,18 @@ TimeStamp EventStateManager::sLatestUser
 TimeStamp EventStateManager::sHandlingInputStart;
 
 EventStateManager::WheelPrefs*
   EventStateManager::WheelPrefs::sInstance = nullptr;
 bool EventStateManager::WheelPrefs::sWheelEventsEnabledOnPlugins = true;
 EventStateManager::DeltaAccumulator*
   EventStateManager::DeltaAccumulator::sInstance = nullptr;
 
+bool EventStateManager::sIsInputEventsSuppressed = false;
+
 EventStateManager::EventStateManager()
   : mLockCursor(0)
   , mLastFrameConsumedSetCursor(false)
   , mCurrentTarget(nullptr)
     // init d&d gesture state machine variables
   , mGestureDownPoint(0,0)
   , mPresContext(nullptr)
   , mLClickCount(0)
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -310,16 +310,32 @@ public:
   static void GetUserPrefsForWheelEvent(const WidgetWheelEvent* aEvent,
                                         double* aOutMultiplierX,
                                         double* aOutMultiplierY);
 
   // Returns whether or not a frame can be vertically scrolled with a mouse
   // wheel (as opposed to, say, a selection or touch scroll).
   static bool CanVerticallyScrollFrameWithWheel(nsIFrame* aFrame);
 
+  static void SuppressInputEvents()
+  {
+    MOZ_ASSERT(!sIsInputEventsSuppressed);
+    sIsInputEventsSuppressed = true;
+  }
+
+  static void UnsuppressInputEvents()
+  {
+    sIsInputEventsSuppressed = false;
+  }
+
+  static bool IsInputEventsSuppressed()
+  {
+    return sIsInputEventsSuppressed;
+  }
+
   // Holds the point in screen coords that a mouse event was dispatched to,
   // before we went into pointer lock mode. This is constantly updated while
   // the pointer is not locked, but we don't update it while the pointer is
   // locked. This is used by dom::Event::GetScreenCoords() to make mouse
   // events' screen coord appear frozen at the last mouse position while
   // the pointer is locked.
   static CSSIntPoint sLastScreenPoint;
 
@@ -1083,16 +1099,18 @@ private:
   // Time at which we began handling user input. Reset to the epoch
   // once we have finished handling user input.
   static TimeStamp sHandlingInputStart;
 
   // Time at which we began handling the latest user input. Not reset
   // at the end of the input.
   static TimeStamp sLatestUserInputStart;
 
+  static bool sIsInputEventsSuppressed;
+
   RefPtr<OverOutElementsWrapper> mMouseEnterLeaveHelper;
   nsRefPtrHashtable<nsUint32HashKey, OverOutElementsWrapper> mPointersEnterLeaveHelper;
 
 public:
   static nsresult UpdateUserActivityTimer(void);
   // Array for accesskey support
   nsCOMArray<nsIContent> mAccessKeys;
 
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -2295,17 +2295,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
                                presContext->AppUnitsToDevPixels(appPoint.y));
         const WidgetMouseEvent& mouseEvent = *anEvent.AsMouseEvent();
         // Get reference point relative to screen:
         LayoutDeviceIntPoint rootPoint(-1, -1);
         if (widget) {
           rootPoint = anEvent.mRefPoint + widget->WidgetToScreenOffset();
         }
 #ifdef MOZ_WIDGET_GTK
-        Window root = GDK_ROOT_WINDOW();
+        Window root = gfxPlatform::IsHeadless() ? X11None : GDK_ROOT_WINDOW();
 #else
         Window root = X11None; // Could XQueryTree, but this is not important.
 #endif
 
         switch (anEvent.mMessage) {
           case eMouseOver:
           case eMouseOut:
             {
@@ -2382,17 +2382,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
 
    //XXX case eMouseScrollEventClass: not received.
 
    case eKeyboardEventClass:
       if (anEvent.mPluginEvent)
         {
           XKeyEvent &event = pluginEvent.xkey;
 #ifdef MOZ_WIDGET_GTK
-          event.root = GDK_ROOT_WINDOW();
+          event.root = gfxPlatform::IsHeadless() ? X11None : GDK_ROOT_WINDOW();
           event.time = anEvent.mTime;
           const GdkEventKey* gdkEvent =
             static_cast<const GdkEventKey*>(anEvent.mPluginEvent);
           event.keycode = gdkEvent->hardware_keycode;
           event.state = gdkEvent->state;
           switch (anEvent.mMessage)
             {
             case eKeyDown:
--- a/dom/webidl/Console.webidl
+++ b/dom/webidl/Console.webidl
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * For more information on this interface, please see
  * https://console.spec.whatwg.org/#console-namespace
  */
 
-[Exposed=(Window,Worker,WorkerDebugger,Worklet),
+[Exposed=(Window,Worker,WorkerDebugger,Worklet,System),
  ClassString="Console",
  ProtoObjectHack]
 namespace console {
   // Logging
   void assert(optional boolean condition = false, any... data);
   void clear();
   void count(optional DOMString label = "default");
   void debug(any... data);
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -2367,25 +2367,22 @@ ServiceWorkerManager::StartControllingAD
   aRegistration->StartControllingADocument();
   mControlledDocuments.Put(aDoc, aRegistration);
 
   // Mark the document's ClientSource as controlled using the ClientHandle
   // interface.  While we could get at the ClientSource directly from the
   // document here, our goal is to move ServiceWorkerManager to a separate
   // process.  Using the ClientHandle supports this remote operation.
   ServiceWorkerInfo* activeWorker = aRegistration->GetActive();
-  nsPIDOMWindowInner* innerWindow = aDoc->GetInnerWindow();
-  if (activeWorker && innerWindow) {
-    Maybe<ClientInfo> clientInfo = innerWindow->GetClientInfo();
-    if (clientInfo.isSome()) {
-      RefPtr<ClientHandle> clientHandle =
-        ClientManager::CreateHandle(clientInfo.ref(),
-                                    SystemGroup::EventTargetFor(TaskCategory::Other));
-      ref = Move(clientHandle->Control(activeWorker->Descriptor()));
-    }
+  Maybe<ClientInfo> clientInfo = aDoc->GetClientInfo();
+  if (activeWorker && clientInfo.isSome()) {
+    RefPtr<ClientHandle> clientHandle =
+      ClientManager::CreateHandle(clientInfo.ref(),
+                                  SystemGroup::EventTargetFor(TaskCategory::Other));
+    ref = Move(clientHandle->Control(activeWorker->Descriptor()));
   }
 
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_CONTROLLED_DOCUMENTS, 1);
   return Move(ref);
 }
 
 void
 ServiceWorkerManager::StopControllingADocument(ServiceWorkerRegistrationInfo* aRegistration)
@@ -2782,38 +2779,16 @@ ServiceWorkerManager::IsAvailable(nsIPri
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aURI);
 
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetServiceWorkerRegistrationInfo(aPrincipal, aURI);
   return registration && registration->GetActive();
 }
 
-bool
-ServiceWorkerManager::IsControlled(nsIDocument* aDoc, ErrorResult& aRv)
-{
-  MOZ_ASSERT(aDoc);
-
-  if (nsContentUtils::IsInPrivateBrowsing(aDoc)) {
-    // Handle the case where a service worker was previously registered in
-    // a non-private window (bug 1255621).
-    return false;
-  }
-
-  RefPtr<ServiceWorkerRegistrationInfo> registration;
-  nsresult rv = GetDocumentRegistration(aDoc, getter_AddRefs(registration));
-  if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE)) {
-    // It's OK to ignore the case where we don't have a registration.
-    aRv.Throw(rv);
-    return false;
-  }
-
-  return !!registration;
-}
-
 nsresult
 ServiceWorkerManager::GetDocumentRegistration(nsIDocument* aDoc,
                                               ServiceWorkerRegistrationInfo** aRegistrationInfo)
 {
   RefPtr<ServiceWorkerRegistrationInfo> registration;
   if (!mControlledDocuments.Get(aDoc, getter_AddRefs(registration))) {
     return NS_ERROR_NOT_AVAILABLE;
   }
@@ -3268,45 +3243,41 @@ ServiceWorkerManager::SetSkipWaitingFlag
 void
 ServiceWorkerManager::UpdateClientControllers(ServiceWorkerRegistrationInfo* aRegistration)
 {
   AssertIsOnMainThread();
 
   RefPtr<ServiceWorkerInfo> activeWorker = aRegistration->GetActive();
   MOZ_DIAGNOSTIC_ASSERT(activeWorker);
 
-  AutoTArray<nsCOMPtr<nsPIDOMWindowInner>, 16> innerWindows;
+  AutoTArray<nsCOMPtr<nsIDocument>, 16> docList;
   for (auto iter = mControlledDocuments.Iter(); !iter.Done(); iter.Next()) {
     if (iter.UserData() != aRegistration) {
       continue;
     }
 
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(iter.Key());
     if (NS_WARN_IF(!doc)) {
       continue;
     }
 
-    nsPIDOMWindowInner* innerWindow = doc->GetInnerWindow();
-    if (NS_WARN_IF(!innerWindow)) {
-      continue;
-    }
-
-    innerWindows.AppendElement(innerWindow);
+    docList.AppendElement(doc.forget());
   }
 
   // Fire event after iterating mControlledDocuments is done to prevent
   // modification by reentering from the event handlers during iteration.
-  for (auto& innerWindow : innerWindows) {
-    Maybe<ClientInfo> clientInfo = innerWindow->GetClientInfo();
-    if (clientInfo.isSome()) {
-      RefPtr<ClientHandle> clientHandle =
-        ClientManager::CreateHandle(clientInfo.ref(),
-                                    innerWindow->EventTargetFor(TaskCategory::Other));
-      clientHandle->Control(activeWorker->Descriptor());
+  for (auto& doc : docList) {
+    Maybe<ClientInfo> clientInfo = doc->GetClientInfo();
+    if (clientInfo.isNothing()) {
+      continue;
     }
+    RefPtr<ClientHandle> clientHandle =
+      ClientManager::CreateHandle(clientInfo.ref(),
+                                  SystemGroup::EventTargetFor(TaskCategory::Other));
+    clientHandle->Control(activeWorker->Descriptor());
   }
 }
 
 already_AddRefed<ServiceWorkerRegistrationInfo>
 ServiceWorkerManager::GetRegistration(nsIPrincipal* aPrincipal,
                                       const nsACString& aScope) const
 {
   MOZ_ASSERT(aPrincipal);
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -120,19 +120,16 @@ public:
   //       are guaranteed the callback will fire before and remove the ref
   //       from this list before the channel is destroyed.
   typedef nsTArray<nsIInterceptedChannel*> InterceptionList;
   nsClassHashtable<nsCStringHashKey, InterceptionList> mNavigationInterceptions;
 
   bool
   IsAvailable(nsIPrincipal* aPrincipal, nsIURI* aURI);
 
-  bool
-  IsControlled(nsIDocument* aDocument, ErrorResult& aRv);
-
   // Return true if the given content process could potentially be executing
   // service worker code with the given principal.  At the current time, this
   // just means that we have any registration for the origin, regardless of
   // scope.  This is a very weak guarantee but is the best we can do when push
   // notifications can currently spin up a service worker in content processes
   // without our involvement in the parent process.
   //
   // In the future when there is only a single ServiceWorkerManager in the
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -131,29 +131,30 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 JSObject*
 WorkerGlobalScope::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   MOZ_CRASH("We should never get here!");
 }
 
-Console*
+already_AddRefed<Console>
 WorkerGlobalScope::GetConsole(ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   if (!mConsole) {
     mConsole = Console::Create(nullptr, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   }
 
-  return mConsole;
+  RefPtr<Console> console = mConsole;
+  return console.forget();
 }
 
 Crypto*
 WorkerGlobalScope::GetCrypto(ErrorResult& aError)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   if (!mCrypto) {
@@ -1040,30 +1041,31 @@ WorkerDebuggerGlobalScope::SetConsoleEve
   RefPtr<Console> console = scope->GetConsole(aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   console->SetConsoleEventHandler(aHandler);
 }
 
-Console*
+already_AddRefed<Console>
 WorkerDebuggerGlobalScope::GetConsole(ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   // Debugger console has its own console object.
   if (!mConsole) {
     mConsole = Console::Create(nullptr, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   }
 
-  return mConsole;
+  RefPtr<Console> console = mConsole;
+  return console.forget();
 }
 
 void
 WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
                                 const Optional<nsAString>& aString) const
 {
   WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
   if (scope) {
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -87,17 +87,17 @@ public:
                                                          DOMEventTargetHelper)
 
   WorkerGlobalScope*
   Self()
   {
     return this;
   }
 
-  Console*
+  already_AddRefed<Console>
   GetConsole(ErrorResult& aRv);
 
   Console*
   GetConsoleIfExists() const
   {
     return mConsole;
   }
 
@@ -405,17 +405,17 @@ public:
   void
   RetrieveConsoleEvents(JSContext* aCx, nsTArray<JS::Value>& aEvents,
                         ErrorResult& aRv);
 
   void
   SetConsoleEventHandler(JSContext* aCx, AnyCallback* aHandler,
                          ErrorResult& aRv);
 
-  Console*
+  already_AddRefed<Console>
   GetConsole(ErrorResult& aRv);
 
   Console*
   GetConsoleIfExists() const
   {
     return mConsole;
   }
 
--- a/dom/worklet/WorkletGlobalScope.cpp
+++ b/dom/worklet/WorkletGlobalScope.cpp
@@ -49,27 +49,28 @@ WorkletGlobalScope::~WorkletGlobalScope(
 
 JSObject*
 WorkletGlobalScope::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   MOZ_CRASH("We should never get here!");
   return nullptr;
 }
 
-Console*
+already_AddRefed<Console>
 WorkletGlobalScope::GetConsole(ErrorResult& aRv)
 {
   if (!mConsole) {
     mConsole = Console::Create(mWindow, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   }
 
-  return mConsole;
+  RefPtr<Console> console = mConsole;
+  return console.forget();
 }
 
 void
 WorkletGlobalScope::Dump(const Optional<nsAString>& aString) const
 {
   if (!nsContentUtils::DOMWindowDumpEnabled()) {
     return;
   }
--- a/dom/worklet/WorkletGlobalScope.h
+++ b/dom/worklet/WorkletGlobalScope.h
@@ -49,17 +49,17 @@ public:
                    JS::MutableHandle<JSObject*> aReflector) = 0;
 
   virtual JSObject*
   GetGlobalJSObject() override
   {
     return GetWrapper();
   }
 
-  Console*
+  already_AddRefed<Console>
   GetConsole(ErrorResult& aRv);
 
   void
   Dump(const Optional<nsAString>& aString) const;
 
 protected:
   ~WorkletGlobalScope();
 
--- a/image/ImageCacheKey.cpp
+++ b/image/ImageCacheKey.cpp
@@ -163,17 +163,17 @@ ImageCacheKey::GetControlledDocumentToke
   // For non-controlled documents, we just return null.  For controlled
   // documents, we cast the pointer into a void* to avoid dereferencing
   // it (since we only use it for comparisons), and return it.
   void* pointer = nullptr;
   using dom::workers::ServiceWorkerManager;
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   if (aDocument && swm) {
     ErrorResult rv;
-    if (swm->IsControlled(aDocument, rv)) {
+    if (aDocument->GetController().isSome()) {
       pointer = aDocument;
     }
   }
   return pointer;
 }
 
 } // namespace image
 } // namespace mozilla
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -8,16 +8,18 @@
 
 #include "nsICODecoder.h"
 
 #include <stdlib.h>
 
 #include "mozilla/EndianUtils.h"
 #include "mozilla/Move.h"
 
+#include "mozilla/gfx/Swizzle.h"
+
 #include "RasterImage.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace image {
 
 // Constants.
@@ -613,16 +615,23 @@ nsICODecoder::FinishMask()
     }
 
     // Iterate through the alpha values, copying from mask to image.
     MOZ_ASSERT(mMaskBuffer);
     MOZ_ASSERT(bmpDecoder->GetImageDataLength() > 0);
     for (size_t i = 3 ; i < bmpDecoder->GetImageDataLength() ; i += 4) {
       imageData[i] = mMaskBuffer[i];
     }
+    int32_t stride = mDownscaler->TargetSize().width * sizeof(uint32_t);
+    DebugOnly<bool> ret =
+    // We know the format is B8G8R8A8 because we always assume bmp's inside
+    // ico's are transparent. 
+      PremultiplyData(imageData, stride, SurfaceFormat::B8G8R8A8,
+        imageData, stride, SurfaceFormat::B8G8R8A8, mDownscaler->TargetSize());
+    MOZ_ASSERT(ret);
   }
 
   return Transition::To(ICOState::FINISHED_RESOURCE, 0);
 }
 
 LexerTransition<ICOState>
 nsICODecoder::FinishResource()
 {
new file mode 100644
--- /dev/null
+++ b/image/test/reftest/downscaling/1404366-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<body>
+<!--
+	1404366-1.ico is an ico file that contains a 32x32 0RGB (0 for all alpha values) bmp
+	where the color values are all white. It also contains a mask. The mask alternates
+	one pixel fully transparent, one pixel fully opaque. The result of drawing this on
+	a white background should be white. This is testing that we premultiply the color
+	values by the alpha derived from the mark when downscaling. If we do not skia will
+	get confused and likely draw non white pixels.
+-->
+<img src="1404366-1.ico" style="width: 12px; height: 12px;">
+</body>
+</html>
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..51c020b069a541988d83d4f0d99d10222cc87ecf
GIT binary patch
literal 4287
zc%1FXu?@f=5JS<Q4XCIo8G~^VOI{99r$&mtt>?n<WLsk|vp@xU%8SAIzY-CWBuSDa
I>F3t%ypgp`IRF3v
--- a/image/test/reftest/downscaling/reftest.list
+++ b/image/test/reftest/downscaling/reftest.list
@@ -205,10 +205,11 @@ fuzzy(18,128) == downscale-32px.html?-pn
 == huge-1.html?100x32768.gif,100,32768 huge-1.html?100x100.gif,100,32768
 == huge-1.html?32768x100.gif,100,100 huge-1.html?100x100.gif,100,100
 == huge-1.html?32768x100.gif,32768,100 huge-1.html?100x100.gif,32768,100
 == huge-1.html?100x32768.jpg,100,100 huge-1.html?100x100.jpg,100,100
 == huge-1.html?100x32768.jpg,100,32768 huge-1.html?100x100.jpg,100,32768
 == huge-1.html?32768x100.jpg,100,100 huge-1.html?100x100.jpg,100,100
 == huge-1.html?32768x100.jpg,32768,100 huge-1.html?100x100.jpg,32768,100
 
-# Only need to run this with downscaling on
+# Only need to run these with downscaling on
 != 1421191-1.html about:blank
+== 1404366-1.html about:blank
--- a/js/src/devtools/automation/README
+++ b/js/src/devtools/automation/README
@@ -18,20 +18,22 @@ In automation, the test jobs will run wi
 catches crashes and generates minidumps, so that autospider.py can produce a
 readable stack trace at the end of the run. Currently this library is only
 available on linux64, and is built via the following procedure:
 
     % git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
     % export PATH=$PATH:$(pwd)/depot_tools
     % mkdir breakpad
     % cd breakpad
+    # python must be python2.7
     % fetch breakpad
     % cd src
     % git fetch https://github.com/hotsphink/breakpad injector
-    % git checkout injector
+    % git checkout FETCH_HEAD
     % cd ..
     % mkdir obj
     % cd obj
-    % ../src/configure
+    # Possibly set $PATH to include a recent gcc
+    % ../src/configure --enable-static
     % mkdir ../root
     % make install DESTDIR=$(pwd)/../root
 
 The shared library will now be in root/usr/local/lib64/libbreakpadinjector.so
--- a/js/src/devtools/automation/autospider.py
+++ b/js/src/devtools/automation/autospider.py
@@ -362,24 +362,27 @@ if not args.nobuild:
         run_command(['sh', '-c', posixpath.join(PDIR.js_src, 'configure') + ' ' + CONFIGURE_ARGS], check=True)
 
     # Run make
     run_command('%s -w %s' % (MAKE, MAKEFLAGS), shell=True, check=True)
 
     if use_minidump:
         # Convert symbols to breakpad format.
         hostdir = os.path.join(OBJDIR, "dist", "host", "bin")
-        os.makedirs(hostdir)
+        if not os.path.isdir(hostdir):
+            os.makedirs(hostdir)
         shutil.copy(os.path.join(DIR.tooltool, "breakpad-tools", "dump_syms"),
                     os.path.join(hostdir, 'dump_syms'))
         run_command([
             'make',
             'recurse_syms',
             'MOZ_SOURCE_REPO=file://' + DIR.source,
-            'RUST_TARGET=0', 'RUSTC_COMMIT=0'
+            'RUST_TARGET=0', 'RUSTC_COMMIT=0',
+            'MOZ_CRASHREPORTER=1',
+            'MOZ_AUTOMATION_BUILD_SYMBOLS=1',
         ], check=True)
 
 COMMAND_PREFIX = []
 # On Linux, disable ASLR to make shell builds a bit more reproducible.
 if subprocess.call("type setarch >/dev/null 2>&1", shell=True) == 0:
     COMMAND_PREFIX.extend(['setarch', platform.machine(), '-R'])
 
 
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -201,22 +201,28 @@ case "$target" in
         CXXFLAGS="$CXXFLAGS -wd5027"
 
         # -Zc:sizedDealloc- disables C++14 global sized deallocation (see bug 1160146)
         CXXFLAGS="$CXXFLAGS -Zc:sizedDealloc-"
 
         AC_SUBST(MSVC_C_RUNTIME_DLL)
         AC_SUBST(MSVC_CXX_RUNTIME_DLL)
 
-        # Check linker version
-        _LD_FULL_VERSION=`"${LINK}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"`
-        _LD_MAJOR_VERSION=`echo ${_LD_FULL_VERSION} | $AWK -F\. '{ print $1 }'`
-        if test "$_LD_MAJOR_VERSION" != "$_CC_SUITE"; then
-            AC_MSG_ERROR([The linker major version, $_LD_FULL_VERSION,  does not match the compiler suite version, $_CC_SUITE.])
-        fi
+        # Check linker version, except in lld builds
+        case "$LINKER" in
+        *lld*)
+            ;;
+        *)
+            _LD_FULL_VERSION=`"${LINKER}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"`
+            _LD_MAJOR_VERSION=`echo ${_LD_FULL_VERSION} | $AWK -F\. '{ print $1 }'`
+            if test "$_LD_MAJOR_VERSION" != "$_CC_SUITE"; then
+                AC_MSG_ERROR([The linker major version, $_LD_FULL_VERSION,  does not match the compiler suite version, $_CC_SUITE.])
+            fi
+            ;;
+        esac
 
         INCREMENTAL_LINKER=1
 
         unset _MSVC_VER_FILTER
 
         CFLAGS="$CFLAGS -D_HAS_EXCEPTIONS=0"
         CXXFLAGS="$CXXFLAGS -D_HAS_EXCEPTIONS=0"
     else
@@ -670,18 +676,18 @@ case "$target" in
             AS="$(basename "$AS_BIN")"
         fi
         AR='lib'
         AR_FLAGS='-NOLOGO -OUT:$@'
         AR_EXTRACT=
         RANLIB='echo not_ranlib'
         STRIP='echo not_strip'
         PKG_SKIP_STRIP=1
-        MKSHLIB='$(LINK) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
-        MKCSHLIB='$(LINK) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
+        MKSHLIB='$(LINKER) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
+        MKCSHLIB='$(LINKER) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
         WIN32_SUBSYSTEM_VERSION=6.01
         WIN32_CONSOLE_EXE_LDFLAGS=-SUBSYSTEM:CONSOLE,$WIN32_SUBSYSTEM_VERSION
         WIN32_GUI_EXE_LDFLAGS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION
         DSO_LDOPTS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION
         _USE_CPP_INCLUDE_FLAG=1
         _DEFINES_CFLAGS="-FI $jsconfdefs -DMOZILLA_CLIENT"
         _DEFINES_CXXFLAGS="-FI $jsconfdefs -DMOZILLA_CLIENT"
         CFLAGS="$CFLAGS -W3 -Gy -Zc:inline"
--- a/js/src/tests/lib/tasks_unix.py
+++ b/js/src/tests/lib/tasks_unix.py
@@ -1,13 +1,13 @@
 # A unix-oriented process dispatcher.  Uses a single thread with select and
 # waitpid to dispatch tasks.  This avoids several deadlocks that are possible
 # with fork/exec + threads + Python.
 
-import errno, os, select, sys
+import errno, os, select, signal, sys
 from datetime import datetime, timedelta
 from progressbar import ProgressBar
 from results import NullTestOutput, TestOutput, escape_cmdline
 
 class Task(object):
     def __init__(self, test, prefix, pid, stdout, stderr):
         self.test = test
         self.cmd = test.get_command(prefix)
@@ -126,24 +126,26 @@ def remove_task(tasks, pid):
         raise KeyError("No such pid: {}".format(pid))
 
     out = tasks[index]
     tasks.pop(index)
     return out
 
 def timed_out(task, timeout):
     """
-    Return True if the given task has been running for longer than |timeout|.
-    |timeout| may be falsy, indicating an infinite timeout (in which case
-    timed_out always returns False).
+    Return a timedelta with the amount we are overdue, or False if the timeout
+    has not yet been reached (or timeout is falsy, indicating there is no
+    timeout.)
     """
-    if timeout:
-        now = datetime.now()
-        return (now - task.start) > timedelta(seconds=timeout)
-    return False
+    if not timeout:
+        return False
+
+    elapsed = datetime.now() - task.start
+    over = elapsed - timedelta(seconds=timeout)
+    return over if over.total_seconds() > 0 else False
 
 def reap_zombies(tasks, timeout):
     """
     Search for children of this process that have finished. If they are tasks,
     then this routine will clean up the child. This method returns a new task
     list that has had the ended tasks removed, followed by the list of finished
     tasks.
     """
@@ -176,21 +178,27 @@ def reap_zombies(tasks, timeout):
                 ''.join(ended.err),
                 returncode,
                 (datetime.now() - ended.start).total_seconds(),
                 timed_out(ended, timeout)))
     return tasks, finished
 
 def kill_undead(tasks, timeout):
     """
-    Signal all children that are over the given timeout.
+    Signal all children that are over the given timeout. Use SIGABRT first to
+    generate a stack dump. If it still doesn't die for another 30 seconds, kill
+    with SIGKILL.
     """
     for task in tasks:
-        if timed_out(task, timeout):
-            os.kill(task.pid, 9)
+        over = timed_out(task, timeout)
+        if over:
+            if over.total_seconds() < 30:
+                os.kill(task.pid, signal.SIGABRT)
+            else:
+                os.kill(task.pid, signal.SIGKILL)
 
 def run_all_tests(tests, prefix, pb, options):
     # Copy and reverse for fast pop off end.
     tests = list(tests)
     tests = tests[:]
     tests.reverse()
 
     # The set of currently running tests.
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -6926,16 +6926,26 @@ PresShell::HandleEvent(nsIFrame* aFrame,
   }
 
   if (mIsDestroying ||
       (sDisableNonTestMouseEvents && !aEvent->mFlags.mIsSynthesizedForTests &&
        aEvent->HasMouseEventMessage())) {
     return NS_OK;
   }
 
+  if (EventStateManager::IsInputEventsSuppressed() &&
+      (aEvent->mClass == eMouseEventClass ||
+       aEvent->mClass == eWheelEventClass ||
+       aEvent->mClass == ePointerEventClass ||
+       aEvent->mClass == eTouchEventClass ||
+       aEvent->mClass == eKeyboardEventClass ||
+       aEvent->mClass == eCompositionEventClass)) {
+    return NS_OK;
+  }
+
   RecordMouseLocation(aEvent);
 
   if (AccessibleCaretEnabled(mDocument->GetDocShell())) {
     // We have to target the focus window because regardless of where the
     // touch goes, we want to access the copy paste manager.
     nsCOMPtr<nsPIDOMWindowOuter> window = GetFocusedDOMWindowInOurWindow();
     nsCOMPtr<nsIDocument> retargetEventDoc =
       window ? window->GetExtantDoc() : nullptr;
--- a/layout/generic/test/test_bug470212.html
+++ b/layout/generic/test/test_bug470212.html
@@ -22,17 +22,17 @@ function doShiftDrag(){
     var wu = SpecialPowers.DOMWindowUtils;
     var canvas = document.getElementById("dragSource");
     var canvasRect = canvas.getBoundingClientRect();
 
     // Drag canvas element starts with a mouse down event, combine with shift
     // key, follows by two mouse move events.
 
     // Press on left-top corner of the canvas element.
-    wu.sendMouseEvent('mousedown',  canvasRect.left, canvasRect.top, 0, 1, 4);
+    wu.sendMouseEvent('mousedown',  canvasRect.left + 1, canvasRect.top + 1, 0, 1, 4);
     // Move to the center of this cavas element.
     wu.sendMouseEvent('mousemove',  canvasRect.left + (canvasRect.width / 2),
                       canvasRect.top + (canvasRect.height / 2), 0, 0, 4);
     // move out of cavas's region.
     wu.sendMouseEvent('mousemove',  canvasRect.left + (canvasRect.width / 2),
                       canvasRect.bottom + 10, 0, 0, 4);
 
     is(window.getSelection().rangeCount, 0, "rangeCount should be 0");
--- a/mobile/android/components/extensions/test/mochitest/test_ext_activeTab_permission.html
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_activeTab_permission.html
@@ -310,17 +310,17 @@ add_task(async function test_activeTab_p
 
   const chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
   const BrowserApp = chromeWin.BrowserApp;
 
   const popupTab = BrowserApp.selectedTab;
   const popupTabId = popupTab.id;
 
   let onceTabClosed = new Promise(resolve => {
-    BrowserApp.deck.addEventListener("TabClose", resolve, {once: true});
+    BrowserApp.deck.addEventListener("TabClose", () => setTimeout(resolve, 0), {once: true});
   });
 
   // Switch to the parent tab of the popup tab.
   // (which should make the extension popup tab to be closed automatically)
   BrowserApp.selectTab(BrowserApp.getTabForId(popupTab.parentId));
 
   info("Wait for the extension popup tab to be closed once the parent tab has been selected");
 
@@ -439,17 +439,17 @@ add_task(async function test_activeTab_b
 
   const chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
   const BrowserApp = chromeWin.BrowserApp;
 
   const popupTab = BrowserApp.selectedTab;
   const popupTabId = popupTab.id;
 
   let onceTabClosed = new Promise(resolve => {
-    BrowserApp.deck.addEventListener("TabClose", resolve, {once: true});
+    BrowserApp.deck.addEventListener("TabClose", () => setTimeout(resolve, 0), {once: true});
   });
 
   // Switch to the parent tab of the popup tab.
   // (which should make the extension popup tab to be closed automatically)
   BrowserApp.selectTab(BrowserApp.getTabForId(popupTab.parentId));
 
   info("Wait for the extension popup tab to be closed once the parent tab has been selected");
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoDisplay.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/GeckoDisplay.java
@@ -40,19 +40,17 @@ public class GeckoDisplay {
      * valid while pausing drawing.
      */
     public void surfaceDestroyed() {
         mSession.onSurfaceDestroyed();
     }
 
     /**
      * Optional callback. The display's coordinates on the screen has changed. Must be
-     * called on the application main thread. Together with the transformation matrix, the
-     * screen origin determines how a point on the display maps to a point on the screen.
+     * called on the application main thread.
      *
      * @param left The X coordinate of the display on the screen, in screen pixels.
      * @param top The Y coordinate of the display on the screen, in screen pixels.
-     * @see #transformationMatrixChanged(Matrix)
      */
     public void screenOriginChanged(final int left, final int top) {
         mSession.onScreenOriginChanged(left, top);
     }
 }
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -112,21 +112,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
       (mSecurityFlags & nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL);
     mSecurityFlags &= ~nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
 
   if (aLoadingContext) {
     // Ensure that all network requests for a window client have the ClientInfo
     // properly set.
     // TODO: The ClientInfo is not set properly for worker initiated requests yet.
-    nsCOMPtr<nsPIDOMWindowInner> contextInner =
-      aLoadingContext->OwnerDoc()->GetInnerWindow();
-    if (contextInner) {
-      mClientInfo = contextInner->GetClientInfo();
-    }
+    mClientInfo = aLoadingContext->OwnerDoc()->GetClientInfo();
 
     nsCOMPtr<nsPIDOMWindowOuter> contextOuter = aLoadingContext->OwnerDoc()->GetWindow();
     if (contextOuter) {
       ComputeIsThirdPartyContext(contextOuter);
       mOuterWindowID = contextOuter->WindowID();
       nsCOMPtr<nsPIDOMWindowOuter> parent = contextOuter->GetScriptableParent();
       mParentOuterWindowID = parent ? parent->WindowID() : mOuterWindowID;
       mTopOuterWindowID = FindTopOuterWindowID(contextOuter);
--- a/netwerk/base/TCPFastOpenLayer.cpp
+++ b/netwerk/base/TCPFastOpenLayer.cpp
@@ -390,16 +390,17 @@ TCPFastOpenFinish(PRFileDesc *fd, PRErro
     } else {
       result = PR_GetError();
     }
     if (tfoFd->lower->methods->sendto == (PRSendtoFN)tfoFd->lower->methods->reserved_fn_0) {
         // sendto is not implemented, it is equal to _PR_InvalidInt!
         // We will disable Fast Open.
         SOCKET_LOG(("TCPFastOpenFinish - sendto not implemented.\n"));
         fastOpenNotSupported = true;
+        tfoStatus = TFO_DISABLED;
     }
   } else {
     // We have some data ready in the buffer we will send it with the syn
     // packet.
     PRInt32 rv = (tfoFd->lower->methods->sendto)(tfoFd->lower,
                                                  secret->mFirstPacketBuf,
                                                  secret->mFirstPacketBufLen,
                                                  0, //flags
@@ -427,16 +428,17 @@ TCPFastOpenFinish(PRFileDesc *fd, PRErro
         rv = (tfoFd->lower->methods->connect)(tfoFd->lower, &secret->mAddr,
                                               PR_INTERVAL_NO_WAIT);
 
         if (rv == PR_SUCCESS) {
           result = PR_IS_CONNECTED_ERROR;
         } else {
           result = PR_GetError();
         }
+        tfoStatus = TFO_DISABLED;
       } else {
         tfoStatus = TFO_TRIED;
       }
     }
   }
 
   if (result == PR_IN_PROGRESS_ERROR) {
     secret->mState = TCPFastOpenSecret::WAITING_FOR_CONNECTCONTINUE;
--- a/netwerk/base/TCPFastOpenLayer.h
+++ b/netwerk/base/TCPFastOpenLayer.h
@@ -15,27 +15,61 @@ namespace net {
 /**
  * This layer must be placed just above PR-tcp socket, i.e. it must be under
  * nss layer.
  * At the beginning of TCPFastOpenLayer.cpp there is explanation what this
  * layer do.
  **/
 
 typedef enum {
-  TFO_NOT_TRIED,
-  TFO_TRIED,
-  TFO_DATA_SENT,
+  TFO_NOT_SET, // This is only as a control.
+               // A connection not using TFO will have the TFO state set upon
+               // connection creation (in nsHalfOpenSocket::SetupConn).
+               // A connection using TFO will have the TFO state set after
+               // the connection is established or canceled.
+  TFO_UNKNOWN, // This is before the primary socket is built, i.e. before
+               // TCPFastOpenFinish is called.
+  TFO_DISABLED, // tfo is disabled because of a tfo error on a previous
+                // connection to the host (i.e. !mEnt->mUseFastOpen).
+                // If TFO is not supported by the OS, it is disabled by
+                // the pref or too many consecutive errors occurred, this value
+                // is not reported. This is set before StartFastOpen is called.
+  TFO_DISABLED_CONNECT, // Connection is using CONNECT. This is set before
+                        // StartFastOpen is called.
+  // The following 3 are set just after TCPFastOpenFinish.
+  TFO_NOT_TRIED, // For some reason TCPFastOpenLayer does not have any data to
+                 // send with the syn packet. This should never happen.
+  TFO_TRIED, // TCP has sent a TFO cookie request.
+  TFO_DATA_SENT, // On Linux, TCP has send data as well. (On Linux we do not
+                 // know whether data has been accepted).
+                 // On Windows, TCP has send data or only a TFO cookie request
+                 // and the data or TFO cookie has been accepted by the server.
+  // The following value is only used on windows and is set after
+  // PR_ConnectContinue. That is the point when we know if TFO data was been
+  // accepted.
+  TFO_DATA_COOKIE_NOT_ACCEPTED, // This is only on Windows. TFO data or TFO
+                                // cookie request has not been accepted.
+  // The following 3 are set during socket error recover
+  // (nsSocketTransport::RecoverFromError).
   TFO_FAILED_CONNECTION_REFUSED,
   TFO_FAILED_NET_TIMEOUT,
   TFO_FAILED_UNKNOW_ERROR,
-  TFO_FAILED_BACKUP_CONNECTION,
+  // The following 4 are set when backup connection finishes before the primary
+  // connection.
+  TFO_FAILED_BACKUP_CONNECTION_TFO_NOT_TRIED,
+  TFO_FAILED_BACKUP_CONNECTION_TFO_TRIED,
+  TFO_FAILED_BACKUP_CONNECTION_TFO_DATA_SENT,
+  TFO_FAILED_BACKUP_CONNECTION_TFO_DATA_COOKIE_NOT_ACCEPTED,
+  // The following 4 are set when the recovery connection fails as well.
   TFO_FAILED_CONNECTION_REFUSED_NO_TFO_FAILED_TOO,
-  TFO_FAILED_NET_TIMEOUT__NO_TFO_FAILED_TOO,
+  TFO_FAILED_NET_TIMEOUT_NO_TFO_FAILED_TOO,
   TFO_FAILED_UNKNOW_ERROR_NO_TFO_FAILED_TOO,
   TFO_FAILED_BACKUP_CONNECTION_NO_TFO_FAILED_TOO,
+  TFO_BACKUP_CONN, // This is a backup conn, for a halfOpenSock that was used
+                   // TFO.
   TFO_FAILED,
   TFO_HTTP // TFO is disabled for non-secure connections.
 } TFOResult;
 
 nsresult AttachTCPFastOpenIOLayer(PRFileDesc *fd);
 
 // Get the result of TCP Fast Open.
 void TCPFastOpenFinish(PRFileDesc *fd, PRErrorCode &err,
--- a/netwerk/base/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -794,17 +794,17 @@ nsSocketTransport::nsSocketTransport()
     , mOutput(this)
     , mQoSBits(0x00)
     , mKeepaliveEnabled(false)
     , mKeepaliveIdleTimeS(-1)
     , mKeepaliveRetryIntervalS(-1)
     , mKeepaliveProbeCount(-1)
     , mFastOpenCallback(nullptr)
     , mFastOpenLayerHasBufferedData(false)
-    , mFastOpenStatus(TFO_NOT_TRIED)
+    , mFastOpenStatus(TFO_NOT_SET)
     , mFirstRetryError(NS_OK)
     , mDoNotRetryToConnect(false)
 {
     SOCKET_LOG(("creating nsSocketTransport @%p\n", this));
 
     mTimeouts[TIMEOUT_CONNECT]    = UINT16_MAX; // no timeout
     mTimeouts[TIMEOUT_READ_WRITE] = UINT16_MAX; // no timeout
 }
@@ -2209,19 +2209,19 @@ nsSocketTransport::OnSocketReady(PRFileD
 #endif
 
         if (mFDFastOpenInProgress && mFastOpenCallback &&
             (mFastOpenStatus == TFO_DATA_SENT)) {
             PROsfd osfd = PR_FileDesc2NativeHandle(fd);
             BOOL option = 0;
             int len = sizeof(option);
             PRInt32 rv = getsockopt((SOCKET)osfd, IPPROTO_TCP, TCP_FASTOPEN, (char*)&option, &len);
-            if ((rv != 0) && !option) {
+            if (!rv && !option) {
                 // On error, I will let the normal necko paths pickup the error.
-                mFastOpenCallback->SetFastOpenStatus(TFO_NOT_TRIED);
+                mFastOpenCallback->SetFastOpenStatus(TFO_DATA_COOKIE_NOT_ACCEPTED);
             }
         }
 #endif
 
         if (gSocketTransportService->IsTelemetryEnabledAndNotSleepPhase() &&
             connectStarted) {
             SendPRBlockingTelemetry(connectStarted,
                 Telemetry::PRCONNECTCONTINUE_BLOCKING_TIME_NORMAL,
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1095,16 +1095,29 @@ HttpChannelChild::OnStopRequest(const ns
     // (although we really shouldn't receive any msgs after OnStop),
     // so make sure this goes out of scope before then.
     AutoEventEnqueuer ensureSerialDispatch(mEventQ);
 
     DoOnStopRequest(this, channelStatus, mListenerContext);
     // DoOnStopRequest() calls ReleaseListeners()
   }
 
+  // If unknownDecoder is involved and the received content is short we will
+  // know whether we need to divert to parent only after OnStopRequest of the
+  // listeners chain is called in DoOnStopRequest. At that moment
+  // unknownDecoder will call OnStartRequest of the real listeners of the
+  // channel including the OnStopRequest of UrlLoader which decides whether we
+  // need to divert to parent.
+  // If we are diverting to parent we should not do a cleanup.
+  if (mDivertingToParent) {
+    LOG(("HttpChannelChild::OnStopRequest  - We are diverting to parent, "
+         "postpone cleaning up."));
+    return;
+  }
+
   CleanupBackgroundChannel();
 
   // If there is a possibility we might want to write alt data to the cache
   // entry, we keep the channel alive. We still send the DocumentChannelCleanup
   // message but request the cache entry to be kept by the parent.
   // If the channel has failed, the cache entry is in a non-writtable state and
   // we want to release it to not block following consumers.
   if (NS_SUCCEEDED(channelStatus) && !mPreferredCachedAltDataType.IsEmpty()) {
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -82,17 +82,17 @@ nsHttpConnection::nsHttpConnection()
     , mTCPKeepaliveConfig(kTCPKeepaliveDisabled)
     , mForceSendPending(false)
     , m0RTTChecked(false)
     , mWaitingFor0RTTResponse(false)
     , mContentBytesWritten0RTT(0)
     , mEarlyDataNegotiated(false)
     , mDid0RTTSpdy(false)
     , mFastOpen(false)
-    , mFastOpenStatus(TFO_NOT_TRIED)
+    , mFastOpenStatus(TFO_NOT_SET)
     , mForceSendDuringFastOpenPending(false)
     , mReceivedSocketWouldBlockDuringFastOpen(false)
 {
     LOG(("Creating nsHttpConnection @%p\n", this));
 
     // the default timeout is for when this connection has not yet processed a
     // transaction
     static const PRIntervalTime k5Sec = PR_SecondsToInterval(5);
@@ -122,22 +122,22 @@ nsHttpConnection::~nsHttpConnection()
     }
     if (mForceSendTimer) {
         mForceSendTimer->Cancel();
         mForceSendTimer = nullptr;
     }
 
     if ((mFastOpenStatus != TFO_FAILED) &&
         (mFastOpenStatus != TFO_HTTP) &&
-        ((mFastOpenStatus != TFO_NOT_TRIED) ||
+        ((mFastOpenStatus != TFO_DISABLED) ||
          gHttpHandler->UseFastOpen())) {
         // TFO_FAILED will be reported in the replacement connection with more
         // details.
         // Otherwise report only if TFO is enabled and supported.
-        Telemetry::Accumulate(Telemetry::TCP_FAST_OPEN_2, mFastOpenStatus);
+        Telemetry::Accumulate(Telemetry::TCP_FAST_OPEN_3, mFastOpenStatus);
     }
 }
 
 nsresult
 nsHttpConnection::Init(nsHttpConnectionInfo *info,
                        uint16_t maxHangTime,
                        nsISocketTransport *transport,
                        nsIAsyncInputStream *instream,
@@ -2441,21 +2441,30 @@ nsHttpConnection::SetFastOpen(bool aFast
         mExperienced = true;
     }
 }
 
 void
 nsHttpConnection::SetFastOpenStatus(uint8_t tfoStatus) {
     mFastOpenStatus = tfoStatus;
     if ((mFastOpenStatus >= TFO_FAILED_CONNECTION_REFUSED) &&
+        (mFastOpenStatus <= TFO_FAILED_BACKUP_CONNECTION_TFO_DATA_COOKIE_NOT_ACCEPTED) &&
         mSocketTransport) {
         nsresult firstRetryError;
         if (NS_SUCCEEDED(mSocketTransport->GetFirstRetryError(&firstRetryError)) &&
             (NS_FAILED(firstRetryError))) {
-            mFastOpenStatus = tfoStatus + 4; 
+            if ((mFastOpenStatus >= TFO_FAILED_BACKUP_CONNECTION_TFO_NOT_TRIED) &&
+                (mFastOpenStatus <= TFO_FAILED_BACKUP_CONNECTION_TFO_DATA_COOKIE_NOT_ACCEPTED)) {
+                mFastOpenStatus = TFO_FAILED_BACKUP_CONNECTION_NO_TFO_FAILED_TOO;
+            } else {
+                // We add +7 to tranform TFO_FAILED_CONNECTION_REFUSED into
+                // TFO_FAILED_CONNECTION_REFUSED_NO_TFO_FAILED_TOO, etc.
+                // If the list in TCPFastOpenLayer.h changes please addapt +7.
+                mFastOpenStatus = tfoStatus + 7;
+            }
         }
     }
 }
 
 void
 nsHttpConnection::BootstrapTimings(TimingStruct times)
 {
     mBootstrappedTimings = times;
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -3850,16 +3850,17 @@ nsHalfOpenSocket::nsHalfOpenSocket(nsCon
     , mDispatchedMTransaction(false)
     , mCaps(caps)
     , mSpeculative(speculative)
     , mIsFromPredictor(isFromPredictor)
     , mAllow1918(true)
     , mHasConnected(false)
     , mPrimaryConnectedOK(false)
     , mBackupConnectedOK(false)
+    , mBackupConnStatsSet(false)
     , mFreeToUse(true)
     , mPrimaryStreamStatus(NS_OK)
     , mFastOpenInProgress(false)
     , mEnt(ent)
 {
     MOZ_ASSERT(ent && trans, "constructor with null arguments");
     LOG(("Creating nsHalfOpenSocket [this=%p trans=%p ent=%s key=%s]\n",
          this, trans, ent->mConnInfo->Origin(), ent->mConnInfo->HashKey().get()));
@@ -3870,17 +3871,17 @@ nsHalfOpenSocket::nsHalfOpenSocket(nsCon
 
         if (isFromPredictor) {
           Telemetry::AutoCounter<Telemetry::PREDICTOR_TOTAL_PRECONNECTS_CREATED> totalPreconnectsCreated;
           ++totalPreconnectsCreated;
         }
     }
 
     if (mEnt->mConnInfo->FirstHopSSL()) {
-      mFastOpenStatus = TFO_NOT_TRIED;
+      mFastOpenStatus = TFO_UNKNOWN;
     } else {
       mFastOpenStatus = TFO_HTTP;
     }
     MOZ_ASSERT(mEnt);
 }
 
 nsHttpConnectionMgr::nsHalfOpenSocket::~nsHalfOpenSocket()
 {
@@ -3980,18 +3981,22 @@ nsHalfOpenSocket::SetupStreams(nsISocket
              (isBackup && gHttpHandler->FastFallbackToIPv4())) {
         tmpFlags |= nsISocketTransport::DISABLE_IPV6;
     }
 
     if (!Allow1918()) {
         tmpFlags |= nsISocketTransport::DISABLE_RFC1918;
     }
 
-    if (!isBackup && mEnt->mUseFastOpen) {
-        socketTransport->SetFastOpenCallback(this);
+    if (!isBackup) {
+        if (mEnt->mUseFastOpen) {
+            socketTransport->SetFastOpenCallback(this);
+        } else {
+            mFastOpenStatus = TFO_DISABLED;
+        }
     }
 
     socketTransport->SetConnectionFlags(tmpFlags);
     socketTransport->SetTlsFlags(ci->GetTlsFlags());
 
     const OriginAttributes& originAttributes = mEnt->mConnInfo->GetOriginAttributes();
     if (originAttributes != OriginAttributes()) {
         socketTransport->SetOriginAttributes(originAttributes);
@@ -4305,19 +4310,40 @@ nsHalfOpenSocket::OnOutputStreamReady(ns
         }
         if (mEnt->mUseFastOpen) {
             gHttpHandler->IncrementFastOpenConsecutiveFailureCounter();
             mEnt->mUseFastOpen = false;
         }
 
         mFastOpenInProgress = false;
         mConnectionNegotiatingFastOpen = nullptr;
-        mFastOpenStatus = TFO_FAILED_BACKUP_CONNECTION;
-    }
-
+        if (mFastOpenStatus == TFO_NOT_TRIED) {
+            mFastOpenStatus = TFO_FAILED_BACKUP_CONNECTION_TFO_NOT_TRIED;
+        } else if (mFastOpenStatus == TFO_TRIED) {
+            mFastOpenStatus = TFO_FAILED_BACKUP_CONNECTION_TFO_TRIED;
+        } else if (mFastOpenStatus == TFO_DATA_SENT) {
+            mFastOpenStatus = TFO_FAILED_BACKUP_CONNECTION_TFO_DATA_SENT;
+        } else {
+            // This is TFO_DATA_COOKIE_NOT_ACCEPTED (I think this cannot
+            // happened, because the primary connection will be already
+            // connected or in recovery and mFastOpenInProgress==false).
+            mFastOpenStatus = TFO_FAILED_BACKUP_CONNECTION_TFO_DATA_COOKIE_NOT_ACCEPTED;
+        }
+    }
+
+    if (((mFastOpenStatus == TFO_DISABLED) ||
+        (mFastOpenStatus == TFO_HTTP)) && !mBackupConnStatsSet) {
+        // Collect telemetry for backup connection being faster than primary
+        // connection. We want to collect this telemetry only for cases where
+        // TFO is not used.
+        mBackupConnStatsSet = true;
+        Telemetry::ScalarSet(Telemetry::ScalarID::NETWORK_HTTP_BACKUP_CONN_WON,
+                             (out == mBackupStreamOut));
+    }
+        
     nsresult rv =  SetupConn(out, false);
     if (mEnt) {
         mEnt->mDoNotDestroy = false;
     }
     return rv;
 }
 
 bool
@@ -4327,53 +4353,42 @@ nsHalfOpenSocket::FastOpenEnabled()
     LOG(("nsHalfOpenSocket::FastOpenEnabled [this=%p]\n", this));
 
     MOZ_ASSERT(mEnt);
 
     if (!mEnt) {
         return false;
     }
 
+    MOZ_ASSERT(mEnt->mConnInfo->FirstHopSSL());
+
     // If mEnt is present this HalfOpen must be in the mHalfOpens,
     // but we want to be sure!!!
     if (!mEnt->mHalfOpens.Contains(this)) {
         return false;
     }
 
     if (!gHttpHandler->UseFastOpen()) {
         // fast open was turned off.
         LOG(("nsHalfOpenSocket::FastEnabled - fast open was turned off.\n"));
         mEnt->mUseFastOpen = false;
+        mFastOpenStatus = TFO_DISABLED;
         return false;
     }
     // We can use FastOpen if we have a transaction or if it is ssl
     // connection. For ssl we will use a null transaction to drive the SSL
     // handshake to completion if there is not a pending transaction. Afterwards
     // the connection will be 100% ready for the next transaction to use it.
     // Make an exception for SSL tunneled HTTP proxy as the NullHttpTransaction
     // does not know how to drive Connect.
-    RefPtr<PendingTransactionInfo> info = FindTransactionHelper(false);
-
-    if ((!info) &&
-        (!mEnt->mConnInfo->FirstHopSSL() || mEnt->mConnInfo->UsingConnect())) {
-        LOG(("nsHalfOpenSocket::FastOpenEnabled - It is a connection without "
-             "transaction and first hop is not ssl.\n"));
+    if (mEnt->mConnInfo->UsingConnect()) {
+        LOG(("nsHalfOpenSocket::FastOpenEnabled - It is using Connect."));
+        mFastOpenStatus = TFO_DISABLED_CONNECT;
         return false;
     }
-
-    if ((info) && !mEnt->mConnInfo->FirstHopSSL()) {
-        // The following function call will check whether is possible to send
-        // data during fast open
-        if (!info->mTransaction->CanDo0RTT()) {
-            LOG(("nsHalfOpenSocket::FastOpenEnabled - it is not safe to restart "
-                 "transaction.\n"));
-            return false;
-        }
-    }
-
     return true;
 }
 
 nsresult
 nsHttpConnectionMgr::
 nsHalfOpenSocket::StartFastOpen()
 {
     MOZ_ASSERT(mStreamOut);
@@ -4551,17 +4566,23 @@ nsHalfOpenSocket::SetFastOpenConnected(n
                 mEnt->RecordIPFamilyPreference(peeraddr.raw.family);
             }
             gHttpHandler->ResetFastOpenConsecutiveFailureCounter();
         }
         mSocketTransport = nullptr;
         mStreamOut = nullptr;
         mStreamIn = nullptr;
 
-        Abandon();
+        // If backup transport has already started put this HalfOpen back to
+        // mEnt list.
+        if (mBackupTransport) {
+            mFastOpenStatus = TFO_BACKUP_CONN;
+            mEnt->mHalfOpens.AppendElement(this);
+            gHttpHandler->ConnMgr()->mNumHalfOpenConns++;
+        }
     }
 
     mFastOpenInProgress = false;
     mConnectionNegotiatingFastOpen = nullptr;
     if (mEnt) {
         mEnt->mDoNotDestroy = false;
         MOZ_ASSERT(mEnt->mHalfOpens.Contains(this));
     } else {
@@ -4571,16 +4592,17 @@ nsHalfOpenSocket::SetFastOpenConnected(n
     }
 }
 
 void
 nsHttpConnectionMgr::
 nsHalfOpenSocket::SetFastOpenStatus(uint8_t tfoStatus)
 {
     MOZ_ASSERT(mFastOpenInProgress);
+    mFastOpenStatus = tfoStatus;
     mConnectionNegotiatingFastOpen->SetFastOpenStatus(tfoStatus);
     mConnectionNegotiatingFastOpen->Transaction()->SetFastOpenStatus(tfoStatus);
 }
 
 void
 nsHttpConnectionMgr::
 nsHalfOpenSocket::CancelFastOpenConnection()
 {
@@ -4799,16 +4821,20 @@ nsHalfOpenSocket::SetupConn(nsIAsyncOutp
         int32_t idx = mEnt->mActiveConns.IndexOf(conn);
         if (NS_SUCCEEDED(rv) && (idx != -1)) {
             mConnectionNegotiatingFastOpen = conn;
         } else {
             conn->SetFastOpen(false);
         }
     } else {
         conn->SetFastOpenStatus(mFastOpenStatus);
+        mFastOpenStatus = TFO_BACKUP_CONN; // Set this to TFO_BACKUP_CONN so
+                                           // that if a backup connection is
+                                           // established we do not report
+                                           // values twice.
     }
 
     // If this halfOpenConn was speculative, but at the ende the conn got a
     // non-null transaction than this halfOpen is not speculative anymore!
     if (conn->Transaction() && !conn->Transaction()->IsNullTransaction()) {
         Claim();
     }
 
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -471,16 +471,17 @@ private:
         TimeStamp             mBackupSynStarted;
 
         // mHasConnected tracks whether one of the sockets has completed the
         // connection process. It may have completed unsuccessfully.
         bool                           mHasConnected;
 
         bool                           mPrimaryConnectedOK;
         bool                           mBackupConnectedOK;
+        bool                           mBackupConnStatsSet;
 
         // A nsHalfOpenSocket can be made for a concrete non-null transaction,
         // but the transaction can be dispatch to another connection. In that
         // case we can free this transaction to be claimed by other
         // transactions.
         bool                           mFreeToUse;
         nsresult                       mPrimaryStreamStatus;
 
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -73,16 +73,17 @@
 #include "nsNSSComponent.h"
 
 #if defined(XP_UNIX)
 #include <sys/utsname.h>
 #endif
 
 #if defined(XP_WIN)
 #include <windows.h>
+#include "mozilla/WindowsVersion.h"
 #endif
 
 #if defined(XP_MACOSX)
 #include <CoreServices/CoreServices.h>
 #include "nsCocoaFeatures.h"
 #endif
 
 #ifdef MOZ_TASK_TRACER
@@ -303,16 +304,18 @@ nsHttpHandler::nsHttpHandler()
 }
 
 void
 nsHttpHandler::SetFastOpenOSSupport()
 {
     mFastOpenSupported = false;
 #if !defined(XP_WIN) && !defined(XP_LINUX) && !defined(ANDROID) && !defined(HAS_CONNECTX)
     return;
+#elif defined(XP_WIN)
+    mFastOpenSupported = IsWindows10BuildOrLater(16299);
 #else
 
     nsAutoCString version;
     nsresult rv;
 #ifdef ANDROID
     nsCOMPtr<nsIPropertyBag2> infoService =
         do_GetService("@mozilla.org/system-info;1");
     MOZ_ASSERT(infoService, "Could not find a system info service");
@@ -327,19 +330,17 @@ nsHttpHandler::SetFastOpenOSSupport()
         rv = NS_ERROR_FAILURE;
     }
 #endif
 
     LOG(("nsHttpHandler::SetFastOpenOSSupport version %s", version.get()));
 
     if (NS_SUCCEEDED(rv)) {
         // set min version minus 1.
-#ifdef XP_WIN
-        int min_version[] = {10, 0};
-#elif XP_MACOSX
+#if XP_MACOSX
         int min_version[] = {15, 0};
 #elif ANDROID
         int min_version[] = {4, 4};
 #elif XP_LINUX
         int min_version[] = {3, 6};
 #endif
         int inx = 0;
         nsCCharSeparatedTokenizer tokenizer(version, '.');
@@ -361,26 +362,16 @@ nsHttpHandler::SetFastOpenOSSupport()
                 mFastOpenSupported = true;
             } else if (ver < min_version[inx]) {
                 break;
             }
             inx++;
         }
     }
 #endif
-
-#ifdef XP_WIN
-  if (mFastOpenSupported) {
-    // We have some problems with lavasoft software and tcp fast open.
-    if (GetModuleHandleW(L"pmls64.dll") || GetModuleHandleW(L"rlls64.dll")) {
-      mFastOpenSupported = false;
-    }
-  }
-#endif
-
     LOG(("nsHttpHandler::SetFastOpenOSSupport %s supported.\n",
          mFastOpenSupported ? "" : "not"));
 }
 
 void
 nsHttpHandler::EnsureUAOverridesInit()
 {
     MOZ_ASSERT(XRE_IsParentProcess());
--- a/netwerk/test/unit/test_bug1355539_http1.js
+++ b/netwerk/test/unit/test_bug1355539_http1.js
@@ -22,16 +22,18 @@ Cu.import("resource://gre/modules/NetUti
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var server = new HttpServer();
 server.start(-1);
 var baseURL = "http://localhost:" + server.identity.primaryPort + "/";
 var maxConnections = 0;
 var debug = false;
+var dummyResponseQueue = new Array();
+var responseQueue = new Array();
 
 function log(msg) {
   if (!debug) {
     return;
   }
 
   if (msg) {
     dump("TEST INFO | " + msg + "\n");
@@ -43,35 +45,35 @@ function make_channel(url) {
   request.QueryInterface(Ci.nsIHttpChannel);
   return request;
 }
 
 function serverStopListener() {
   server.stop();
 }
 
-function createHttpRequest(requestId, priority, isBlocking) {
+function createHttpRequest(requestId, priority, isBlocking, callback) {
   let uri = baseURL;
   var chan = make_channel(uri);
-  var listner = new HttpResponseListener(requestId);
+  var listner = new HttpResponseListener(requestId, callback);
   chan.setRequestHeader("X-ID", requestId, false);
   chan.setRequestHeader("Cache-control", "no-store", false);
   chan.QueryInterface(Ci.nsISupportsPriority).priority = priority;
   if (isBlocking) {
     var cos = chan.QueryInterface(Ci.nsIClassOfService);
     cos.addClassFlags(Ci.nsIClassOfService.Leader);
   }
   chan.asyncOpen2(listner);
   log("Create http request id=" + requestId);
 }
 
-function setup_dummyHttpRequests() {
+function setup_dummyHttpRequests(callback) {
   log("setup_dummyHttpRequests");
   for (var i = 0; i < maxConnections ; i++) {
-    createHttpRequest(i, i, false);
+    createHttpRequest(i, i, false, callback);
     do_test_pending();
   }
 }
 
 var transactionQueue = [
   {requestId: 101, priority: Ci.nsISupportsPriority.PRIORITY_HIGH, isBlocking: true},
   {requestId: 102, priority: Ci.nsISupportsPriority.PRIORITY_NORMAL, isBlocking: true},
   {requestId: 103, priority: Ci.nsISupportsPriority.PRIORITY_LOW, isBlocking: true},
@@ -94,75 +96,91 @@ function setup_HttpRequests() {
 function check_response_id(responses)
 {
   for (var i = 0; i < responses.length; i++) {
     var id = responses[i].getHeader("X-ID");
     do_check_eq(id, transactionQueue[i].requestId);
   }
 }
 
-function HttpResponseListener(id)
+function HttpResponseListener(id, onStopCallback)
 {
   this.id = id
+  this.stopCallback = onStopCallback;
 };
 
 HttpResponseListener.prototype =
 {
   onStartRequest: function (request, ctx) {
   },
 
   onDataAvailable: function (request, ctx, stream, off, cnt) {
   },
 
   onStopRequest: function (request, ctx, status) {
     log("STOP id=" + this.id);
     do_test_finished();
+    if (this.stopCallback) {
+      this.stopCallback();
+    }
   }
 };
 
-var responseQueue = new Array();
 function setup_http_server()
 {
   log("setup_http_server");
   var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
   maxConnections = prefs.getIntPref("network.http.max-persistent-connections-per-server");
 
   var allDummyHttpRequestReceived = false;
   // Start server; will be stopped at test cleanup time.
   server.registerPathHandler('/', function(metadata, response)
   {
     var id = metadata.getHeader("X-ID");
     log("Server recived the response id=" + id);
 
     response.processAsync();
     response.setHeader("X-ID", id);
-    responseQueue.push(response);
 
-    if (responseQueue.length == maxConnections && !allDummyHttpRequestReceived) {
+    if (!allDummyHttpRequestReceived) {
+      dummyResponseQueue.push(response);
+    } else {
+      responseQueue.push(response);
+    }
+
+    if (dummyResponseQueue.length == maxConnections) {
       log("received all dummy http requets");
       allDummyHttpRequestReceived = true;
       setup_HttpRequests();
-      processResponses();
+      processDummyResponse();
     } else if (responseQueue.length == maxConnections) {
       log("received all http requets");
       check_response_id(responseQueue);
       processResponses();
     }
 
   });
 
   do_register_cleanup(function() {
     server.stop(serverStopListener);
   });
 
 }
 
+function processDummyResponse() {
+  if (!dummyResponseQueue.length) {
+    return;
+  }
+  var resposne = dummyResponseQueue.pop();
+  resposne.finish();
+}
+
 function processResponses() {
   while (responseQueue.length) {
     var resposne = responseQueue.pop();
     resposne.finish();
   }
 }
 
 function run_test() {
   setup_http_server();
-  setup_dummyHttpRequests();
+  setup_dummyHttpRequests(processDummyResponse);
 }
--- a/old-configure.in
+++ b/old-configure.in
@@ -237,22 +237,28 @@ case "$target" in
 
         if test -n "$WIN32_REDIST_DIR"; then
           if test ! -d "$WIN32_REDIST_DIR"; then
             AC_MSG_ERROR([Invalid Win32 Redist directory: ${WIN32_REDIST_DIR}])
           fi
           WIN32_REDIST_DIR=`cd "$WIN32_REDIST_DIR" && pwd -W`
         fi
 
-        # Check linker version
-        _LD_FULL_VERSION=`"${LINK}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"`
-        _LD_MAJOR_VERSION=`echo ${_LD_FULL_VERSION} | $AWK -F\. '{ print $1 }'`
-        if test "$_LD_MAJOR_VERSION" != "$_CC_SUITE"; then
-            AC_MSG_ERROR([The linker major version, $_LD_FULL_VERSION,  does not match the compiler suite version, $_CC_SUITE.])
-        fi
+        # Check linker version, except in lld builds
+        case "$LINKER" in
+        *lld*)
+            ;;
+        *)
+            _LD_FULL_VERSION=`"${LINKER}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"`
+            _LD_MAJOR_VERSION=`echo ${_LD_FULL_VERSION} | $AWK -F\. '{ print $1 }'`
+            if test "$_LD_MAJOR_VERSION" != "$_CC_SUITE"; then
+                AC_MSG_ERROR([The linker major version, $_LD_FULL_VERSION,  does not match the compiler suite version, $_CC_SUITE.])
+            fi
+            ;;
+        esac
 
         INCREMENTAL_LINKER=1
 
         # Set midl environment
         case "$target" in
         i*86-*)
             MIDL_FLAGS="${MIDL_FLAGS} -env win32"
             ;;
@@ -896,18 +902,18 @@ case "$target" in
             AS="$(basename "$AS_BIN")"
         fi
         AR='lib'
         AR_FLAGS='-NOLOGO -OUT:$@'
         AR_EXTRACT=
         RANLIB='echo not_ranlib'
         STRIP='echo not_strip'
         PKG_SKIP_STRIP=1
-        MKSHLIB='$(LINK) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
-        MKCSHLIB='$(LINK) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
+        MKSHLIB='$(LINKER) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
+        MKCSHLIB='$(LINKER) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
         WIN32_SUBSYSTEM_VERSION=6.01
         WIN32_CONSOLE_EXE_LDFLAGS=-SUBSYSTEM:CONSOLE,$WIN32_SUBSYSTEM_VERSION
         WIN32_GUI_EXE_LDFLAGS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION
         DSO_LDOPTS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION
         _USE_CPP_INCLUDE_FLAG=1
         _DEFINES_CFLAGS="-FI $_objdir/mozilla-config.h -DMOZILLA_CLIENT"
         _DEFINES_CXXFLAGS="-FI $_objdir/mozilla-config.h -DMOZILLA_CLIENT"
         CFLAGS="$CFLAGS -W3 -Gy -Zc:inline"
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -2165,54 +2165,55 @@ function synthesizeDragOver(aSrcElement,
     aWindow = window;
   }
   if (!aDestWindow) {
     aDestWindow = aWindow;
   }
 
   const obs = _EU_Cc["@mozilla.org/observer-service;1"].getService(_EU_Ci.nsIObserverService);
   const ds = _EU_Cc["@mozilla.org/widget/dragservice;1"].getService(_EU_Ci.nsIDragService);
-  var sess = ds.getCurrentSession();
 
   // This method runs before other callbacks, and acts as a way to inject the
   // initial drag data into the DataTransfer.
   function fillDrag(event) {
+    ds.startDragSession();
+
     if (aDragData) {
       for (var i = 0; i < aDragData.length; i++) {
         var item = aDragData[i];
         for (var j = 0; j < item.length; j++) {
           event.dataTransfer.mozSetDataAt(item[j].type, item[j].data, i);
         }
       }
     }
     event.dataTransfer.dropEffect = aDropEffect || "move";
     event.preventDefault();
   }
 
   function trapDrag(subject, topic) {
     if (topic == "on-datatransfer-available") {
+      var sess = ds.getCurrentSession();
       sess.dataTransfer = _EU_maybeUnwrap(_EU_maybeWrap(subject).mozCloneForEvent("drop"));
       sess.dataTransfer.dropEffect = subject.dropEffect;
+      obs.removeObserver(trapDrag, "on-datatransfer-available");
     }
   }
 
   // need to use real mouse action
-  aWindow.addEventListener("dragstart", fillDrag, true);
+  aWindow.addEventListener("dragstart", fillDrag, { capture: true, once: true });
   obs.addObserver(trapDrag, "on-datatransfer-available");
   synthesizeMouseAtCenter(aSrcElement, { type: "mousedown" }, aWindow);
 
   var rect = aSrcElement.getBoundingClientRect();
   var x = rect.width / 2;
   var y = rect.height / 2;
   synthesizeMouse(aSrcElement, x, y, { type: "mousemove" }, aWindow);
   synthesizeMouse(aSrcElement, x+10, y+10, { type: "mousemove" }, aWindow);
-  aWindow.removeEventListener("dragstart", fillDrag, true);
-  obs.removeObserver(trapDrag, "on-datatransfer-available");
 
-  var dataTransfer = sess.dataTransfer;
+  var dataTransfer = ds.getCurrentSession().dataTransfer;
 
   // The EventStateManager will fire our dragenter event if it needs to.
   var event = createDragEventObject("dragover", aDestElement, aDestWindow,
                                     dataTransfer, aDragEvent);
   var result = sendDragEvent(event, aDestElement, aDestWindow);
 
   return [result, dataTransfer];
 }
@@ -2278,29 +2279,25 @@ function synthesizeDrop(aSrcElement, aDe
 {
   if (!aWindow) {
     aWindow = window;
   }
   if (!aDestWindow) {
     aDestWindow = aWindow;
   }
 
-  var ds = _EU_Cc["@mozilla.org/widget/dragservice;1"]
-           .getService(_EU_Ci.nsIDragService);
-
-  ds.startDragSession();
-
   try {
     var [result, dataTransfer] = synthesizeDragOver(aSrcElement, aDestElement,
                                                     aDragData, aDropEffect,
                                                     aWindow, aDestWindow,
                                                     aDragEvent);
     return synthesizeDropAfterDragOver(result, dataTransfer, aDestElement,
                                        aDestWindow, aDragEvent);
   } finally {
+    var ds = _EU_Cc["@mozilla.org/widget/dragservice;1"].getService(_EU_Ci.nsIDragService);
     ds.endDragSession(true, _parseModifiers(aDragEvent));
   }
 }
 
 var PluginUtils =
 {
   withTestPlugin : function(callback)
   {
--- a/testing/web-platform/meta/css/css-backgrounds/border-image-slice-001.xht.ini
+++ b/testing/web-platform/meta/css/css-backgrounds/border-image-slice-001.xht.ini
@@ -1,3 +1,3 @@
-[border-image-slice-percentage.html]
+[border-image-slice-001.xht]
   type: reftest
   disabled: if (os == "linux") and debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1383061
deleted file mode 100644
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/execorder.html.ini
+++ /dev/null
@@ -1,28 +0,0 @@
-[execorder.html]
-  type: testharness
-  expected:
-    if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5"): OK
-  [Unordered module script execution (parsed, unordered #1)]
-    expected:
-      if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5"): PASS
-
-  [Unordered module script execution (parsed, unordered #2)]
-    expected:
-      if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5"): PASS
-
-  [Unordered module script execution (dynamic, unordered #1)]
-    expected:
-      if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5"): PASS
-
-  [Unordered module script execution (dynamic, unordered #2)]
-    expected:
-      if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5"): PASS
-
-  [Interlaced module/non-module script execution (parsed, async-ordered)]
-    expected:
-      if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5"): PASS
-
-  [Interlaced module/non-module script execution (dynamic, async-ordered)]
-    expected:
-      if not debug and not e10s and (os == "mac") and (version == "OS X 10.10.5"): PASS
-
deleted file mode 100644
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[instantiation-error-1.html]
-  [Test that missing exports lead to SyntaxError events on window and load events on script, and that exceptions are remembered]
-    expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[instantiation-error-2.html]
-  [Test that missing exports lead to SyntaxError events on window and load events on script, and that exceptions are remembered]
-    expected: FAIL
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html.ini
+++ b/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html.ini
@@ -1,3 +1,2 @@
 [instantiation-error-3.html]
-  [Test that unresolvable cycles lead to SyntaxError events on window and load events on script, and that exceptions are remembered]
-    expected: FAIL
+  disabled: bug 1426195
deleted file mode 100644
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[instantiation-error-4.html]
-  [Test that loading a graph in which a module is already errored results in that module's error.]
-    expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[instantiation-error-5.html]
-  [Test that loading a graph in which a module is already errored results in that module's error.]
-    expected: FAIL
--- a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html
@@ -1,27 +1,29 @@
 <!DOCTYPE html>
 <title>Handling of instantiation errors, 1</title>
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script>
     setup({allow_uncaught_exception: true});
 
-    window.log = [];
-
-    window.addEventListener("error", ev => log.push(ev.error));
-
     const test_load = async_test(
         "Test that missing exports lead to SyntaxError events on window and " +
-        "load events on script, and that exceptions are remembered");
+        "load events on script");
+
+    window.log = [];
+    window.addEventListener("error", ev => {
+      test_load.step(() => assert_equals(ev.error.constructor, SyntaxError));
+      log.push(ev.message);
+    });
+
     window.addEventListener("load", test_load.step_func_done(ev => {
-      const exn = log[0];
-      assert_array_equals(log, [exn, 1, exn, 2, exn, 3, exn, 4, exn, 5]);
-      assert_equals(exn.constructor, SyntaxError);
+      const msg = log[0];
+      assert_array_equals(log, [msg, 1, msg, 2, msg, 3, msg, 4, msg, 5]);
     }));
 
     function unreachable() { log.push("unexpected"); }
 </script>
 <script type="module" src="./missing-export.js"
     onerror="unreachable()" onload="log.push(1)"></script>
 <script type="module" src="./missing-export.js"
     onerror="unreachable()" onload="log.push(2)"></script>
--- a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html
@@ -1,27 +1,29 @@
 <!DOCTYPE html>
 <title>Handling of instantiation errors, 2</title>
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script>
     setup({allow_uncaught_exception: true});
 
-    window.log = [];
-
-    window.addEventListener("error", ev => log.push(ev.error));
-
     const test_load = async_test(
         "Test that missing exports lead to SyntaxError events on window and " +
-        "load events on script, and that exceptions are remembered");
+        "load events on script");
+
+    window.log = [];
+    window.addEventListener("error", ev => {
+      test_load.step(() => assert_equals(ev.error.constructor, SyntaxError));
+      log.push(ev.message);
+    });
+
     window.addEventListener("load", test_load.step_func_done(ev => {
-      const exn = log[0];
-      assert_array_equals(log, [exn, 1, exn, 2, exn, 3, exn, 4, exn, 5]);
-      assert_equals(exn.constructor, SyntaxError);
+      const msg = log[0];
+      assert_array_equals(log, [msg, 1, msg, 2, msg, 3, msg, 4, msg, 5]);
     }));
 
     function unreachable() { log.push("unexpected"); }
 </script>
 <script type="module" src="./missing-export-nested.js"
     onerror="unreachable()" onload="log.push(1)"></script>
 <script type="module" src="./missing-export-nested.js"
     onerror="unreachable()" onload="log.push(2)"></script>
--- a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html
@@ -1,27 +1,29 @@
 <!DOCTYPE html>
 <title>Handling of instantiation errors, 3</title>
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script>
     setup({allow_uncaught_exception: true});
 
-    window.log = [];
-
-    window.addEventListener("error", ev => log.push(ev.error));
-
     const test_load = async_test(
         "Test that unresolvable cycles lead to SyntaxError events on window " +
-        "and load events on script, and that exceptions are remembered");
+        "and load events on script");
+
+    window.log = [];
+    window.addEventListener("error", ev => {
+      test_load.step(() => assert_equals(ev.error.constructor, SyntaxError));
+      log.push(ev.message);
+    });
+
     window.addEventListener("load", test_load.step_func_done(ev => {
-      const exn = log[0];
-      assert_array_equals(log, [exn, 1, exn, 2, exn, 3]);
-      assert_equals(exn.constructor, SyntaxError);
+      const msg = log[0];
+      assert_array_equals(log, [msg, 1, msg, 2, msg, 3]);
     }));
 
     function unreachable() { log.push("unexpected"); }
 </script>
 <script type="module" src="./cycle-unresolvable.js"
     onerror="unreachable()" onload="log.push(1)" nomodule></script>
 <script type="module" src="./cycle-unresolvable-a.js"
     onerror="unreachable()" onload="log.push(2)"></script>
--- a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html
@@ -2,26 +2,28 @@
 <title>Handling of instantiation errors, 4</title>
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script>
     setup({allow_uncaught_exception: true});
 
     window.log = [];
-
-    window.addEventListener("error", ev => log.push(ev.error));
-
     const test_load = async_test(
         "Test that loading a graph in which a module is already " +
-        "errored results in that module's error.");
+        "errored results in an error.");
+
+    window.addEventListener("error", ev => {
+      test_load.step(() => assert_equals(ev.error.constructor, SyntaxError));
+      log.push(ev.message);
+    });
+
     window.addEventListener("load", test_load.step_func_done(ev => {
-      const exn = log[0];
-      assert_array_equals(log, [exn, 1, exn, 2]);
-      assert_equals(exn.constructor, SyntaxError);
+      const msg = log[0];
+      assert_array_equals(log, [msg, 1, msg, 2]);
     }));
 
     function unreachable() { log.push("unexpected"); }
 </script>
 <script type="module" src="./instantiation-error-4a.js"
     onerror="unreachable()" onload="log.push(1)"></script>
 <script type="module" src="./instantiation-error-4d.js"
     onerror="unreachable()" onload="log.push(2)"></script>
--- a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html
@@ -1,27 +1,29 @@
 <!DOCTYPE html>
 <title>Handling of instantiation errors, 5</title>
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script>
     setup({allow_uncaught_exception: true});
 
-    window.log = [];
-
-    window.addEventListener("error", ev => log.push(ev.error));
-
     const test_load = async_test(
         "Test that loading a graph in which a module is already " +
-        "errored results in that module's error.");
+        "errored results an error.");
+
+    window.log = [];
+    window.addEventListener("error", ev => {
+      test_load.step(() => assert_equals(ev.error.constructor, SyntaxError));
+      log.push(ev.message);
+    });
+
     window.addEventListener("load", test_load.step_func_done(ev => {
-      const exn = log[0];
-      assert_array_equals(log, [exn, 1, exn, 2]);
-      assert_equals(exn.constructor, SyntaxError);
+      const msg = log[0];
+      assert_array_equals(log, [msg, 1, msg, 2]);
     }));
 
     function unreachable() { log.push("unexpected"); }
 </script>
 <script type="module" src="./instantiation-error-5a.js"
     onerror="unreachable()" onload="log.push(1)"></script>
 <script type="module" src="./instantiation-error-5d.js"
     onerror="unreachable()" onload="log.push(2)"></script>
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -2418,24 +2418,24 @@
     "alert_emails": ["necko@mozilla.com"],
     "bug_numbers": [1357682],
     "expires_in_version": "61",
     "kind": "categorical",
     "keyed": true,
     "description": "Stats about success rate of HTTP OMT request in content process, keyed by content policy.",
     "labels": ["success", "successMainThread", "failListener", "failListenerChain", "notRequested"]
   },
-  "TCP_FAST_OPEN_2": {
-    "record_in_processes": ["main", "content"],
+  "TCP_FAST_OPEN_3": {
+    "record_in_processes": ["main"],
     "expires_in_version": "61",
     "kind": "enumerated",
-    "n_values": 16,
-    "description": "When a http connection is closed, track whether or not TCP Fast Open was used: 0=TFO_NOT_TRIED(There was no http connection and it was not TLS), 1=TFO_TRIED_NEGOTIATING, 2=TFO_DATA_SENT, 3=TFO_FAILED_CONNECTION_REFUSED, 4=TFO_FAILED_NET_TIMEOUT, 5=TFO_FAILED_UNKNOW_ERROR, 6=TFO_FAILED_BACKUP_CONNECTION, 7=TFO_FAILED_CONNECTION_REFUSED_NO_TFO_FAILED_TOO, 8=TFO_FAILED_NET_TIMEOUT__NO_TFO_FAILED_TOO, 9=TFO_FAILED_UNKNOW_ERROR_NO_TFO_FAILED_TOO, 10=TFO_FAILED_BACKUP_CONNECTION_NO_TFO_FAILED_TOO.",
+    "n_values": 32,
+    "description": "When a http connection is closed, track whether or not TCP Fast Open was used: 0=TFO_NOT_SET, 1=TFO_UNKNOWN, 2=TFO_DISABLED, 3=TFO_DISABLED_CONNECT, 4=TFO_NOT_TRIED, 5=TFO_TRIED, 6=TFO_DATA_SENT, 7=TFO_DATA_COOKIE_NOT_ACCEPTED, 8=TFO_FAILED_CONNECTION_REFUSED, 9=TFO_FAILED_NET_TIMEOUT, 10=TFO_FAILED_UNKNOW_ERROR, 11=TFO_FAILED_BACKUP_CONNECTION_TFO_NOT_TRIED, 12=TFO_FAILED_BACKUP_CONNECTION_TFO_TRIED, 13=TFO_FAILED_BACKUP_CONNECTION_TFO_DATA_SENT, 14=TFO_FAILED_BACKUP_CONNECTION_TFO_DATA_COOKIE_NOT_ACCEPTED, 15=TFO_FAILED_CONNECTION_REFUSED_NO_TFO_FAILED_TOO, 16=TFO_FAILED_NET_TIMEOUT__NO_TFO_FAILED_TOO, 17=TFO_FAILED_UNKNOW_ERROR_NO_TFO_FAILED_TOO, 18=TFO_FAILED_BACKUP_CONNECTION_NO_TFO_FAILED_TOO, 19=TFO_BACKUP_CONN. Please look at netwerk/base/TCPFastOpenLayer.h for more info",
     "alert_emails": ["necko@mozilla.com", "ddamjanovic@mozilla.com"],
-    "bug_numbers": [1390881]
+    "bug_numbers": [1402879]
   },
   "TCP_FAST_OPEN_STATUS": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "61",
     "kind": "enumerated",
     "n_values": 8,
     "description": "TCP Fast Open was: 0=enabled during the session, 1=not available or disabled in the os, 2=disabled by the pref, 3=disabled based on the too many connection failures.",
     "alert_emails": ["necko@mozilla.com", "ddamjanovic@mozilla.com"],
--- a/toolkit/components/telemetry/Scalars.yaml
+++ b/toolkit/components/telemetry/Scalars.yaml
@@ -1262,16 +1262,31 @@ screenshots:
     notification_emails:
       - jhirsch@mozilla.com
       - ibicking@mozilla.com
       - clouserw@mozilla.com
     release_channel_collection: opt-out
     record_in_processes:
       - 'main'
 
+network.http:
+  backup_conn_won:
+    bug_numbers:
+      - 1402811
+    description: >
+      For connection where TFO has not be use, collect telemetry on whether the
+      backup connection or the primary connection was faster.
+    expires: "61"
+    kind: boolean
+    notification_emails:
+      - necko@mozilla.com
+      - ddamjanovic@mozilla.com
+    record_in_processes:
+      - 'main'
+
 idb.type:
   persistent_count:
     bug_numbers:
       - 1360567
     description: >
       Number of times indexeddb.open(name, {storage: "persistent"}) has been used.
     expires: "60"
     kind: uint
--- a/widget/nsDragServiceProxy.cpp
+++ b/widget/nsDragServiceProxy.cpp
@@ -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/. */
 
 #include "nsDragServiceProxy.h"
 #include "nsIDocument.h"
 #include "nsISupportsPrimitives.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/EventStateManager.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "nsContentUtils.h"
 
 using mozilla::ipc::Shmem;
 using mozilla::dom::TabChild;
 using mozilla::dom::OptionalShmem;
 using mozilla::LayoutDeviceIntRect;
@@ -83,8 +84,26 @@ nsDragServiceProxy::InvokeDragSessionImp
     }
   }
 
   mozilla::Unused << child->SendInvokeDragSession(dataTransfers, aActionType,
                                                   mozilla::void_t(), 0, 0, dragRect);
   StartDragSession();
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsDragServiceProxy::StartDragSession()
+{
+  // Normally, OS stops firing input events when a drag operation starts. But
+  // there may be some pending input events queued in the content process. We
+  // have to suppress them since spec says that input events must be suppressed
+  // when there is a dnd session.
+  EventStateManager::SuppressInputEvents();
+  return nsBaseDragService::StartDragSession();
+}
+
+NS_IMETHODIMP
+nsDragServiceProxy::EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers)
+{
+  EventStateManager::UnsuppressInputEvents();
+  return nsBaseDragService::EndDragSession(aDoneDrag, aKeyModifiers);
+}
--- a/widget/nsDragServiceProxy.h
+++ b/widget/nsDragServiceProxy.h
@@ -14,13 +14,18 @@ public:
   nsDragServiceProxy();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsBaseDragService
   virtual nsresult InvokeDragSessionImpl(nsIArray* anArrayTransferables,
                                          nsIScriptableRegion* aRegion,
                                          uint32_t aActionType) override;
+
+  // nsIDragService
+  NS_IMETHOD StartDragSession() override;
+  NS_IMETHOD EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers) override;
+
 private:
   virtual ~nsDragServiceProxy();
 };
 
 #endif // NSDRAGSERVICEPROXY_H
--- a/xpcom/io/nsLocalFileCommon.cpp
+++ b/xpcom/io/nsLocalFileCommon.cpp
@@ -10,16 +10,17 @@
 
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsReadableUtils.h"
 #include "nsPrintfCString.h"
 #include "nsCRT.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsUTF8Utils.h"
+#include "nsArray.h"
 
 #ifdef XP_WIN
 #include <string.h>
 #endif
 
 
 void
 NS_StartupLocalFile()