Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 19 May 2017 15:14:19 -0700
changeset 409851 8d60d0f825110cfb646ac31dc16dc011708bcf34
parent 409829 979f11deabd01d6cb897d064d3d9ed11ea8baa93 (current diff)
parent 409850 5aa81aa442e207661db6b8d34984d3e519c10ba2 (diff)
child 410187 2222a2e846f757200cd86848976cce36198b70ba
child 410212 cd9b1ab819e88a5b9cc53b7fc651a4d9bf3eef05
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.0a1
first release with
nightly linux32
8d60d0f82511 / 55.0a1 / 20170520182312 / files
nightly linux64
8d60d0f82511 / 55.0a1 / 20170520182312 / files
nightly mac
8d60d0f82511 / 55.0a1 / 20170520030204 / files
nightly win32
8d60d0f82511 / 55.0a1 / 20170520030204 / files
nightly win64
8d60d0f82511 / 55.0a1 / 20170520030204 / 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 inbound to central, a=merge MozReview-Commit-ID: EI67EKp8ykS
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
testing/mochitest/browser-test.js
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -263,23 +263,27 @@ menuitem.bookmark-item {
 #close-button {
   list-style-image: url("chrome://global/skin/icons/Close.gif");
 }
 
 /* Location bar */
 #main-window {
   --urlbar-border-color: ThreeDShadow;
   --urlbar-border-color-hover: var(--urlbar-border-color);
-  --urlbar-background-color: -moz-field;
 }
 
 #navigator-toolbox:-moz-lwtheme {
   --urlbar-border-color: rgba(0,0,0,.3);
 }
 
+#urlbar {
+  /* override textbox[enablehistory="true"] styling: */
+  background-color: -moz-field;
+}
+
 %include ../shared/urlbar-searchbar.inc.css
 
 %ifdef MOZ_PHOTON_THEME
 
 #urlbar[focused="true"],
 .searchbar-textbox[focused="true"] {
   border-color: Highlight;
 }
@@ -296,20 +300,16 @@ menuitem.bookmark-item {
   margin: 0 3px;
 }
 
 #urlbar[focused],
 .searchbar-textbox[focused] {
   border-color: Highlight;
 }
 
-#urlbar {
-  background-color: -moz-field;
-}
-
 #urlbar:-moz-lwtheme,
 .searchbar-textbox:-moz-lwtheme {
   background-color: rgba(255,255,255,.8);
   color: black;
 }
 
 #urlbar:-moz-lwtheme[focused=true],
 .searchbar-textbox:-moz-lwtheme[focused=true] {
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -522,17 +522,16 @@ toolbarpaletteitem[place="palette"] > #p
 
 %include ../shared/urlbar-searchbar.inc.css
 
 %ifdef MOZ_PHOTON_THEME
 
 #main-window {
   --urlbar-border-color: hsla(240, 5%, 5%, .25);
   --urlbar-border-color-hover: hsla(240, 5%, 5%, .35);
-  --urlbar-background-color: -moz-field;
 }
 
 #urlbar[focused="true"],
 .searchbar-textbox[focused="true"] {
   border-color: -moz-mac-focusring;
   box-shadow: var(--focus-ring-box-shadow);
 }
 
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 %ifdef MOZ_PHOTON_THEME
 
 #urlbar,
 .searchbar-textbox {
   -moz-appearance: none;
   background-clip: content-box;
-  background-color: var(--urlbar-background-color);
   border: 1px solid var(--urlbar-border-color);
   border-radius: var(--toolbarbutton-border-radius);
   box-shadow: 0 1px 4px hsla(0, 0%, 0%, .05);
   padding: 0;
   margin: 0 5px;
   min-height: 30px;
 }
 
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -665,17 +665,16 @@ toolbar[brighttext] #close-button {
 %include ../shared/urlbar-searchbar.inc.css
 
 %ifdef MOZ_PHOTON_THEME
 
 @media (-moz-windows-default-theme) {
   #main-window:not(:-moz-lwtheme) {
     --urlbar-border-color: hsla(240, 5%, 5%, .25);
     --urlbar-border-color-hover: hsla(240, 5%, 5%, .35);
-    --urlbar-background-color: -moz-field;
   }
 }
 
 #urlbar,
 .searchbar-textbox {
   font-size: 1.15em;
 }
 
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -251,16 +251,17 @@ TimeoutManager::TimeoutManager(nsGlobalW
 
   MOZ_LOG(gLog, LogLevel::Debug,
           ("TimeoutManager %p created, tracking bucketing %s\n",
            this, gAnnotateTrackingChannels ? "enabled" : "disabled"));
 }
 
 TimeoutManager::~TimeoutManager()
 {
+  MOZ_DIAGNOSTIC_ASSERT(mWindow.AsInner()->InnerObjectsFreed());
   MOZ_DIAGNOSTIC_ASSERT(!mThrottleTrackingTimeoutsTimer);
 
   MOZ_LOG(gLog, LogLevel::Debug,
           ("TimeoutManager %p destroyed\n", this));
 }
 
 /* static */
 void
@@ -1467,17 +1468,18 @@ void
 TimeoutManager::OnDocumentLoaded()
 {
   MaybeStartThrottleTrackingTimout();
 }
 
 void
 TimeoutManager::MaybeStartThrottleTrackingTimout()
 {
-  if (gTrackingTimeoutThrottlingDelay <= 0) {
+  if (gTrackingTimeoutThrottlingDelay <= 0 ||
+      mWindow.AsInner()->InnerObjectsFreed()) {
     return;
   }
 
   MOZ_DIAGNOSTIC_ASSERT(!mThrottleTrackingTimeouts);
 
   MOZ_LOG(gLog, LogLevel::Debug,
           ("TimeoutManager %p delaying tracking timeout throttling by %dms\n",
            this, gTrackingTimeoutThrottlingDelay));
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -419,31 +419,35 @@ def DOMClass(descriptor):
           GetProtoObjectHandle,
           GetCCParticipant<${nativeType}>::Get()
         """,
         protoChain=', '.join(protoList),
         nativeType=descriptor.nativeType,
         hooks=NativePropertyHooks(descriptor))
 
 
+def InstanceReservedSlots(descriptor):
+    return INSTANCE_RESERVED_SLOTS + descriptor.interface.totalMembersInSlots
+
+
 class CGDOMJSClass(CGThing):
     """
     Generate a DOMJSClass for a given descriptor
     """
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
 
     def declare(self):
         return ""
 
     def define(self):
         callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
         objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr'
-        slotCount = INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots
+        slotCount = InstanceReservedSlots(self.descriptor)
         classFlags = "JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | "
         if self.descriptor.isGlobal():
             classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS)"
             traceHook = "JS_GlobalObjectTraceHook"
             reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
         else:
             classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
             traceHook = 'nullptr'
@@ -523,19 +527,20 @@ class CGDOMProxyJSClass(CGThing):
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
 
     def declare(self):
         return ""
 
     def define(self):
+        slotCount = InstanceReservedSlots(self.descriptor)
         # We need one reserved slot (DOM_OBJECT_SLOT).
         flags = ["JSCLASS_IS_DOMJSCLASS",
-                 "JSCLASS_HAS_RESERVED_SLOTS(1)"]
+                 "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount]
         # We don't use an IDL annotation for JSCLASS_EMULATES_UNDEFINED because
         # we don't want people ever adding that to any interface other than
         # HTMLAllCollection.  So just hardcode it here.
         if self.descriptor.interface.identifier.name == "HTMLAllCollection":
             flags.append("JSCLASS_EMULATES_UNDEFINED")
         objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr'
         return fill(
             """
@@ -12712,20 +12717,16 @@ class CGDescriptor(CGThing):
         if (descriptor.interface.hasMembersInSlots() and
             descriptor.interface.hasChildInterfaces()):
             raise TypeError("We don't support members in slots on "
                             "non-leaf interfaces like %s" %
                             descriptor.interface.identifier.name)
 
         if descriptor.concrete:
             if descriptor.proxy:
-                if descriptor.interface.totalMembersInSlots != 0:
-                    raise TypeError("We can't have extra reserved slots for "
-                                    "proxy interface %s" %
-                                    descriptor.interface.identifier.name)
                 cgThings.append(CGGeneric(fill(
                     """
                     static_assert(IsBaseOf<nsISupports, ${nativeType} >::value,
                                       "We don't support non-nsISupports native classes for "
                                       "proxy-based bindings yet");
 
                     """,
                     nativeType=descriptor.nativeType)))
@@ -12736,18 +12737,19 @@ class CGDescriptor(CGThing):
                 cgThings.append(CGDOMJSProxyHandlerDeclarer(handlerThing))
                 cgThings.append(CGProxyIsProxy(descriptor))
                 cgThings.append(CGProxyUnwrap(descriptor))
                 cgThings.append(CGDOMJSProxyHandlerDefiner(handlerThing))
                 cgThings.append(CGDOMProxyJSClass(descriptor))
             else:
                 cgThings.append(CGDOMJSClass(descriptor))
                 cgThings.append(CGGetJSClassMethod(descriptor))
-                if descriptor.interface.hasMembersInSlots():
-                    cgThings.append(CGUpdateMemberSlotsMethod(descriptor))
+
+            if descriptor.interface.hasMembersInSlots():
+                cgThings.append(CGUpdateMemberSlotsMethod(descriptor))
 
             if descriptor.isGlobal():
                 assert descriptor.wrapperCache
                 cgThings.append(CGWrapGlobalMethod(descriptor, properties))
             elif descriptor.wrapperCache:
                 cgThings.append(CGWrapWithCacheMethod(descriptor, properties))
                 cgThings.append(CGWrapMethod(descriptor))
             else:
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -1212,16 +1212,18 @@ public:
   virtual nsISupports* GetParentObject();
 
   uint32_t IndexedGetter(uint32_t, bool&);
   uint32_t IndexedGetter(uint32_t&) = delete;
   uint32_t Item(uint32_t&);
   uint32_t Item(uint32_t, bool&) = delete;
   uint32_t Length();
   void LegacyCall(JS::Handle<JS::Value>);
+  int32_t CachedAttr();
+  int32_t StoreInSlotAttr();
 };
 
 class TestNamedGetterInterface : public nsISupports,
                                  public nsWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS
 
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -1183,16 +1183,18 @@ dictionary DictWithConditionalMembers {
   [ChromeOnly, Func="nsGenericHTMLElement::TouchEventsEnabled"]
   long chromeOnlyFuncControlledMember;
 };
 
 interface TestIndexedGetterInterface {
   getter long item(unsigned long idx);
   readonly attribute unsigned long length;
   legacycaller void();
+  [Cached, Pure] readonly attribute long cachedAttr;
+  [StoreInSlot, Pure] readonly attribute long storeInSlotAttr;
 };
 
 interface TestNamedGetterInterface {
   getter DOMString (DOMString name);
 };
 
 interface TestIndexedGetterAndSetterAndNamedGetterInterface {
   getter DOMString (DOMString myName);
--- a/dom/file/ipc/IPCBlobInputStream.cpp
+++ b/dom/file/ipc/IPCBlobInputStream.cpp
@@ -187,16 +187,20 @@ IPCBlobInputStream::Clone(nsIInputStream
 {
   if (mState == eClosed) {
     return NS_BASE_STREAM_CLOSED;
   }
 
   MOZ_ASSERT(mActor);
 
   nsCOMPtr<nsIInputStream> stream = mActor->CreateStream();
+  if (!stream) {
+    return NS_ERROR_FAILURE;
+  }
+
   stream.forget(aResult);
   return NS_OK;
 }
 
 // nsIAsyncInputStream interface
 
 NS_IMETHODIMP
 IPCBlobInputStream::CloseWithStatus(nsresult aStatus)
--- a/dom/file/ipc/IPCBlobInputStreamChild.cpp
+++ b/dom/file/ipc/IPCBlobInputStreamChild.cpp
@@ -8,29 +8,27 @@
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 // This runnable is used in case the last stream is forgotten on the 'wrong'
 // thread.
-class DeleteRunnable final : public Runnable
+class ShutdownRunnable final : public Runnable
 {
 public:
-  explicit DeleteRunnable(IPCBlobInputStreamChild* aActor)
+  explicit ShutdownRunnable(IPCBlobInputStreamChild* aActor)
     : mActor(aActor)
   {}
 
   NS_IMETHOD
   Run() override
   {
-    if (mActor->IsAlive()) {
-      mActor->Send__delete__(mActor);
-    }
+    mActor->Shutdown();
     return NS_OK;
   }
 
 private:
   RefPtr<IPCBlobInputStreamChild> mActor;
 };
 
 // This runnable is used in case StreamNeeded() has been called on a non-owning
@@ -91,69 +89,97 @@ IPCBlobInputStreamChild::IPCBlobInputStr
   , mActorAlive(true)
   , mOwningThread(NS_GetCurrentThread())
 {}
 
 IPCBlobInputStreamChild::~IPCBlobInputStreamChild()
 {}
 
 void
+IPCBlobInputStreamChild::Shutdown()
+{
+  MutexAutoLock lock(mMutex);
+
+  RefPtr<IPCBlobInputStreamChild> kungFuDeathGrip = this;
+
+  mPendingOperations.Clear();
+
+  if (mActorAlive) {
+    SendClose();
+    mActorAlive = false;
+  }
+}
+
+void
 IPCBlobInputStreamChild::ActorDestroy(IProtocol::ActorDestroyReason aReason)
 {
-  MutexAutoLock lock(mMutex);
-  mActorAlive = false;
+  {
+    MutexAutoLock lock(mMutex);
+    mActorAlive = false;
+  }
+
+  Shutdown();
 }
 
 bool
 IPCBlobInputStreamChild::IsAlive()
 {
   MutexAutoLock lock(mMutex);
   return mActorAlive;
 }
 
 already_AddRefed<nsIInputStream>
 IPCBlobInputStreamChild::CreateStream()
 {
   MutexAutoLock lock(mMutex);
 
+  if (!mActorAlive) {
+    return nullptr;
+  }
+
   RefPtr<IPCBlobInputStream> stream = new IPCBlobInputStream(this);
   mStreams.AppendElement(stream);
   return stream.forget();
 }
 
 void
 IPCBlobInputStreamChild::ForgetStream(IPCBlobInputStream* aStream)
 {
   MOZ_ASSERT(aStream);
 
-  RefPtr<IPCBlobInputStreamChild> kungFoDeathGrip = this;
+  RefPtr<IPCBlobInputStreamChild> kungFuDeathGrip = this;
 
   {
     MutexAutoLock lock(mMutex);
     mStreams.RemoveElement(aStream);
 
     if (!mStreams.IsEmpty() || !mActorAlive) {
       return;
     }
   }
 
   if (mOwningThread == NS_GetCurrentThread()) {
-    Send__delete__(this);
+    Shutdown();
     return;
   }
 
-  RefPtr<DeleteRunnable> runnable = new DeleteRunnable(this);
+  RefPtr<ShutdownRunnable> runnable = new ShutdownRunnable(this);
   mOwningThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
 }
 
 void
 IPCBlobInputStreamChild::StreamNeeded(IPCBlobInputStream* aStream,
                                       nsIEventTarget* aEventTarget)
 {
   MutexAutoLock lock(mMutex);
+
+  if (!mActorAlive) {
+    return;
+  }
+
   MOZ_ASSERT(mStreams.Contains(aStream));
 
   PendingOperation* opt = mPendingOperations.AppendElement();
   opt->mStream = aStream;
   opt->mEventTarget = aEventTarget ? aEventTarget : NS_GetCurrentThread();
 
   if (mOwningThread == NS_GetCurrentThread()) {
     SendStreamNeeded();
@@ -170,16 +196,17 @@ IPCBlobInputStreamChild::RecvStreamReady
   nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aStream);
 
   RefPtr<IPCBlobInputStream> pendingStream;
   nsCOMPtr<nsIEventTarget> eventTarget;
 
   {
     MutexAutoLock lock(mMutex);
     MOZ_ASSERT(!mPendingOperations.IsEmpty());
+    MOZ_ASSERT(mActorAlive);
 
     pendingStream = mPendingOperations[0].mStream;
     eventTarget = mPendingOperations[0].mEventTarget;
 
     mPendingOperations.RemoveElementAt(0);
   }
 
   RefPtr<StreamReadyRunnable> runnable =
--- a/dom/file/ipc/IPCBlobInputStreamChild.h
+++ b/dom/file/ipc/IPCBlobInputStreamChild.h
@@ -51,16 +51,19 @@ public:
 
   void
   StreamNeeded(IPCBlobInputStream* aStream,
                nsIEventTarget* aEventTarget);
 
   mozilla::ipc::IPCResult
   RecvStreamReady(const OptionalIPCStream& aStream) override;
 
+  void
+  Shutdown();
+
 private:
   ~IPCBlobInputStreamChild();
 
   // Raw pointers because these streams keep this actor alive. When the last
   // stream is unregister, the actor will be deleted. This list is protected by
   // mutex.
   nsTArray<IPCBlobInputStream*> mStreams;
 
--- a/dom/file/ipc/IPCBlobInputStreamParent.cpp
+++ b/dom/file/ipc/IPCBlobInputStreamParent.cpp
@@ -91,10 +91,19 @@ IPCBlobInputStreamParent::RecvStreamNeed
 
   if (!SendStreamReady(ipcStream.TakeValue())) {
     return IPC_FAIL(this, "SendStreamReady failed");
   }
 
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+IPCBlobInputStreamParent::RecvClose()
+{
+  MOZ_ASSERT(mContentManager || mPBackgroundManager);
+
+  Unused << Send__delete__(this);
+  return IPC_OK();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/file/ipc/IPCBlobInputStreamParent.h
+++ b/dom/file/ipc/IPCBlobInputStreamParent.h
@@ -39,16 +39,19 @@ public:
   Size() const
   {
     return mSize;
   }
 
   mozilla::ipc::IPCResult
   RecvStreamNeeded() override;
 
+  mozilla::ipc::IPCResult
+  RecvClose() override;
+
 private:
   IPCBlobInputStreamParent(const nsID& aID, uint64_t aSize,
                            nsIContentParent* aManager);
 
   IPCBlobInputStreamParent(const nsID& aID, uint64_t aSize,
                            mozilla::ipc::PBackgroundParent* aManager);
 
   const nsID mID;
--- a/dom/file/ipc/PIPCBlobInputStream.ipdl
+++ b/dom/file/ipc/PIPCBlobInputStream.ipdl
@@ -15,18 +15,18 @@ namespace mozilla {
 namespace ipc {
 
 protocol PIPCBlobInputStream
 {
   manager PBackground or PContent or PContentBridge;
 
 parent:
   async StreamNeeded();
-
-  async __delete__();
+  async Close();
 
 child:
   async StreamReady(OptionalIPCStream aStream);
+  async __delete__();
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/html/HTMLOptionElement.h
+++ b/dom/html/HTMLOptionElement.h
@@ -39,16 +39,21 @@ public:
   // nsIDOMHTMLOptionElement
   using mozilla::dom::Element::SetText;
   using mozilla::dom::Element::GetText;
   NS_DECL_NSIDOMHTMLOPTIONELEMENT
 
   bool Selected() const;
   bool DefaultSelected() const;
 
+  void SetSelectedChanged(bool aValue)
+  {
+    mSelectedChanged = aValue;
+  }
+
   virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
                                               int32_t aModType) const override;
 
   virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
                                  const nsAttrValueOrString* aValue,
                                  bool aNotify) override;
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue,
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -1067,17 +1067,17 @@ HTMLSelectElement::SetOptionsSelectedByI
         OnOptionSelected(selectFrame, optIndex, false, true,
                          aOptionsMask & NOTIFY);
         optionsDeselected = true;
       }
     }
   }
 
   // Make sure something is selected unless we were set to -1 (none)
-  if (optionsDeselected && aStartIndex != -1) {
+  if (optionsDeselected && aStartIndex != -1 && !(aOptionsMask & NO_RESELECT)) {
     optionsSelected =
       CheckSelectSomething(aOptionsMask & NOTIFY) || optionsSelected;
   }
 
   // Let the caller know whether anything was changed
   return optionsSelected || optionsDeselected;
 }
 
@@ -1643,23 +1643,24 @@ HTMLSelectElement::Reset()
 
   for (uint32_t i = 0; i < numOptions; i++) {
     RefPtr<HTMLOptionElement> option = Item(i);
     if (option) {
       //
       // Reset the option to its default value
       //
 
-      uint32_t mask = SET_DISABLED | NOTIFY;
+      uint32_t mask = SET_DISABLED | NOTIFY | NO_RESELECT;
       if (option->DefaultSelected()) {
         mask |= IS_SELECTED;
         numSelected++;
       }
 
       SetOptionsSelectedByIndex(i, i, mask);
+      option->SetSelectedChanged(false);
     }
   }
 
   //
   // If nothing was selected and it's not multiple, select something
   //
   if (numSelected == 0 && IsCombobox()) {
     SelectSomething(true);
--- a/dom/html/HTMLSelectElement.h
+++ b/dom/html/HTMLSelectElement.h
@@ -129,22 +129,26 @@ public:
    *
    *  CLEAR_ALL     whether to clear all other options (for example, if you
    *                are normal-clicking on the current option)
    *
    *  SET_DISABLED  whether it is permissible to set disabled options
    *                (for JavaScript)
    *
    *  NOTIFY        whether to notify frames and such
+   *
+   *  NO_RESELECT   no need to select something after an option is deselected
+   *                (for reset)
    */
   enum OptionType {
     IS_SELECTED   = 1 << 0,
     CLEAR_ALL     = 1 << 1,
     SET_DISABLED  = 1 << 2,
-    NOTIFY        = 1 << 3
+    NOTIFY        = 1 << 3,
+    NO_RESELECT   = 1 << 4
   };
 
   using nsIConstraintValidation::GetValidationMessage;
 
   explicit HTMLSelectElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
                              FromParser aFromParser = NOT_FROM_PARSER);
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLSelectElement, select)
--- a/dom/storage/SessionStorageManager.cpp
+++ b/dom/storage/SessionStorageManager.cpp
@@ -84,17 +84,17 @@ SessionStorageManager::GetStorage(mozIDO
                                   bool aPrivate,
                                   nsIDOMStorage** aRetval)
 {
   *aRetval = nullptr;
 
   nsAutoCString originKey;
   nsAutoCString originAttributes;
   nsresult rv = GenerateOriginKey(aPrincipal, originAttributes, originKey);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
+  if (NS_FAILED(rv)) {
     return rv;
   }
 
   OriginKeyHashTable* table;
   if (!mOATable.Get(originAttributes, &table)) {
     return NS_OK;
   }
 
@@ -123,17 +123,17 @@ SessionStorageManager::CloneStorage(nsID
   if (storage->Type() != Storage::eSessionStorage) {
     return NS_ERROR_UNEXPECTED;
   }
 
   nsAutoCString originKey;
   nsAutoCString originAttributes;
   nsresult rv = GenerateOriginKey(storage->Principal(), originAttributes,
                                   originKey);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
+  if (NS_FAILED(rv)) {
     return rv;
   }
 
   OriginKeyHashTable* table;
   if (!mOATable.Get(originAttributes, &table)) {
     table = new OriginKeyHashTable();
     mOATable.Put(originAttributes, table);
   }
--- a/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp
+++ b/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp
@@ -62,16 +62,17 @@ AndroidDynamicToolbarAnimator::AndroidDy
   // Compositor thread only
   , mCompositorShutdown(false)
   , mCompositorAnimationDeferred(false)
   , mCompositorLayersUpdateEnabled(false)
   , mCompositorAnimationStarted(false)
   , mCompositorReceivedFirstPaint(false)
   , mCompositorWaitForPageResize(false)
   , mCompositorToolbarShowRequested(false)
+  , mCompositorSendResponseForSnapshotUpdate(false)
   , mCompositorAnimationStyle(eAnimate)
   , mCompositorMaxToolbarHeight(0)
   , mCompositorToolbarHeight(0)
   , mCompositorSurfaceHeight(0)
   , mCompositorAnimationDirection(0)
   , mCompositorAnimationStartHeight(0)
 {}
 
@@ -265,40 +266,16 @@ AndroidDynamicToolbarAnimator::GetCurren
 
 ScreenIntCoord
 AndroidDynamicToolbarAnimator::GetCompositionHeight() const
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   return mCompositorCompositionSize.height;
 }
 
-bool
-AndroidDynamicToolbarAnimator::SetCompositionSize(ScreenIntSize aSize)
-{
-  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
-  if (mCompositorCompositionSize == aSize) {
-    return false;
-  }
-
-  ScreenIntSize prevSize = mCompositorCompositionSize;
-  mCompositorCompositionSize = aSize;
-
-  // The width has changed so the static snapshot needs to be updated
-  if ((prevSize.width != aSize.width) && (mToolbarState != eToolbarVisible)) {
-    PostMessage(STATIC_TOOLBAR_NEEDS_UPDATE);
-  }
-
-  if (prevSize.height != aSize.height) {
-    UpdateControllerCompositionHeight(aSize.height);
-    UpdateFixedLayerMargins();
-  }
-
-  return true;
-}
-
 void
 AndroidDynamicToolbarAnimator::SetScrollingRootContent()
 {
   MOZ_ASSERT(APZThreadUtils::IsControllerThread());
   mControllerScrollingRootContent = true;
 }
 
 void
@@ -313,18 +290,18 @@ AndroidDynamicToolbarAnimator::ToolbarAn
   case TOOLBAR_HIDDEN:
     // If the toolbar is animating, then it is already unlocked.
     if (mToolbarState != eToolbarAnimating) {
       mToolbarState = eToolbarUnlocked;
       if (mCompositorAnimationDeferred) {
         StartCompositorAnimation(mCompositorAnimationDirection, mCompositorAnimationStyle, mCompositorToolbarHeight, mCompositorWaitForPageResize);
       }
     } else {
-      // The compositor is already animating the toolbar so no need to defer.
-      mCompositorAnimationDeferred = false;
+      // Animation already running so just make sure it is going the right direction.
+      StartCompositorAnimation(MOVE_TOOLBAR_UP, mCompositorAnimationStyle, mCompositorToolbarHeight, mCompositorWaitForPageResize);
     }
     break;
   case TOOLBAR_VISIBLE:
     // If we are currently animating, let the animation finish.
     if (mToolbarState != eToolbarAnimating) {
       mToolbarState = eToolbarVisible;
     }
     break;
@@ -465,16 +442,45 @@ AndroidDynamicToolbarAnimator::UpdateRoo
   CSSToScreenScale scale = ViewTargetAs<ScreenPixel>(aMetrics.GetZoom().ToScaleFactor(),
                                                      PixelCastJustification::ScreenIsParentLayerForRoot);
   ScreenPoint scrollOffset = aMetrics.GetScrollOffset() * scale;
   CSSRect cssPageRect = aMetrics.GetScrollableRect();
 
   UpdateFrameMetrics(scrollOffset, scale, cssPageRect);
 }
 
+void
+AndroidDynamicToolbarAnimator::MaybeUpdateCompositionSizeAndRootFrameMetrics(const FrameMetrics& aMetrics)
+{
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+  CSSToScreenScale scale = ViewTargetAs<ScreenPixel>(aMetrics.GetZoom().ToScaleFactor(),
+                                                     PixelCastJustification::ScreenIsParentLayerForRoot);
+  ScreenIntSize size = ScreenIntSize::Round(aMetrics.GetRootCompositionSize() * scale);
+
+  if (mCompositorCompositionSize == size) {
+    return;
+  }
+
+  ScreenIntSize prevSize = mCompositorCompositionSize;
+  mCompositorCompositionSize = size;
+
+  // The width has changed so the static snapshot needs to be updated
+  if ((prevSize.width != size.width) && (mToolbarState == eToolbarUnlocked)) {
+    // No need to set mCompositorSendResponseForSnapshotUpdate. If it is already true we don't want to change it.
+    PostMessage(STATIC_TOOLBAR_NEEDS_UPDATE);
+  }
+
+  if (prevSize.height != size.height) {
+    UpdateControllerCompositionHeight(size.height);
+    UpdateFixedLayerMargins();
+  }
+
+  UpdateRootFrameMetrics(aMetrics);
+}
+
 // Layers updates are need by Robocop test which enables them
 void
 AndroidDynamicToolbarAnimator::EnableLayersUpdateNotifications(bool aEnable)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   mCompositorLayersUpdateEnabled = aEnable;
 }
 
@@ -520,17 +526,18 @@ AndroidDynamicToolbarAnimator::GetToolba
       // Upload failed!
       mCompositorToolbarTexture = nullptr;
     }
 
     RefPtr<UiCompositorControllerParent> uiController = UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
     uiController->DeallocShmem(mCompositorToolbarPixels.ref());
     mCompositorToolbarPixels.reset();
     // Send notification that texture is ready after the current composition has completed.
-    if (mCompositorToolbarTexture) {
+    if (mCompositorToolbarTexture && mCompositorSendResponseForSnapshotUpdate) {
+      mCompositorSendResponseForSnapshotUpdate = false;
       CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod(this, &AndroidDynamicToolbarAnimator::PostToolbarReady));
     }
   }
 
   if (mCompositorToolbarTexture) {
     if (!mCompositorToolbarEffect) {
       mCompositorToolbarEffect = new EffectRGB(mCompositorToolbarTexture, true, SamplingFilter::LINEAR);
     }
@@ -569,16 +576,17 @@ AndroidDynamicToolbarAnimator::ProcessTo
   if (tryingToHideToolbar && !mControllerScrollingRootContent) {
     // This prevent the toolbar from hiding if a subframe is being scrolled up.
     // The toolbar will always become visible regardless what is being scrolled down.
     return status;
   }
 
   if (aCurrentToolbarState == eToolbarVisible) {
     if (tryingToHideToolbar && (mControllerState != eUnlockPending)) {
+      mCompositorSendResponseForSnapshotUpdate = true;
       PostMessage(STATIC_TOOLBAR_NEEDS_UPDATE);
       mControllerState = eUnlockPending;
     }
     return status;
   }
 
   if (aCurrentToolbarState != eToolbarUnlocked) {
     return status;
@@ -791,17 +799,17 @@ AndroidDynamicToolbarAnimator::UpdateFix
   if (parent) {
     ScreenIntCoord surfaceHeight = parent->GetEGLSurfaceSize().height;
     if (surfaceHeight != mCompositorSurfaceHeight) {
       mCompositorSurfaceHeight = surfaceHeight;
       UpdateControllerSurfaceHeight(mCompositorSurfaceHeight);
     }
     AsyncCompositionManager* manager = parent->GetCompositionManager(nullptr);
     if (manager) {
-      if (mToolbarState == eToolbarAnimating) {
+      if ((mToolbarState == eToolbarAnimating) && mCompositorAnimationStarted) {
         manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
       } else {
         manager->SetFixedLayerMargins(0, GetFixedLayerMarginsBottom());
       }
     }
   }
 }
 
@@ -846,31 +854,33 @@ AndroidDynamicToolbarAnimator::StartComp
   mCompositorAnimationDirection = aDirection;
   mCompositorAnimationStartHeight = mCompositorToolbarHeight = aHeight;
   mCompositorAnimationStyle = aAnimationStyle;
   mCompositorWaitForPageResize = aWaitForPageResize;
   // If the snapshot is not unlocked, request the UI thread update the snapshot
   // and defer animation until it has been unlocked
   if ((initialToolbarState != eToolbarUnlocked) && (initialToolbarState != eToolbarAnimating)) {
     mCompositorAnimationDeferred = true;
+    mCompositorSendResponseForSnapshotUpdate = true;
     PostMessage(STATIC_TOOLBAR_NEEDS_UPDATE);
   } else {
     // Toolbar is either unlocked or already animating so animation may begin immediately
     mCompositorAnimationDeferred = false;
     mToolbarState = eToolbarAnimating;
     if (initialToolbarState != eToolbarAnimating) {
       mCompositorAnimationStarted = false;
     }
-    // Let the controller know we starting an animation so it may clear the AnimationStartPending flag.
+    // Let the controller know we are starting an animation so it may clear the AnimationStartPending flag.
     NotifyControllerAnimationStarted();
-    CompositorBridgeParent* parent = CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(mRootLayerTreeId);
-    if (parent) {
-      mCompositorAnimationStartTimeStamp = parent->GetAPZCTreeManager()->GetFrameTime();
-    }
+    // Only reset the time stamp and start compositor animation if not already animating.
     if (initialToolbarState != eToolbarAnimating) {
+      CompositorBridgeParent* parent = CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(mRootLayerTreeId);
+      if (parent) {
+        mCompositorAnimationStartTimeStamp = parent->GetAPZCTreeManager()->GetFrameTime();
+      }
       // Kick the compositor to start the animation if we aren't already animating.
       RequestComposite();
     }
   }
 }
 
 void
 AndroidDynamicToolbarAnimator::NotifyControllerAnimationStarted()
--- a/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.h
+++ b/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.h
@@ -76,30 +76,30 @@ public:
   // returns the height in device pixels of the current Android surface used to display content and the toolbar.
   // This will only change when the surface provided by the system actually changes size such as when
   // the device is rotated or the virtual keyboard is made visible.
   ScreenIntCoord GetCurrentSurfaceHeight() const;
   // This is the height in device pixels of the root document's content. While the toolbar is being hidden or
   // shown, the content may extend beyond the bottom of the surface until the toolbar is completely
   // visible or hidden.
   ScreenIntCoord GetCompositionHeight() const;
-  // Returns true if the composition size has changed from the last time it was set.
-  bool SetCompositionSize(ScreenIntSize aSize);
   // Called to signal that root content is being scrolled. This prevents sub scroll frames from
   // affecting the toolbar when being scrolled up. The idea is a scrolling down will always
   // show the toolbar while scrolling up will only hide the toolbar if it is the root content
   // being scrolled.
   void SetScrollingRootContent();
   void ToolbarAnimatorMessageFromUI(int32_t aMessage);
   // Returns true if the animation will continue and false if it has completed.
   bool UpdateAnimation(const TimeStamp& aCurrentFrame);
   // Called to signify the first paint has occurred.
   void FirstPaint();
   // Called whenever the root document's FrameMetrics have reached a steady state.
   void UpdateRootFrameMetrics(const FrameMetrics& aMetrics);
+  // Only update the frame metrics if the root composition size has changed
+  void MaybeUpdateCompositionSizeAndRootFrameMetrics(const FrameMetrics& aMetrics);
   // When aEnable is set to true, it informs the animator that the UI thread expects to
   // be notified when the layer tree  has been updated. Enabled currently by robocop tests.
   void EnableLayersUpdateNotifications(bool aEnable);
   // Called when a layer has been updated so the UI thread may be notified if necessary.
   void NotifyLayersUpdated();
   // Adopts the Shmem containing the toolbar snapshot sent from the UI thread.
   // The AndroidDynamicToolbarAnimator is responsible for deallocating the Shmem when
   // it is done being used.
@@ -220,17 +220,18 @@ protected:
   // Compositor thread only
   bool mCompositorShutdown;             // Set to true when the compositor has been shutdown
   bool mCompositorAnimationDeferred;    // An animation has been deferred until the toolbar is unlocked
   bool mCompositorLayersUpdateEnabled;  // Flag set to true when the UI thread is expecting to be notified when a layer has been updated
   bool mCompositorAnimationStarted;     // Set to true when the compositor has actually started animating the static snapshot.
   bool mCompositorReceivedFirstPaint;   // Set to true when a first paint occurs. Used by toolbar animator to detect a new page load.
   bool mCompositorWaitForPageResize;    // Set to true if the bottom of the page has been reached and the toolbar animator should wait for the page to resize before ending animation.
   bool mCompositorToolbarShowRequested; // Set to true if the animator has already requested the real toolbar chrome be shown
-  AnimationStyle mCompositorAnimationStyle;       // Set to true when the snap should be immediately hidden or shown in the animation update
+  bool mCompositorSendResponseForSnapshotUpdate;  // Set to true when a message should be sent after a static toolbar snapshot update
+  AnimationStyle mCompositorAnimationStyle;       // Set to true when the snapshot should be immediately hidden or shown in the animation update
   ScreenIntCoord mCompositorMaxToolbarHeight;     // Should contain the same value as mControllerMaxToolbarHeight
   ScreenIntCoord mCompositorToolbarHeight;        // This value is only updated by the compositor thread when the mToolbarState == ToolbarAnimating
   ScreenIntCoord mCompositorSurfaceHeight;        // Current height of the render surface
   ScreenIntSize  mCompositorCompositionSize;      // Current size of the visible page
   int32_t mCompositorAnimationDirection;          // Direction the snapshot should be animated
   ScreenIntCoord mCompositorAnimationStartHeight; // The height of the snapshot at the start of an animation
   ScreenIntSize mCompositorToolbarPixelsSize;     // Size of the received toolbar pixels
   Maybe<mozilla::ipc::Shmem> mCompositorToolbarPixels; // Shared memory contain the updated snapshot pixels used to create the OGL texture
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3472,22 +3472,17 @@ void AsyncPanZoomController::NotifyLayer
   // TODO if we're in a drag and scrollOffsetUpdated is set then we want to
   // ignore it
 
 #if defined(MOZ_WIDGET_ANDROID)
   if (aLayerMetrics.IsRootContent()) {
     if (APZCTreeManager* manager = GetApzcTreeManager()) {
       AndroidDynamicToolbarAnimator* animator = manager->GetAndroidDynamicToolbarAnimator();
       MOZ_ASSERT(animator);
-      CSSToScreenScale scale = ViewTargetAs<ScreenPixel>(aLayerMetrics.GetZoom().ToScaleFactor(),
-                                                         PixelCastJustification::ScreenIsParentLayerForRoot);
-      ScreenIntSize size = ScreenIntSize::Round(aLayerMetrics.GetRootCompositionSize() * scale);
-      if (animator->SetCompositionSize(size)) {
-        animator->UpdateRootFrameMetrics(aLayerMetrics);
-      }
+      animator->MaybeUpdateCompositionSizeAndRootFrameMetrics(aLayerMetrics);
     }
   }
 #endif
 
   if ((aIsFirstPaint && aThisLayerTreeUpdated) || isDefault) {
     // Initialize our internal state to something sane when the content
     // that was just painted is something we knew nothing about previously
     CancelAnimation();
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -940,33 +940,34 @@ AsyncCompositionManager::ApplyAsyncConte
           // 6 for details.
           if (!(*aOutFoundRoot)) {
             *aOutFoundRoot = metrics.IsRootContent() ||       /* RCD */
                   (layer->GetParent() == nullptr &&          /* rootmost metrics */
                    i + 1 >= layer->GetScrollMetadataCount());
             if (*aOutFoundRoot) {
               mRootScrollableId = metrics.GetScrollId();
               Compositor* compositor = mLayerManager->GetCompositor();
-              if (mIsFirstPaint) {
-                if (CompositorBridgeParent* bridge = compositor->GetCompositorBridgeParent()) {
-                  AndroidDynamicToolbarAnimator* animator = bridge->GetAPZCTreeManager()->GetAndroidDynamicToolbarAnimator();
-                  MOZ_ASSERT(animator);
+              if (CompositorBridgeParent* bridge = compositor->GetCompositorBridgeParent()) {
+                AndroidDynamicToolbarAnimator* animator = bridge->GetAPZCTreeManager()->GetAndroidDynamicToolbarAnimator();
+                MOZ_ASSERT(animator);
+                if (mIsFirstPaint) {
                   animator->UpdateRootFrameMetrics(metrics);
                   animator->FirstPaint();
+                  mIsFirstPaint = false;
+                }
+                if (mLayersUpdated) {
+                  animator->NotifyLayersUpdated();
+                  mLayersUpdated = false;
+                }
+                // If this is not actually the root content then the animator is not getting updated in AsyncPanZoomController::NotifyLayersUpdated
+                // because the root content document is not scrollable. So update it here so it knows if the root composition size has changed.
+                if (!metrics.IsRootContent()) {
+                  animator->MaybeUpdateCompositionSizeAndRootFrameMetrics(metrics);
                 }
               }
-              if (mLayersUpdated) {
-                if (CompositorBridgeParent* bridge = compositor->GetCompositorBridgeParent()) {
-                  AndroidDynamicToolbarAnimator* animator = bridge->GetAPZCTreeManager()->GetAndroidDynamicToolbarAnimator();
-                  MOZ_ASSERT(animator);
-                  animator->NotifyLayersUpdated();
-                }
-                mLayersUpdated = false;
-              }
-              mIsFirstPaint = false;
               fixedLayerMargins = mFixedLayerMargins;
             }
           }
 #else
           *aOutFoundRoot = false;
           // Non-Android platforms still care about this flag being cleared after
           // the first call to TransformShadowTree().
           mIsFirstPaint = false;
--- a/gfx/layers/composite/Diagnostics.h
+++ b/gfx/layers/composite/Diagnostics.h
@@ -76,19 +76,19 @@ public:
   void AddTxnFrame() {
     mTransactionFps.AddFrame(TimeStamp::Now());
   }
 
   std::string GetFrameOverlayString(const GPUStats& aStats);
 
   class Record {
   public:
-    Record() {
+    explicit Record(TimeStamp aStart = TimeStamp()) {
       if (gfxPrefs::LayersDrawFPS()) {
-        mStart = TimeStamp::Now();
+        mStart = aStart.IsNull() ? TimeStamp::Now() : aStart;
       }
     }
     bool Recording() const {
       return !mStart.IsNull();
     }
     float Duration() const {
       return (TimeStamp::Now() - mStart).ToMilliseconds();
     }
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -914,17 +914,17 @@ LayerManagerComposite::Render(const nsIn
   if (haveLayerEffects) {
     previousTarget = PushGroupForLayerEffects();
   } else {
     mTwoPassTmpTarget = nullptr;
   }
 
   // Render our layers.
   {
-    Diagnostics::Record record;
+    Diagnostics::Record record(mRenderStartTime);
     RootLayer()->Prepare(ViewAs<RenderTargetPixel>(clipRect, PixelCastJustification::RenderTargetIsParentLayerForRoot));
     if (record.Recording()) {
       mDiagnostics->RecordPrepareTime(record.Duration());
     }
   }
   // Execute draw commands.
   {
     Diagnostics::Record record;
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -564,21 +564,24 @@ BackgroundChildImpl::DeallocPGamepadTest
   delete static_cast<dom::GamepadTestChannelChild*>(aActor);
   return true;
 }
 
 #ifdef EARLY_BETA_OR_EARLIER
 void
 BackgroundChildImpl::OnChannelReceivedMessage(const Message& aMsg)
 {
+// Telemetry collection temporarily disabled in bug 1366156.
+#if 0
   if (aMsg.type() == layout::PVsync::MessageType::Msg_Notify__ID) {
     // Not really necessary to look at the message payload, it will be
     // <0.5ms away from TimeStamp::Now()
     SchedulerGroup::MarkVsyncReceived();
   }
+#endif
 }
 #endif
 
 dom::PWebAuthnTransactionChild*
 BackgroundChildImpl::AllocPWebAuthnTransactionChild()
 {
   MOZ_CRASH("PWebAuthnTransaction actor should be manually constructed!");
   return nullptr;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "builtin/TestingFunctions.h"
 
+#include "mozilla/Atomics.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Move.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/Unused.h"
 
 #include <cmath>
 
 #include "jsapi.h"
@@ -62,21 +63,21 @@
 
 using namespace js;
 
 using mozilla::ArrayLength;
 using mozilla::Move;
 
 // If fuzzingSafe is set, remove functionality that could cause problems with
 // fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE.
-static bool fuzzingSafe = false;
+static mozilla::Atomic<bool> fuzzingSafe(false);
 
 // If disableOOMFunctions is set, disable functionality that causes artificial
 // OOM conditions.
-static bool disableOOMFunctions = false;
+static mozilla::Atomic<bool> disableOOMFunctions(false);
 
 static bool
 EnvVarIsDefined(const char* name)
 {
     const char* value = getenv(name);
     return value && *value;
 }
 
--- a/js/src/gc/GenerateStatsPhases.py
+++ b/js/src/gc/GenerateStatsPhases.py
@@ -44,16 +44,17 @@
 #    | B |   | C |   | D |
 #    +---+   +---+   +---+
 #              |       |
 #              v       v
 #            +---+   +---+
 #            | E |   | E'|
 #            +---+   +---+
 
+import re
 import sys
 import collections
 
 class PhaseKind():
     def __init__(self, name, descr, bucket, children = []):
         self.name = name
         self.descr = descr
         self.bucket = bucket
@@ -169,62 +170,66 @@ def findAllPhaseKinds():
     return phases
 
 AllPhaseKinds = findAllPhaseKinds()
 
 # Expand the DAG into a tree, duplicating phases which have more than
 # one parent.
 
 class Phase:
-    def __init__(self, phaseKind, parent, depth):
+    def __init__(self, phaseKind, parent):
         self.phaseKind = phaseKind
         self.parent = parent
-        self.depth = depth
+        self.depth = parent.depth + 1 if parent else 0
         self.children = []
         self.nextSibling = None
         self.nextInPhaseKind = None
 
+        self.path = re.sub(r'\W+', '_', phaseKind.name.lower())
+        if parent is not None:
+            self.path = parent.path + '.' + self.path
+
 def expandPhases():
     phases = []
-    phasesForPhase = collections.defaultdict(list)
+    phasesForKind = collections.defaultdict(list)
 
-    def traverse(phaseKind, parent, depth):
-        ep = Phase(phaseKind, parent, depth)
+    def traverse(phaseKind, parent):
+        ep = Phase(phaseKind, parent)
         phases.append(ep)
 
         # Update list of expanded phases for this phase kind.
-        if phasesForPhase[phaseKind]:
-            phasesForPhase[phaseKind][-1].nextInPhaseKind = ep
-        phasesForPhase[phaseKind].append(ep)
+        if phasesForKind[phaseKind]:
+            phasesForKind[phaseKind][-1].nextInPhaseKind = ep
+        phasesForKind[phaseKind].append(ep)
 
         # Recurse over children.
         for child in phaseKind.children:
-            child_ep = traverse(child, ep, depth + 1)
+            child_ep = traverse(child, ep)
             if ep.children:
                 ep.children[-1].nextSibling = child_ep
             ep.children.append(child_ep)
         return ep
 
     for phaseKind in PhaseKindGraphRoots:
-        traverse(phaseKind, None, 0)
+        traverse(phaseKind, None)
 
-    return phases, phasesForPhase
+    return phases, phasesForKind
 
 AllPhases, PhasesForPhaseKind = expandPhases()
 
-# Name expanded phases based on phase kind name and index if there are
-# multiple expanded phases corresponding to a single phase kind.
+# Name phases based on phase kind name and index if there are multiple phases
+# corresponding to a single phase kind.
 
 for phaseKind in AllPhaseKinds:
     phases = PhasesForPhaseKind[phaseKind]
     if len(phases) == 1:
         phases[0].name = "%s" % phaseKind.name
     else:
-        for index, xphase in enumerate(phases):
-            xphase.name = "%s_%d" % (phaseKind.name, index + 1)
+        for index, phase in enumerate(phases):
+            phase.name = "%s_%d" % (phaseKind.name, index + 1)
 
 # Generate code.
 
 def writeList(out, items):
     if items:
         out.write(",\n".join("  " + item for item in items) + "\n")
 
 def writeEnumClass(out, name, type, items, extraItems):
@@ -245,48 +250,49 @@ def generateHeader(out):
         "IMPLICIT_SUSPENSION"
     ]
     writeEnumClass(out, "PhaseKind", "uint8_t", phaseKindNames, extraPhaseKinds)
     out.write("\n")
 
     #
     # Generate Phase enum.
     #
-    expandedPhaseNames = map(lambda xphase: xphase.name, AllPhases)
+    phaseNames = map(lambda phase: phase.name, AllPhases)
     extraPhases = [
         "NONE = LIMIT",
         "EXPLICIT_SUSPENSION = LIMIT",
         "IMPLICIT_SUSPENSION"
     ]
-    writeEnumClass(out, "Phase", "uint8_t", expandedPhaseNames, extraPhases)
+    writeEnumClass(out, "Phase", "uint8_t", phaseNames, extraPhases)
 
 def generateCpp(out):
     #
     # Generate the PhaseKindInfo table.
     #
     out.write("static const PhaseKindTable phaseKinds = {\n")
     for phaseKind in AllPhaseKinds:
-        xPhase = PhasesForPhaseKind[phaseKind][0]
+        phase = PhasesForPhaseKind[phaseKind][0]
         out.write("    /* PhaseKind::%s */ PhaseKindInfo { Phase::%s, %d },\n" %
-                  (phaseKind.name, xPhase.name, phaseKind.bucket))
+                  (phaseKind.name, phase.name, phaseKind.bucket))
     out.write("};\n")
     out.write("\n")
 
     #
     # Generate the PhaseInfo tree.
     #
-    def name(xphase):
-        return "Phase::" + xphase.name if xphase else "Phase::NONE"
+    def name(phase):
+        return "Phase::" + phase.name if phase else "Phase::NONE"
 
     out.write("static const PhaseTable phases = {\n")
-    for xphase in AllPhases:
-        firstChild = xphase.children[0] if xphase.children else None
-        phaseKind = xphase.phaseKind
-        out.write("    /* %s */ PhaseInfo { %s, %s, %s, %s, PhaseKind::%s, %d, \"%s\" },\n" %
-                  (name(xphase),
-                   name(xphase.parent),
+    for phase in AllPhases:
+        firstChild = phase.children[0] if phase.children else None
+        phaseKind = phase.phaseKind
+        out.write("    /* %s */ PhaseInfo { %s, %s, %s, %s, PhaseKind::%s, %d, \"%s\", \"%s\" },\n" %
+                  (name(phase),
+                   name(phase.parent),
                    name(firstChild),
-                   name(xphase.nextSibling),
-                   name(xphase.nextInPhaseKind),
+                   name(phase.nextSibling),
+                   name(phase.nextInPhaseKind),
                    phaseKind.name,
-                   xphase.depth,
-                   phaseKind.descr))
+                   phase.depth,
+                   phaseKind.descr,
+                   phase.path))
     out.write("};\n")
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -102,22 +102,23 @@ struct PhaseInfo
 {
     Phase parent;
     Phase firstChild;
     Phase nextSibling;
     Phase nextInPhase;
     PhaseKind phaseKind;
     uint8_t depth;
     const char* name;
+    const char* path;
 };
 
-// A table of ExpandePhaseInfo indexed by Phase.
+// A table of PhaseInfo indexed by Phase.
 using PhaseTable = EnumeratedArray<Phase, Phase::LIMIT, PhaseInfo>;
 
-// A table of PhaseKindInfo indexed by Phase.
+// A table of PhaseKindInfo indexed by PhaseKind.
 using PhaseKindTable = EnumeratedArray<PhaseKind, PhaseKind::LIMIT, PhaseKindInfo>;
 
 #include "gc/StatsPhasesGenerated.cpp"
 
 static double
 t(TimeDuration duration)
 {
     return duration.ToMilliseconds();
@@ -127,18 +128,18 @@ Phase
 Statistics::currentPhase() const
 {
     return phaseNestingDepth ? phaseNesting[phaseNestingDepth - 1] : Phase::NONE;
 }
 
 PhaseKind
 Statistics::currentPhaseKind() const
 {
-    // Public API to get the current phase.  Return the current phase,
-    // suppressing the synthetic PhaseKind::MUTATOR phase.
+    // Public API to get the current phase kind, suppressing the synthetic
+    // PhaseKind::MUTATOR phase.
 
     Phase phase = currentPhase();
     MOZ_ASSERT_IF(phase == Phase::MUTATOR, phaseNestingDepth == 1);
     if (phase == Phase::NONE || phase == Phase::MUTATOR)
         return PhaseKind::NONE;
 
     return phases[phase].phaseKind;
 }
@@ -616,45 +617,23 @@ Statistics::formatJsonSliceDescription(u
     json.property("initial_state", gc::StateName(slice.initialState));
     json.property("final_state", gc::StateName(slice.finalState));
     json.property("budget", budgetDescription);
     json.property("page_faults", int64_t(slice.endFaults - slice.startFaults));
     json.property("start_timestamp", slice.start - originTime, JSONPrinter::SECONDS);
     json.property("end_timestamp", slice.end - originTime, JSONPrinter::SECONDS);
 }
 
-static UniqueChars
-SanitizeJsonKey(const char* const buffer)
-{
-    char* mut = strdup(buffer);
-    if (!mut)
-        return UniqueChars(nullptr);
-
-    char* c = mut;
-    while (*c) {
-        if (!isalpha(*c))
-            *c = '_';
-        else if (isupper(*c))
-            *c = tolower(*c);
-        ++c;
-    }
-
-    return UniqueChars(mut);
-}
-
 void
 Statistics::formatJsonPhaseTimes(const PhaseTimeTable& phaseTimes, JSONPrinter& json) const
 {
     for (auto phase : AllPhases()) {
-        UniqueChars name = SanitizeJsonKey(phases[phase].name);
-        if (!name)
-            json.outOfMemory();
         TimeDuration ownTime = phaseTimes[phase];
         if (!ownTime.IsZero())
-            json.property(name.get(), ownTime, JSONPrinter::MILLISECONDS);
+            json.property(phases[phase].path, ownTime, JSONPrinter::MILLISECONDS);
     }
 }
 
 Statistics::Statistics(JSRuntime* rt)
   : runtime(rt),
     fp(nullptr),
     nonincrementalReason_(gc::AbortReason::None),
     preBytes(0),
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11432,16 +11432,21 @@ CodeGenerator::visitGetDOMProperty(LGetD
     const Register ValueReg = ToRegister(ins->getValueReg());
 
     Label haveValue;
     if (ins->mir()->valueMayBeInSlot()) {
         size_t slot = ins->mir()->domMemberSlotIndex();
         // It's a bit annoying to redo these slot calculations, which duplcate
         // LSlots and a few other things like that, but I'm not sure there's a
         // way to reuse those here.
+        //
+        // If this ever gets fixed to work with proxies (by not assuming that
+        // reserved slot indices, which is what domMemberSlotIndex() returns,
+        // match fixed slot indices), we can reenable MGetDOMProperty for
+        // proxies in IonBuilder.
         if (slot < NativeObject::MAX_FIXED_SLOTS) {
             masm.loadValue(Address(ObjectReg, NativeObject::getFixedSlotOffset(slot)),
                            JSReturnOperand);
         } else {
             // It's a dynamic slot.
             slot -= NativeObject::MAX_FIXED_SLOTS;
             // Use PrivateReg as a scratch register for the slots pointer.
             masm.loadPtr(Address(ObjectReg, NativeObject::offsetOfSlots()),
@@ -11504,31 +11509,41 @@ CodeGenerator::visitGetDOMProperty(LGetD
 void
 CodeGenerator::visitGetDOMMemberV(LGetDOMMemberV* ins)
 {
     // It's simpler to duplicate visitLoadFixedSlotV here than it is to try to
     // use an LLoadFixedSlotV or some subclass of it for this case: that would
     // require us to have MGetDOMMember inherit from MLoadFixedSlot, and then
     // we'd have to duplicate a bunch of stuff we now get for free from
     // MGetDOMProperty.
+    //
+    // If this ever gets fixed to work with proxies (by not assuming that
+    // reserved slot indices, which is what domMemberSlotIndex() returns,
+    // match fixed slot indices), we can reenable MGetDOMMember for
+    // proxies in IonBuilder.
     Register object = ToRegister(ins->object());
     size_t slot = ins->mir()->domMemberSlotIndex();
     ValueOperand result = GetValueOutput(ins);
 
     masm.loadValue(Address(object, NativeObject::getFixedSlotOffset(slot)), result);
 }
 
 void
 CodeGenerator::visitGetDOMMemberT(LGetDOMMemberT* ins)
 {
     // It's simpler to duplicate visitLoadFixedSlotT here than it is to try to
     // use an LLoadFixedSlotT or some subclass of it for this case: that would
     // require us to have MGetDOMMember inherit from MLoadFixedSlot, and then
     // we'd have to duplicate a bunch of stuff we now get for free from
     // MGetDOMProperty.
+    //
+    // If this ever gets fixed to work with proxies (by not assuming that
+    // reserved slot indices, which is what domMemberSlotIndex() returns,
+    // match fixed slot indices), we can reenable MGetDOMMember for
+    // proxies in IonBuilder.
     Register object = ToRegister(ins->object());
     size_t slot = ins->mir()->domMemberSlotIndex();
     AnyRegister result = ToAnyRegister(ins->getDef(0));
     MIRType type = ins->mir()->type();
 
     masm.loadUnboxedValue(Address(object, NativeObject::getFixedSlotOffset(slot)), type, result);
 }
 
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -10876,48 +10876,57 @@ IonBuilder::getPropTryCommonGetter(bool*
     }
 
     bool isDOM = objTypes && objTypes->isDOMClass(constraints());
     if (isDOM)
         MOZ_TRY_VAR(isDOM, testShouldDOMCall(objTypes, commonGetter, JSJitInfo::Getter));
 
     if (isDOM) {
         const JSJitInfo* jitinfo = commonGetter->jitInfo();
-        MInstruction* get;
-        if (jitinfo->isAlwaysInSlot) {
-            // If our object is a singleton and we know the property is
-            // constant (which is true if and only if the get doesn't alias
-            // anything), we can just read the slot here and use that constant.
-            JSObject* singleton = objTypes->maybeSingleton();
-            if (singleton && jitinfo->aliasSet() == JSJitInfo::AliasNone) {
-                size_t slot = jitinfo->slotIndex;
-                *emitted = true;
-                pushConstant(GetReservedSlot(singleton, slot));
-                return Ok();
+        // We don't support MGetDOMProperty/MGetDOMMember on things that might
+        // be proxies when the value might be in a slot, because the
+        // CodeGenerator code for LGetDOMProperty/LGetDOMMember doesn't handle
+        // that case correctly.
+        if ((!jitinfo->isAlwaysInSlot && !jitinfo->isLazilyCachedInSlot) ||
+            !objTypes->maybeProxy(constraints())) {
+            MInstruction* get;
+            if (jitinfo->isAlwaysInSlot) {
+                // If our object is a singleton and we know the property is
+                // constant (which is true if and only if the get doesn't alias
+                // anything), we can just read the slot here and use that
+                // constant.
+                JSObject* singleton = objTypes->maybeSingleton();
+                if (singleton && jitinfo->aliasSet() == JSJitInfo::AliasNone) {
+                    size_t slot = jitinfo->slotIndex;
+                    *emitted = true;
+                    pushConstant(GetReservedSlot(singleton, slot));
+                    return Ok();
+                }
+
+                // We can't use MLoadFixedSlot here because it might not have
+                // the right aliasing behavior; we want to alias DOM setters as
+                // needed.
+                get = MGetDOMMember::New(alloc(), jitinfo, obj, guard, globalGuard);
+            } else {
+                get = MGetDOMProperty::New(alloc(), jitinfo, obj, guard, globalGuard);
             }
-
-            // We can't use MLoadFixedSlot here because it might not have the
-            // right aliasing behavior; we want to alias DOM setters as needed.
-            get = MGetDOMMember::New(alloc(), jitinfo, obj, guard, globalGuard);
-        } else {
-            get = MGetDOMProperty::New(alloc(), jitinfo, obj, guard, globalGuard);
-        }
-        if (!get)
-            return abort(AbortReason::Alloc);
-        current->add(get);
-        current->push(get);
-
-        if (get->isEffectful())
-            MOZ_TRY(resumeAfter(get));
-
-        MOZ_TRY(pushDOMTypeBarrier(get, types, commonGetter));
-
-        trackOptimizationOutcome(TrackedOutcome::DOM);
-        *emitted = true;
-        return Ok();
+            if (!get)
+                return abort(AbortReason::Alloc);
+            current->add(get);
+            current->push(get);
+
+            if (get->isEffectful())
+                MOZ_TRY(resumeAfter(get));
+
+            MOZ_TRY(pushDOMTypeBarrier(get, types, commonGetter));
+
+            trackOptimizationOutcome(TrackedOutcome::DOM);
+            *emitted = true;
+            return Ok();
+        }
     }
 
     // Don't call the getter with a primitive value.
     if (obj->type() != MIRType::Object) {
         MGuardObject* guardObj = MGuardObject::New(alloc(), obj);
         current->add(guardObj);
         obj = guardObj;
     }
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -40,19 +40,16 @@
 # define PATH_MAX (MAX_PATH > _MAX_DIR ? MAX_PATH : _MAX_DIR)
 # define getcwd _getcwd
 #else
 # include <libgen.h>
 #endif
 
 using js::shell::RCFile;
 
-static RCFile** gErrFilePtr = nullptr;
-static RCFile** gOutFilePtr = nullptr;
-
 namespace js {
 namespace shell {
 
 #ifdef XP_WIN
 const char PathSeparator = '\\';
 #else
 const char PathSeparator = '/';
 #endif
@@ -550,23 +547,25 @@ Redirect(JSContext* cx, const CallArgs& 
 
     args.rval().setObject(*oldFileObj);
     return true;
 }
 
 static bool
 osfile_redirectOutput(JSContext* cx, unsigned argc, Value* vp) {
     CallArgs args = CallArgsFromVp(argc, vp);
-    return Redirect(cx, args, gOutFilePtr);
+    ShellContext* scx = GetShellContext(cx);
+    return Redirect(cx, args, scx->outFilePtr);
 }
 
 static bool
 osfile_redirectError(JSContext* cx, unsigned argc, Value* vp) {
     CallArgs args = CallArgsFromVp(argc, vp);
-    return Redirect(cx, args, gErrFilePtr);
+    ShellContext* scx = GetShellContext(cx);
+    return Redirect(cx, args, scx->errFilePtr);
 }
 
 static bool
 osfile_close(JSContext* cx, unsigned argc, Value* vp) {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     Rooted<FileObject*> fileObj(cx);
     if (args.get(0).isObject()) {
@@ -1005,18 +1004,19 @@ DefineOS(JSContext* cx, HandleObject glo
         !GenerateInterfaceHelp(cx, ospath, "os.path"))
     {
         return false;
     }
 
     if (!GenerateInterfaceHelp(cx, obj, "os"))
         return false;
 
-    gOutFilePtr = shellOut;
-    gErrFilePtr = shellErr;
+    ShellContext* scx = GetShellContext(cx);
+    scx->outFilePtr = shellOut;
+    scx->errFilePtr = shellErr;
 
     // For backwards compatibility, expose various os.file.* functions as
     // direct methods on the global.
     struct Export {
         const char* src;
         const char* dst;
     };
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -108,16 +108,18 @@
 #include "vm/ErrorObject-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::cli;
 using namespace js::shell;
 
+using js::shell::RCFile;
+
 using mozilla::ArrayLength;
 using mozilla::Atomic;
 using mozilla::MakeScopeExit;
 using mozilla::Maybe;
 using mozilla::Nothing;
 using mozilla::NumberEqualsInt32;
 using mozilla::PodCopy;
 using mozilla::PodEqual;
@@ -147,199 +149,107 @@ static const size_t gMaxStackSize = 128 
  * Limit the timeout to 30 minutes to prevent an overflow on platfoms
  * that represent the time internally in microseconds using 32-bit int.
  */
 static const TimeDuration MAX_TIMEOUT_INTERVAL = TimeDuration::FromSeconds(1800.0);
 
 // SharedArrayBuffer and Atomics are enabled by default (tracking Firefox).
 #define SHARED_MEMORY_DEFAULT 1
 
-// Some platform hooks must be implemented for single-step profiling.
-#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS64)
-# define SINGLESTEP_PROFILING
-#endif
-
-enum class ScriptKind
-{
-    Script,
-    DecodeScript,
-    Module
-};
-
-class OffThreadState {
-    enum State {
-        IDLE,           /* ready to work; no token, no source */
-        COMPILING,      /* working; no token, have source */
-        DONE            /* compilation done: have token and source */
-    };
-
-  public:
-    OffThreadState()
-      : monitor(mutexid::ShellOffThreadState),
-        state(IDLE),
-        token(),
-        source(nullptr)
-    { }
-
-    bool startIfIdle(JSContext* cx, ScriptKind kind,
-                     ScopedJSFreePtr<char16_t>& newSource)
-    {
-        AutoLockMonitor alm(monitor);
-        if (state != IDLE)
-            return false;
-
-        MOZ_ASSERT(!token);
-
-        source = newSource.forget();
-
-        scriptKind = kind;
-        state = COMPILING;
-        return true;
-    }
-
-    bool startIfIdle(JSContext* cx, ScriptKind kind,
-                     JS::TranscodeBuffer&& newXdr)
-    {
-        AutoLockMonitor alm(monitor);
-        if (state != IDLE)
-            return false;
-
-        MOZ_ASSERT(!token);
-
-        xdr = mozilla::Move(newXdr);
-
-        scriptKind = kind;
-        state = COMPILING;
-        return true;
-    }
-
-    void abandon(JSContext* cx) {
-        AutoLockMonitor alm(monitor);
-        MOZ_ASSERT(state == COMPILING);
-        MOZ_ASSERT(!token);
-        MOZ_ASSERT(source || !xdr.empty());
-
-        if (source)
-            js_free(source);
-        source = nullptr;
-        xdr.clearAndFree();
-
-        state = IDLE;
-    }
-
-    void markDone(void* newToken) {
-        AutoLockMonitor alm(monitor);
-        MOZ_ASSERT(state == COMPILING);
-        MOZ_ASSERT(!token);
-        MOZ_ASSERT(source || !xdr.empty());
-        MOZ_ASSERT(newToken);
-
-        token = newToken;
-        state = DONE;
-        alm.notify();
-    }
-
-    void* waitUntilDone(JSContext* cx, ScriptKind kind) {
-        AutoLockMonitor alm(monitor);
-        if (state == IDLE || scriptKind != kind)
-            return nullptr;
-
-        if (state == COMPILING) {
-            while (state != DONE)
-                alm.wait();
-        }
-
-        MOZ_ASSERT(source || !xdr.empty());
-        if (source)
-            js_free(source);
-        source = nullptr;
-        xdr.clearAndFree();
-
-        MOZ_ASSERT(token);
-        void* holdToken = token;
-        token = nullptr;
-        state = IDLE;
-        return holdToken;
-    }
-
-    JS::TranscodeBuffer& xdrBuffer() { return xdr; }
-
-  private:
-    Monitor monitor;
-    ScriptKind scriptKind;
-    State state;
-    void* token;
-    char16_t* source;
-    JS::TranscodeBuffer xdr;
-};
-
-#ifdef SINGLESTEP_PROFILING
-typedef Vector<char16_t, 0, SystemAllocPolicy> StackChars;
-#endif
-
-class NonshrinkingGCObjectVector : public GCVector<JSObject*, 0, SystemAllocPolicy>
-{
-  public:
-    void sweep() {
-        for (uint32_t i = 0; i < this->length(); i++) {
-            if (JS::GCPolicy<JSObject*>::needsSweep(&(*this)[i]))
-                (*this)[i] = nullptr;
-        }
-    }
-};
-
-using MarkBitObservers = JS::WeakCache<NonshrinkingGCObjectVector>;
+bool
+OffThreadState::startIfIdle(JSContext* cx, ScriptKind kind, ScopedJSFreePtr<char16_t>& newSource)
+{
+    AutoLockMonitor alm(monitor);
+    if (state != IDLE)
+        return false;
+
+    MOZ_ASSERT(!token);
+
+    source = newSource.forget();
+
+    scriptKind = kind;
+    state = COMPILING;
+    return true;
+}
+
+bool
+OffThreadState::startIfIdle(JSContext* cx, ScriptKind kind, JS::TranscodeBuffer&& newXdr)
+{
+    AutoLockMonitor alm(monitor);
+    if (state != IDLE)
+        return false;
+
+    MOZ_ASSERT(!token);
+
+    xdr = mozilla::Move(newXdr);
+
+    scriptKind = kind;
+    state = COMPILING;
+    return true;
+}
+
+void
+OffThreadState::abandon(JSContext* cx)
+{
+    AutoLockMonitor alm(monitor);
+    MOZ_ASSERT(state == COMPILING);
+    MOZ_ASSERT(!token);
+    MOZ_ASSERT(source || !xdr.empty());
+
+    if (source)
+        js_free(source);
+    source = nullptr;
+    xdr.clearAndFree();
+
+    state = IDLE;
+}
+
+void
+OffThreadState::markDone(void* newToken)
+{
+    AutoLockMonitor alm(monitor);
+    MOZ_ASSERT(state == COMPILING);
+    MOZ_ASSERT(!token);
+    MOZ_ASSERT(source || !xdr.empty());
+    MOZ_ASSERT(newToken);
+
+    token = newToken;
+    state = DONE;
+    alm.notify();
+}
+
+void*
+OffThreadState::waitUntilDone(JSContext* cx, ScriptKind kind)
+{
+    AutoLockMonitor alm(monitor);
+    if (state == IDLE || scriptKind != kind)
+        return nullptr;
+
+    if (state == COMPILING) {
+        while (state != DONE)
+            alm.wait();
+    }
+
+    MOZ_ASSERT(source || !xdr.empty());
+    if (source)
+        js_free(source);
+    source = nullptr;
+    xdr.clearAndFree();
+
+    MOZ_ASSERT(token);
+    void* holdToken = token;
+    token = nullptr;
+    state = IDLE;
+    return holdToken;
+}
 
 struct ShellCompartmentPrivate {
     JS::Heap<JSObject*> grayRoot;
 };
 
-// Per-context shell state.
-struct ShellContext
-{
-    explicit ShellContext(JSContext* cx);
-    bool isWorker;
-    double timeoutInterval;
-    double startTime;
-    Atomic<bool> serviceInterrupt;
-    Atomic<bool> haveInterruptFunc;
-    JS::PersistentRootedValue interruptFunc;
-    bool lastWarningEnabled;
-    JS::PersistentRootedValue lastWarning;
-    JS::PersistentRootedValue promiseRejectionTrackerCallback;
-#ifdef SINGLESTEP_PROFILING
-    Vector<StackChars, 0, SystemAllocPolicy> stacks;
-#endif
-
-    /*
-     * Watchdog thread state.
-     */
-    Mutex watchdogLock;
-    ConditionVariable watchdogWakeup;
-    Maybe<Thread> watchdogThread;
-    Maybe<TimeStamp> watchdogTimeout;
-
-    ConditionVariable sleepWakeup;
-
-    int exitCode;
-    bool quitting;
-
-    UniqueChars readLineBuf;
-    size_t readLineBufPos;
-
-    static const uint32_t GeckoProfilingMaxStackSize = 1000;
-    ProfileEntry geckoProfilingStack[GeckoProfilingMaxStackSize];
-    mozilla::Atomic<uint32_t> geckoProfilingStackSize;
-
-    OffThreadState offThreadState;
-
-    UniqueChars moduleLoadPath;
-    UniquePtr<MarkBitObservers> markObservers;
-};
-
 struct MOZ_STACK_CLASS EnvironmentPreparer : public js::ScriptEnvironmentPreparer {
     JSContext* cx;
     explicit EnvironmentPreparer(JSContext* cx)
       : cx(cx)
     {
         js::SetScriptEnvironmentPreparer(cx, this);
     }
     void invoke(JS::HandleObject scope, Closure& closure) override;
@@ -471,21 +381,23 @@ ShellContext::ShellContext(JSContext* cx
     interruptFunc(cx, NullValue()),
     lastWarningEnabled(false),
     lastWarning(cx, NullValue()),
     promiseRejectionTrackerCallback(cx, NullValue()),
     watchdogLock(mutexid::ShellContextWatchdog),
     exitCode(0),
     quitting(false),
     readLineBufPos(0),
+    errFilePtr(nullptr),
+    outFilePtr(nullptr),
     geckoProfilingStackSize(0)
 {}
 
-static ShellContext*
-GetShellContext(JSContext* cx)
+ShellContext*
+js::shell::GetShellContext(JSContext* cx)
 {
     ShellContext* sc = static_cast<ShellContext*>(JS_GetContextPrivate(cx));
     MOZ_ASSERT(sc);
     return sc;
 }
 
 static void
 TraceGrayRoots(JSTracer* trc, void* data)
--- a/js/src/shell/jsshell.h
+++ b/js/src/shell/jsshell.h
@@ -2,18 +2,35 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jsshell_js_h
 #define jsshell_js_h
 
+#include "mozilla/Atomics.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/TimeStamp.h"
+
 #include "jsapi.h"
 
+#include "js/GCVector.h"
+#include "threading/ConditionVariable.h"
+#include "threading/LockGuard.h"
+#include "threading/Mutex.h"
+#include "threading/Thread.h"
+#include "vm/GeckoProfiler.h"
+#include "vm/Monitor.h"
+
+// Some platform hooks must be implemented for single-step profiling.
+#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS64)
+# define SINGLESTEP_PROFILING
+#endif
+
 namespace js {
 namespace shell {
 
 enum JSShellErrNum {
 #define MSG_DEF(name, count, exception, format) \
     name,
 #include "jsshell.msg"
 #undef MSG_DEF
@@ -85,12 +102,121 @@ struct RCFile {
 //   snarf = os.file.readFile;
 //
 // This provides a mechanism for namespacing the various JS shell helper
 // functions without breaking backwards compatibility with things that use the
 // global names.
 bool
 CreateAlias(JSContext* cx, const char* dstName, JS::HandleObject namespaceObj, const char* srcName);
 
+enum class ScriptKind
+{
+    Script,
+    DecodeScript,
+    Module
+};
+
+class OffThreadState {
+    enum State {
+        IDLE,           /* ready to work; no token, no source */
+        COMPILING,      /* working; no token, have source */
+        DONE            /* compilation done: have token and source */
+    };
+
+  public:
+    OffThreadState()
+      : monitor(mutexid::ShellOffThreadState),
+        state(IDLE),
+        token(),
+        source(nullptr)
+    { }
+
+    bool startIfIdle(JSContext* cx, ScriptKind kind, ScopedJSFreePtr<char16_t>& newSource);
+
+    bool startIfIdle(JSContext* cx, ScriptKind kind, JS::TranscodeBuffer&& newXdr);
+
+    void abandon(JSContext* cx);
+
+    void markDone(void* newToken);
+
+    void* waitUntilDone(JSContext* cx, ScriptKind kind);
+
+    JS::TranscodeBuffer& xdrBuffer() { return xdr; }
+
+  private:
+    js::Monitor monitor;
+    ScriptKind scriptKind;
+    State state;
+    void* token;
+    char16_t* source;
+    JS::TranscodeBuffer xdr;
+};
+
+class NonshrinkingGCObjectVector : public GCVector<JSObject*, 0, SystemAllocPolicy>
+{
+  public:
+    void sweep() {
+        for (uint32_t i = 0; i < this->length(); i++) {
+            if (JS::GCPolicy<JSObject*>::needsSweep(&(*this)[i]))
+                (*this)[i] = nullptr;
+        }
+    }
+};
+
+using MarkBitObservers = JS::WeakCache<NonshrinkingGCObjectVector>;
+
+#ifdef SINGLESTEP_PROFILING
+using StackChars = Vector<char16_t, 0, SystemAllocPolicy>;
+#endif
+
+// Per-context shell state.
+struct ShellContext
+{
+    explicit ShellContext(JSContext* cx);
+    bool isWorker;
+    double timeoutInterval;
+    double startTime;
+    mozilla::Atomic<bool> serviceInterrupt;
+    mozilla::Atomic<bool> haveInterruptFunc;
+    JS::PersistentRootedValue interruptFunc;
+    bool lastWarningEnabled;
+    JS::PersistentRootedValue lastWarning;
+    JS::PersistentRootedValue promiseRejectionTrackerCallback;
+#ifdef SINGLESTEP_PROFILING
+    Vector<StackChars, 0, SystemAllocPolicy> stacks;
+#endif
+
+    /*
+     * Watchdog thread state.
+     */
+    js::Mutex watchdogLock;
+    js::ConditionVariable watchdogWakeup;
+    mozilla::Maybe<js::Thread> watchdogThread;
+    mozilla::Maybe<mozilla::TimeStamp> watchdogTimeout;
+
+    js::ConditionVariable sleepWakeup;
+
+    int exitCode;
+    bool quitting;
+
+    JS::UniqueChars readLineBuf;
+    size_t readLineBufPos;
+
+    js::shell::RCFile** errFilePtr;
+    js::shell::RCFile** outFilePtr;
+
+    static const uint32_t GeckoProfilingMaxStackSize = 1000;
+    js::ProfileEntry geckoProfilingStack[GeckoProfilingMaxStackSize];
+    mozilla::Atomic<uint32_t> geckoProfilingStackSize;
+
+    OffThreadState offThreadState;
+
+    JS::UniqueChars moduleLoadPath;
+    UniquePtr<MarkBitObservers> markObservers;
+};
+
+extern ShellContext*
+GetShellContext(JSContext* cx);
+
 } /* namespace shell */
 } /* namespace js */
 
 #endif
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -2405,16 +2405,37 @@ TemporaryTypeSet::maybeCallable(Compiler
         if (!getObject(i)->hasStableClassAndProto(constraints))
             return true;
     }
 
     return false;
 }
 
 bool
+TemporaryTypeSet::maybeProxy(CompilerConstraintList* constraints)
+{
+    if (!maybeObject())
+        return false;
+
+    if (unknownObject())
+        return true;
+
+    unsigned count = getObjectCount();
+    for (unsigned i = 0; i < count; i++) {
+        const Class* clasp = getObjectClass(i);
+        if (!clasp)
+            continue;
+        if (clasp->isProxy() || !getObject(i)->hasStableClassAndProto(constraints))
+            return true;
+    }
+
+    return false;
+}
+
+bool
 TemporaryTypeSet::maybeEmulatesUndefined(CompilerConstraintList* constraints)
 {
     if (!maybeObject())
         return false;
 
     if (unknownObject())
         return true;
 
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -824,16 +824,19 @@ class TemporaryTypeSet : public TypeSet
                                    TypedArraySharedness* sharedness = nullptr);
 
     /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */
     bool isDOMClass(CompilerConstraintList* constraints);
 
     /* Whether clasp->isCallable() is true for one or more objects in this set. */
     bool maybeCallable(CompilerConstraintList* constraints);
 
+    /* Whether clasp->isProxy() might be true for one or more objects in this set. */
+    bool maybeProxy(CompilerConstraintList* constraints);
+
     /* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */
     bool maybeEmulatesUndefined(CompilerConstraintList* constraints);
 
     /* Get the single value which can appear in this type set, otherwise nullptr. */
     JSObject* maybeSingleton();
     ObjectKey* maybeSingleObject();
 
     /* Whether any objects in the type set needs a barrier on id. */
--- a/js/xpconnect/loader/ScriptPreloader.cpp
+++ b/js/xpconnect/loader/ScriptPreloader.cpp
@@ -28,17 +28,17 @@
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "xpcpublic.h"
 
 #define DELAYED_STARTUP_TOPIC "browser-delayed-startup-finished"
 #define DOC_ELEM_INSERTED_TOPIC "document-element-inserted"
 #define CLEANUP_TOPIC "xpcom-shutdown"
 #define SHUTDOWN_TOPIC "quit-application-granted"
-#define CACHE_FLUSH_TOPIC "startupcache-invalidate"
+#define CACHE_INVALIDATE_TOPIC "startupcache-invalidate"
 
 namespace mozilla {
 namespace {
 static LazyLogModule gLog("ScriptPreloader");
 
 #define LOG(level, ...) MOZ_LOG(gLog, LogLevel::level, (__VA_ARGS__))
 }
 
@@ -158,17 +158,19 @@ ScriptPreloader::InitContentChild(Conten
     // that process type is not included in the next session's cache. This
     // should be a sufficiently rare occurrence that it's not worth trying to
     // handle specially.
     auto processType = GetChildProcessType(parent.GetRemoteType());
     bool wantScriptData = !cache.mInitializedProcesses.contains(processType);
     cache.mInitializedProcesses += processType;
 
     auto fd = cache.mCacheData.cloneFileDescriptor();
-    if (fd.IsValid()) {
+    // Don't send original cache data to new processes if the cache has been
+    // invalidated.
+    if (fd.IsValid() && !cache.mCacheInvalidated) {
         Unused << parent.SendPScriptCacheConstructor(fd, wantScriptData);
     } else {
         Unused << parent.SendPScriptCacheConstructor(NS_ERROR_FILE_NOT_FOUND, wantScriptData);
     }
 }
 
 ProcessType
 ScriptPreloader::GetChildProcessType(const nsAString& remoteType)
@@ -222,17 +224,17 @@ ScriptPreloader::ScriptPreloader()
         // In the child process, we need to freeze the script cache before any
         // untrusted code has been executed. The insertion of the first DOM
         // document element may sometimes be earlier than is ideal, but at
         // least it should always be safe.
         obs->AddObserver(this, DOC_ELEM_INSERTED_TOPIC, false);
     }
     obs->AddObserver(this, SHUTDOWN_TOPIC, false);
     obs->AddObserver(this, CLEANUP_TOPIC, false);
-    obs->AddObserver(this, CACHE_FLUSH_TOPIC, false);
+    obs->AddObserver(this, CACHE_INVALIDATE_TOPIC, false);
 
     AutoSafeJSAPI jsapi;
     JS_AddExtraGCRootsTracer(jsapi.cx(), TraceOp, this);
 }
 
 void
 ScriptPreloader::ForceWriteCacheFile()
 {
@@ -260,20 +262,22 @@ ScriptPreloader::Cleanup()
 
     AutoSafeJSAPI jsapi;
     JS_RemoveExtraGCRootsTracer(jsapi.cx(), TraceOp, this);
 
     UnregisterWeakMemoryReporter(this);
 }
 
 void
-ScriptPreloader::FlushCache()
+ScriptPreloader::InvalidateCache()
 {
     MonitorAutoLock mal(mMonitor);
 
+    mCacheInvalidated = true;
+
     for (auto& script : IterHash(mScripts)) {
         // We can only purge finished scripts here. Async scripts that are
         // still being parsed off-thread have a non-refcounted reference to
         // this script, which needs to stay alive until they finish parsing.
         if (script->mReadyToExecute) {
             script->Cancel();
             script.Remove();
         }
@@ -316,18 +320,18 @@ ScriptPreloader::Observe(nsISupports* su
 
         if (mChildActor) {
             mChildActor->SendScriptsAndFinalize(mScripts);
         }
     } else if (!strcmp(topic, SHUTDOWN_TOPIC)) {
         ForceWriteCacheFile();
     } else if (!strcmp(topic, CLEANUP_TOPIC)) {
         Cleanup();
-    } else if (!strcmp(topic, CACHE_FLUSH_TOPIC)) {
-        FlushCache();
+    } else if (!strcmp(topic, CACHE_INVALIDATE_TOPIC)) {
+        InvalidateCache();
     }
 
     return NS_OK;
 }
 
 
 Result<nsCOMPtr<nsIFile>, nsresult>
 ScriptPreloader::GetCacheFile(const nsAString& suffix)
@@ -719,16 +723,31 @@ ScriptPreloader::NoteScript(const nsCStr
             script->mSize = xdrData.Length();
             script->mXDRData.construct<nsTArray<uint8_t>>(Forward<nsTArray<uint8_t>>(xdrData));
 
             auto& data = script->Array();
             script->mXDRRange.emplace(data.Elements(), data.Length());
         }
     }
 
+    if (!script->mSize && !script->mScript) {
+        // If the content process is sending us a script entry for a script
+        // which was in the cache at startup, it expects us to already have this
+        // script data, so it doesn't send it.
+        //
+        // However, the cache may have been invalidated at this point (usually
+        // due to the add-on manager installing or uninstalling a legacy
+        // extension during very early startup), which means we may no longer
+        // have an entry for this script. Since that means we have no data to
+        // write to the new cache, and no JSScript to generate it from, we need
+        // to discard this entry.
+        mScripts.Remove(cachePath);
+        return;
+    }
+
     script->UpdateLoadTime(loadTime);
     script->mProcessTypes += processType;
 }
 
 JSScript*
 ScriptPreloader::GetCachedScript(JSContext* cx, const nsCString& path)
 {
     // If a script is used by both the parent and the child, it's stored only
--- a/js/xpconnect/loader/ScriptPreloader.h
+++ b/js/xpconnect/loader/ScriptPreloader.h
@@ -345,17 +345,17 @@ private:
     // thread for quite as long.
     static constexpr int MAX_MAINTHREAD_DECODE_SIZE = 50 * 1024;
 
     ScriptPreloader();
 
     void ForceWriteCacheFile();
     void Cleanup();
 
-    void FlushCache();
+    void InvalidateCache();
 
     // Opens the cache file for reading.
     Result<Ok, nsresult> OpenCache();
 
     // Writes a new cache file to disk. Must not be called on the main thread.
     Result<Ok, nsresult> WriteCache();
 
     // Prepares scripts for writing to the cache, serializing new scripts to
@@ -399,16 +399,17 @@ private:
 
     // True after we've shown the first window, and are no longer adding new
     // scripts to the cache.
     bool mStartupFinished = false;
 
     bool mCacheInitialized = false;
     bool mSaveComplete = false;
     bool mDataPrepared = false;
+    bool mCacheInvalidated = false;
 
     // The process type of the current process.
     static ProcessType sProcessType;
 
     // The process types for which remote processes have been initialized, and
     // are expected to send back script data.
     EnumSet<ProcessType> mInitializedProcesses{};
 
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -1703,17 +1703,25 @@ public class BrowserApp extends GeckoApp
 
     @Override
     public boolean isToolbarChromeVisible() {
        return mBrowserChrome.getVisibility() == View.VISIBLE;
     }
 
     @Override
     public void toggleToolbarChrome(final boolean aShow) {
-        toggleChrome(aShow);
+        if (aShow) {
+            mBrowserChrome.setVisibility(View.VISIBLE);
+        } else {
+            // The chrome needs to be INVISIBLE instead of GONE so that
+            // it will continue update when the layout changes. This
+            // ensures the bitmap generated for the static toolbar
+            // snapshot is the correct size.
+            mBrowserChrome.setVisibility(View.INVISIBLE);
+        }
     }
 
     public void refreshToolbarHeight() {
         ThreadUtils.assertOnUiThread();
 
         int height = 0;
         if (mBrowserChrome != null) {
             height = mBrowserChrome.getHeight();
@@ -1725,32 +1733,27 @@ public class BrowserApp extends GeckoApp
             mToolbarHeight = height;
             mLayerView.setMaxToolbarHeight(height);
             mDynamicToolbar.setVisible(true, VisibilityTransition.IMMEDIATE);
         }
     }
 
     @Override
     void toggleChrome(final boolean aShow) {
-        if (aShow) {
-            mBrowserChrome.setVisibility(View.VISIBLE);
-        } else {
-            // The chrome needs to be INVISIBLE instead of GONE so that
-            // it will continue update when the layout changes. This
-            // ensures the bitmap generated for the static toolbar
-            // snapshot is the correct size.
-            mBrowserChrome.setVisibility(View.INVISIBLE);
+        if (mDynamicToolbar != null) {
+            mDynamicToolbar.setVisible(aShow, VisibilityTransition.IMMEDIATE);
         }
-
         super.toggleChrome(aShow);
     }
 
     @Override
     void focusChrome() {
-        mBrowserChrome.setVisibility(View.VISIBLE);
+        if (mDynamicToolbar != null) {
+            mDynamicToolbar.setVisible(true, VisibilityTransition.IMMEDIATE);
+        }
         mActionBarFlipper.requestFocusFromTouch();
 
         super.focusChrome();
     }
 
     @Override
     public void refreshChrome() {
         invalidateOptionsMenu();
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -476,16 +476,21 @@ nsHttpHandler::Init()
         obsService->AddObserver(this, "last-pb-context-exited", true);
         obsService->AddObserver(this, "browser:purge-session-history", true);
         obsService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true);
         obsService->AddObserver(this, "application-background", true);
         obsService->AddObserver(this,
                                 "net:current-toplevel-outer-content-windowid",
                                 true);
 
+        if (mFastOpenSupported) {
+            obsService->AddObserver(this, "captive-portal-login", true);
+            obsService->AddObserver(this, "captive-portal-login-success", true);
+        }
+
         // disabled as its a nop right now
         // obsService->AddObserver(this, "net:failed-to-process-uri-content", true);
     }
 
     MakeNewRequestTokenBucket();
     mWifiTickler = new Tickler();
     if (NS_FAILED(mWifiTickler->Init()))
         mWifiTickler = nullptr;
@@ -643,17 +648,16 @@ nsHttpHandler::IncrementFastOpenConsecut
     LOG(("nsHttpHandler::IncrementFastOpenConsecutiveFailureCounter - "
          "failed=%d failure_limit=%d", mFastOpenConsecutiveFailureCounter,
          mFastOpenConsecutiveFailureLimit));
     if (mFastOpenConsecutiveFailureCounter < mFastOpenConsecutiveFailureLimit) {
         mFastOpenConsecutiveFailureCounter++;
         if (mFastOpenConsecutiveFailureCounter == mFastOpenConsecutiveFailureLimit) {
             LOG(("nsHttpHandler::IncrementFastOpenConsecutiveFailureCounter - "
                  "Fast open failed too many times"));
-            SetFastOpenNotSupported();
         }
     }
 }
 
 nsresult
 nsHttpHandler::GetStreamConverterService(nsIStreamConverterService **result)
 {
     if (!mStreamConvSvc) {
@@ -2310,16 +2314,21 @@ nsHttpHandler::Observe(nsISupports *subj
             if (sCurrentTopLevelOuterContentWindowId != windowId) {
                 sCurrentTopLevelOuterContentWindowId = windowId;
                 if (mConnMgr) {
                     mConnMgr->UpdateCurrentTopLevelOuterContentWindowId(
                         sCurrentTopLevelOuterContentWindowId);
                 }
             }
         }
+    } else if (!strcmp(topic, "captive-portal-login") ||
+               !strcmp(topic, "captive-portal-login-success")) {
+         // We have detected a captive portal and we will reset the Fast Open
+         // failure counter.
+         ResetFastOpenConsecutiveFailureCounter();
     }
 
     return NS_OK;
 }
 
 // nsISpeculativeConnect
 
 nsresult
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -159,17 +159,21 @@ public:
       return mTCPKeepaliveLongLivedEnabled;
     }
     // Returns time (secs) before first TCP keepalive probes should be sent;
     // same time used between successful keepalive probes.
     int32_t GetTCPKeepaliveLongLivedIdleTime() {
       return mTCPKeepaliveLongLivedIdleTimeS;
     }
 
-    bool UseFastOpen() { return mUseFastOpen && mFastOpenSupported; }
+    bool UseFastOpen()
+    {
+        return mUseFastOpen && mFastOpenSupported &&
+               mFastOpenConsecutiveFailureCounter < mFastOpenConsecutiveFailureLimit;
+    }
     // If one of tcp connections return PR_NOT_TCP_SOCKET_ERROR while trying
     // fast open, it means that Fast Open is turned off so we will not try again
     // until a restart. This is only on Linux.
     // For windows 10 we can only check whether a version of windows support
     // Fast Open at run time, so if we get error PR_NOT_IMPLEMENTED_ERROR it
     // means that Fast Open is not supported and we will set mFastOpenSupported
     // to false.
     void SetFastOpenNotSupported() { mFastOpenSupported = false; }
--- a/testing/firefox-ui/tests/functional/keyboard_shortcuts/test_browser_window.py
+++ b/testing/firefox-ui/tests/functional/keyboard_shortcuts/test_browser_window.py
@@ -1,15 +1,12 @@
 # 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/.
 
-import sys
-import unittest
-
 from firefox_puppeteer import PuppeteerMixin
 from marionette_driver import Wait
 from marionette_harness import MarionetteTestCase
 
 
 class TestBrowserWindowShortcuts(PuppeteerMixin, MarionetteTestCase):
 
     def test_addons_manager(self):
@@ -52,30 +49,8 @@ class TestBrowserWindowShortcuts(Puppete
         # Anon locator has not been released yet (bug 1080764)
         def has_input_selected(mn):
             selection_name = mn.execute_script("""
                 return window.document.activeElement.localName;
             """)
             return selection_name == "input"
 
         Wait(self.marionette).until(has_input_selected)
-
-
-@unittest.skipIf(sys.platform == 'darwin',
-                 'Quit Shotcut not supported due to native menu of Mac OS')
-class TestBrowserQuitShortcut(PuppeteerMixin, MarionetteTestCase):
-
-    def test_quit_firefox_shortcut(self):
-        def quit_via_shortcut_callback():
-            if self.puppeteer.platform == 'win':
-                key = 'quitApplicationCmdWin2.accesskey'
-            else:
-                key = 'quitApplicationCmdUnix.key'
-
-            self.browser.send_shortcut(self.browser.localize_entity(key),
-                                       accel=True)
-
-        self.marionette.quit(in_app=True, callback=quit_via_shortcut_callback)
-        self.assertIsNone(self.marionette.session)
-
-    def tearDown(self):
-        self.marionette.start_session()
-        super(TestBrowserQuitShortcut, self).tearDown()
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/windows.py
+++ b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/windows.py
@@ -404,17 +404,18 @@ class BaseWindow(BaseLib):
         keys = []
         for modifier in kwargs:
             if modifier not in keymap:
                 raise KeyError('"%s" is not a known modifier' % modifier)
 
             if kwargs[modifier] is True:
                 keys.append(keymap[modifier])
 
-        keys.append(command_key)
+        # Bug 1125209 - Only lower-case command keys should be sent
+        keys.append(command_key.lower())
 
         self.switch_to()
 
         with self.marionette.using_context("chrome"):
             self.window_element.send_keys(*keys)
 
     def switch_to(self, focus=False):
         """Switches the context to this chrome window.
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -89,18 +89,18 @@ function testInit() {
       // Window is the [ChromeWindow] for messageManager, so we need content.window
       // Currently chrome tests are run in a content window instead of a ChromeWindow
       var webNav = content.window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                          .getInterface(Components.interfaces.nsIWebNavigation);
       webNav.loadURI(url, null, null, null, null);
     };
 
     var listener = 'data:,function doLoad(e) { var data=e.detail&&e.detail.data;removeEventListener("contentEvent", function (e) { doLoad(e); }, false, true);sendAsyncMessage("chromeEvent", {"data":data}); };addEventListener("contentEvent", function (e) { doLoad(e); }, false, true);';
+    messageManager.addMessageListener("chromeEvent", messageHandler);
     messageManager.loadFrameScript(listener, true);
-    messageManager.addMessageListener("chromeEvent", messageHandler);
   }
   if (gConfig.e10s) {
     e10s_init();
 
     let processCount = prefs.getIntPref("dom.ipc.processCount", 1);
     if (processCount > 1) {
       // Currently starting a content process is slow, to aviod timeouts, let's
       // keep alive content processes.
--- a/testing/mochitest/redirect.html
+++ b/testing/mochitest/redirect.html
@@ -22,16 +22,18 @@
       redirect("chrome://mochikit/content/harness.xul");
     }
 
     function onLoad() {
       // Wait for MozAfterPaint, since the listener in browser-test.js is not
       // added until then.
       window.addEventListener("MozAfterPaint", function() {
         setTimeout(redirectToHarness, 0);
+        // In case the listener was not ready, try again after a few seconds.
+        setTimeout(redirectToHarness, 5000);
       }, {once: true});
 
     }
   </script>
 </head>
 
 <body onload="onLoad();">
 redirecting...
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -12909,17 +12909,17 @@
     "low": 32,
     "high": 750,
     "n_buckets": 40,
     "keyed": true,
     "description": "Measures the number of milliseconds we spend waiting for sync message manager IPC messages to finish sending, keyed by message name. Note: only messages that wait for more than 500 microseconds are included in this probe."
   },
   "DISPLAY_ITEM_USAGE_COUNT": {
     "record_in_processes": ["main", "content"],
-    "alert_emails": ["mchang@mozilla.com", "gfx-telemetry@mozilla.com"],
+    "alert_emails": ["mchang@mozilla.com", "gfx-telemetry-alerts@mozilla.com"],
     "bug_numbers": [1353521],
     "expires_in_version": "56",
     "kind": "enumerated",
     "n_values": 99,
     "description": "Count of which layout display items are being created. Display items are created by layout to determine what content to render. A full description is above the class definition for nsDisplayItem. The list of types is kept in nsDisplayItemTypes.h."
   },
   "TIMEOUT_EXECUTION_FG_MS":
   {
--- a/xpcom/threads/SchedulerGroup.cpp
+++ b/xpcom/threads/SchedulerGroup.cpp
@@ -56,28 +56,34 @@ static Atomic<uint64_t> gEarliestUnproce
 class MOZ_RAII AutoCollectVsyncTelemetry final
 {
 public:
   explicit AutoCollectVsyncTelemetry(SchedulerGroup::Runnable* aRunnable
                                      MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
     : mIsBackground(aRunnable->IsBackground())
   {
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+// Telemetry collection temporarily disabled in bug 1366156.
+#if 0
 #ifdef EARLY_BETA_OR_EARLIER
     aRunnable->GetName(mKey);
     mStart = TimeStamp::Now();
 #endif
+#endif
   }
   ~AutoCollectVsyncTelemetry()
   {
+// Telemetry collection temporarily disabled in bug 1366156.
+#if 0
 #ifdef EARLY_BETA_OR_EARLIER
     if (Telemetry::CanRecordBase()) {
       CollectTelemetry();
     }
 #endif
+#endif
   }
 
 private:
   void CollectTelemetry();
 
   bool mIsBackground;
   nsCString mKey;
   TimeStamp mStart;