merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 07 Jun 2017 13:34:43 +0200
changeset 410757 fb40bcb6155bd1e3ac5468ff4575cce171efbc12
parent 410729 f6320f91851c2cede08b0fb54a6d0525b870310e (current diff)
parent 410756 0145ab10f5cc62bdf5cee9453be305809e5f7840 (diff)
child 410758 6c590acaff7c556798d7b7b47886d26f243d4781
child 410801 c154fc4eefbab2ca95c55768a631620ac6023ac7
child 410923 568c208a0531436946515bcc377222fd460bb76e
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -113,16 +113,24 @@ AccessibleWrap::Shutdown()
 STDMETHODIMP
 AccessibleWrap::QueryInterface(REFIID iid, void** ppv)
 {
   if (!ppv)
     return E_INVALIDARG;
 
   *ppv = nullptr;
 
+  if (IID_IClientSecurity == iid) {
+    // Some code might QI(IID_IClientSecurity) to detect whether or not we are
+    // a proxy. Right now that can potentially happen off the main thread, so we
+    // look for this condition immediately so that we don't trigger other code
+    // that might not be thread-safe.
+    return E_NOINTERFACE;
+  }
+
   if (IID_IUnknown == iid)
     *ppv = static_cast<IAccessible*>(this);
   else if (IID_IDispatch == iid || IID_IAccessible == iid)
     *ppv = static_cast<IAccessible*>(this);
   else if (IID_IEnumVARIANT == iid && !IsProxy()) {
     // Don't support this interface for leaf elements.
     if (!HasChildren() || nsAccUtils::MustPrune(this))
       return E_NOINTERFACE;
--- a/accessible/windows/sdn/sdnAccessible.cpp
+++ b/accessible/windows/sdn/sdnAccessible.cpp
@@ -34,16 +34,24 @@ sdnAccessible::~sdnAccessible()
 
 STDMETHODIMP
 sdnAccessible::QueryInterface(REFIID aREFIID, void** aInstancePtr)
 {
   if (!aInstancePtr)
     return E_FAIL;
   *aInstancePtr = nullptr;
 
+  if (aREFIID == IID_IClientSecurity) {
+    // Some code might QI(IID_IClientSecurity) to detect whether or not we are
+    // a proxy. Right now that can potentially happen off the main thread, so we
+    // look for this condition immediately so that we don't trigger other code
+    // that might not be thread-safe.
+    return E_NOINTERFACE;
+  }
+
   if (aREFIID == IID_ISimpleDOMNode) {
     *aInstancePtr = static_cast<ISimpleDOMNode*>(this);
     AddRef();
     return S_OK;
   }
 
   AccessibleWrap* accessible = GetAccessible();
   if (accessible)
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -698,17 +698,29 @@ Element::GetScrollFrame(nsIFrame **aStyl
         return scrollFrame;
       }
     }
   }
 
   nsIDocument* doc = OwnerDoc();
   // Note: This IsScrollingElement() call can flush frames, if we're the body of
   // a quirks mode document.
-  if (OwnerDoc()->IsScrollingElement(this)) {
+  bool isScrollingElement = OwnerDoc()->IsScrollingElement(this);
+  // Now reget *aStyledFrame if the caller asked for it, because that frame
+  // flush can kill it.
+  if (aStyledFrame) {
+    nsIFrame* frame = GetPrimaryFrame(FlushType::None);
+    if (frame) {
+      *aStyledFrame = nsLayoutUtils::GetStyleFrame(frame);
+    } else {
+      *aStyledFrame = nullptr;
+    }
+  }
+
+  if (isScrollingElement) {
     // Our scroll info should map to the root scrollable frame if there is one.
     if (nsIPresShell* shell = doc->GetShell()) {
       return shell->GetRootScrollFrameAsScrollable();
     }
   }
 
   return nullptr;
 }
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/1370072.html
@@ -0,0 +1,18 @@
+<script>
+function start() {
+	o1=document.createElement('iframe');
+	o1.addEventListener('load',fun0);
+	document.body.appendChild(o1);
+}
+function fun0() {
+	o5=o1.contentDocument;
+	o52=function() {let x=o5.querySelectorAll('*:not([id])');return x[x.length-1]}();
+	o1.contentWindow.onresize=fun1;
+	o1.height='5px';
+	o52.clientTop;
+}
+function fun1() {
+	document.documentElement.appendChild(o1);
+}
+</script>
+<body onload="start()"></body>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -209,8 +209,9 @@ load 1230422.html
 load 1251361.html
 load 1304437.html
 pref(dom.IntersectionObserver.enabled,true) load 1324209.html
 pref(dom.IntersectionObserver.enabled,true) load 1326194-1.html
 pref(dom.IntersectionObserver.enabled,true) load 1326194-2.html
 pref(dom.IntersectionObserver.enabled,true) load 1332939.html
 pref(dom.IntersectionObserver.enabled,true) load 1353529.xul
 pref(dom.webcomponents.enabled,true) load 1341693.html
+load 1370072.html
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1606,16 +1606,21 @@ LookupComponentsShim(JSContext *cx, JS::
                      JS::MutableHandle<JS::PropertyDescriptor> desc);
 
 // static
 bool
 nsWindowSH::NameStructEnabled(JSContext* aCx, nsGlobalWindow *aWin,
                               const nsAString& aName,
                               const nsGlobalNameStruct& aNameStruct)
 {
+  // DOMConstructor is special: creating its proto does not actually define it
+  // as a property on the global.  So we don't want to expose its name either.
+  if (aName.EqualsLiteral("DOMConstructor")) {
+    return false;
+  }
   const nsGlobalNameStruct* nameStruct = &aNameStruct;
   return (nameStruct->mType != nsGlobalNameStruct::eTypeProperty &&
           nameStruct->mType != nsGlobalNameStruct::eTypeClassConstructor) ||
          OldBindingConstructorEnabled(nameStruct, aWin, aCx);
 }
 
 #ifdef RELEASE_OR_BETA
 #define USE_CONTROLLERS_SHIM
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -5133,34 +5133,58 @@ nsGlobalWindow::MayResolve(jsid aId)
 
   nsAutoString name;
   AssignJSFlatString(name, JSID_TO_FLAT_STRING(aId));
 
   return nameSpaceManager->LookupName(name);
 }
 
 void
-nsGlobalWindow::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
+nsGlobalWindow::GetOwnPropertyNames(JSContext* aCx, JS::AutoIdVector& aNames,
                                     ErrorResult& aRv)
 {
   MOZ_ASSERT(IsInnerWindow());
   // "Components" is marked as enumerable but only resolved on demand :-/.
   //aNames.AppendElement(NS_LITERAL_STRING("Components"));
 
   nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
   if (nameSpaceManager) {
     JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
 
-    WebIDLGlobalNameHash::GetNames(aCx, wrapper, aNames);
+    // There are actually two ways we can get called here: For normal
+    // enumeration or for Xray enumeration.  In the latter case, we want to
+    // return all possible WebIDL names, because we don't really support
+    // deleting these names off our Xray; trying to resolve them will just make
+    // them come back.  In the former case, we want to avoid returning deleted
+    // names.  But the JS engine already knows about the non-deleted
+    // already-resolved names, so we can just return the so-far-unresolved ones.
+    //
+    // We can tell which case we're in by whether aCx is in our wrapper's
+    // compartment.  If not, we're in the Xray case.
+    WebIDLGlobalNameHash::NameType nameType =
+      js::IsObjectInContextCompartment(wrapper, aCx) ?
+        WebIDLGlobalNameHash::UnresolvedNamesOnly :
+        WebIDLGlobalNameHash::AllNames;
+    if (!WebIDLGlobalNameHash::GetNames(aCx, wrapper, nameType, aNames)) {
+      aRv.NoteJSContextException(aCx);
+    }
 
     for (auto i = nameSpaceManager->GlobalNameIter(); !i.Done(); i.Next()) {
       const GlobalNameMapEntry* entry = i.Get();
       if (nsWindowSH::NameStructEnabled(aCx, this, entry->mKey,
                                         entry->mGlobalName)) {
-        aNames.AppendElement(entry->mKey);
+        // Just append all of these; even if they get deleted our resolve hook
+        // just goes ahead and recreates them.
+        JSString* str = JS_AtomizeUCStringN(aCx,
+                                            entry->mKey.BeginReading(),
+                                            entry->mKey.Length());
+        if (!str || !aNames.append(NON_INTEGER_ATOM_TO_JSID(str))) {
+          aRv.NoteJSContextException(aCx);
+          return;
+        }
       }
     }
   }
 }
 
 /* static */ bool
 nsGlobalWindow::IsPrivilegedChromeWindow(JSContext* aCx, JSObject* aObj)
 {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -481,17 +481,17 @@ public:
 
   bool DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
                  JS::Handle<jsid> aId,
                  JS::MutableHandle<JS::PropertyDescriptor> aDesc);
   // The return value is whether DoResolve might end up resolving the given id.
   // If in doubt, return true.
   static bool MayResolve(jsid aId);
 
-  void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
+  void GetOwnPropertyNames(JSContext* aCx, JS::AutoIdVector& aNames,
                            mozilla::ErrorResult& aRv);
 
   // Object Management
   static already_AddRefed<nsGlobalWindow> Create(nsGlobalWindow *aOuterWindow);
 
   static nsGlobalWindow *FromSupports(nsISupports *supports)
   {
     // Make sure this matches the casts we do in QueryInterface().
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -3896,17 +3896,17 @@ bool
 nsObjectLoadingContent::MayResolve(jsid aId)
 {
   // We can resolve anything, really.
   return true;
 }
 
 void
 nsObjectLoadingContent::GetOwnPropertyNames(JSContext* aCx,
-                                            nsTArray<nsString>& /* unused */,
+                                            JS::AutoIdVector& /* unused */,
                                             ErrorResult& aRv)
 {
   // Just like DoResolve, just make sure we're instantiated.  That will do
   // the work our Enumerate hook needs to do.  This purposefully does not fire
   // for xray resolves, see bug 967694
   RefPtr<nsNPAPIPluginInstance> pi;
   aRv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
 }
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -176,17 +176,17 @@ class nsObjectLoadingContent : public ns
     bool DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
                    JS::Handle<jsid> aId,
                    JS::MutableHandle<JS::PropertyDescriptor> aDesc);
     // The return value is whether DoResolve might end up resolving the given
     // id.  If in doubt, return true.
     static bool MayResolve(jsid aId);
 
     // Helper for WebIDL enumeration
-    void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& /* unused */,
+    void GetOwnPropertyNames(JSContext* aCx, JS::AutoIdVector& /* unused */,
                              mozilla::ErrorResult& aRv);
 
     // WebIDL API
     nsIDocument* GetContentDocument(nsIPrincipal& aSubjectPrincipal);
     void GetActualType(nsAString& aType) const
     {
       CopyUTF8toUTF16(mContentType, aType);
     }
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -449,31 +449,55 @@ class CGDOMJSClass(CGThing):
             traceHook = "JS_GlobalObjectTraceHook"
             reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
         else:
             classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
             traceHook = 'nullptr'
             reservedSlots = slotCount
         if self.descriptor.interface.hasProbablyShortLivingWrapper():
             classFlags += " | JSCLASS_SKIP_NURSERY_FINALIZE"
+
+        objectOps = "JS_NULL_OBJECT_OPS"
+        objectOpsString = ""
         if self.descriptor.interface.getExtendedAttribute("NeedResolve"):
             resolveHook = RESOLVE_HOOK_NAME
             mayResolveHook = MAY_RESOLVE_HOOK_NAME
-            enumerateHook = ENUMERATE_HOOK_NAME
+            enumerateHook = "nullptr"
+            objectOpsString = fill(
+                """
+                const js::ObjectOps sInstanceObjectOps = {
+                  nullptr, /* lookupProperty */
+                  nullptr, /* defineProperty */
+                  nullptr, /* hasProperty */
+                  nullptr, /* getProperty */
+                  nullptr, /* setProperty */
+                  nullptr, /* getOwnPropertyDescriptor */
+                  nullptr, /* deleteProperty */
+                  nullptr, /* watch */
+                  nullptr, /* unwatch */
+                  nullptr, /* getElements */
+                  ${enumerate}, /* enumerate */
+                  nullptr, /* funToString */
+                };
+
+                """,
+                enumerate=ENUMERATE_HOOK_NAME)
+            objectOps = "&sInstanceObjectOps"
         elif self.descriptor.isGlobal():
             resolveHook = "mozilla::dom::ResolveGlobal"
             mayResolveHook = "mozilla::dom::MayResolveGlobal"
             enumerateHook = "mozilla::dom::EnumerateGlobal"
         else:
             resolveHook = "nullptr"
             mayResolveHook = "nullptr"
             enumerateHook = "nullptr"
 
         return fill(
             """
+            $*{objectOpsString}
             static const js::ClassOps sClassOps = {
               ${addProperty}, /* addProperty */
               nullptr,               /* delProperty */
               nullptr,               /* getProperty */
               nullptr,               /* setProperty */
               ${enumerate}, /* enumerate */
               ${resolve}, /* resolve */
               ${mayResolve}, /* mayResolve */
@@ -490,35 +514,37 @@ class CGDOMJSClass(CGThing):
             };
 
             static const DOMJSClass sClass = {
               { "${name}",
                 ${flags},
                 &sClassOps,
                 JS_NULL_CLASS_SPEC,
                 &sClassExtension,
-                JS_NULL_OBJECT_OPS
+                ${objectOps}
               },
               $*{descriptor}
             };
             static_assert(${instanceReservedSlots} == DOM_INSTANCE_RESERVED_SLOTS,
                           "Must have the right minimal number of reserved slots.");
             static_assert(${reservedSlots} >= ${slotCount},
                           "Must have enough reserved slots.");
             """,
+            objectOpsString=objectOpsString,
             name=self.descriptor.interface.identifier.name,
             flags=classFlags,
             addProperty=ADDPROPERTY_HOOK_NAME if wantsAddProperty(self.descriptor) else 'nullptr',
             enumerate=enumerateHook,
             resolve=resolveHook,
             mayResolve=mayResolveHook,
             finalize=FINALIZE_HOOK_NAME,
             call=callHook,
             trace=traceHook,
             objectMoved=objectMovedHook,
+            objectOps=objectOps,
             descriptor=DOMClass(self.descriptor),
             instanceReservedSlots=INSTANCE_RESERVED_SLOTS,
             reservedSlots=reservedSlots,
             slotCount=slotCount)
 
 
 class CGDOMProxyJSClass(CGThing):
     """
@@ -8888,43 +8914,42 @@ class CGMayResolveHook(CGAbstractStaticM
 class CGEnumerateHook(CGAbstractBindingMethod):
     """
     Enumerate hook for objects with custom hooks.
     """
     def __init__(self, descriptor):
         assert descriptor.interface.getExtendedAttribute("NeedResolve")
 
         args = [Argument('JSContext*', 'cx'),
-                Argument('JS::Handle<JSObject*>', 'obj')]
+                Argument('JS::Handle<JSObject*>', 'obj'),
+                Argument('JS::AutoIdVector&', 'properties'),
+                Argument('bool', 'enumerableOnly')]
         # Our "self" is actually the "obj" argument in this case, not the thisval.
         CGAbstractBindingMethod.__init__(
             self, descriptor, ENUMERATE_HOOK_NAME,
             args, getThisObj="", callArgs="")
 
     def generate_code(self):
         return CGGeneric(dedent("""
-            AutoTArray<nsString, 8> names;
             binding_detail::FastErrorResult rv;
-            self->GetOwnPropertyNames(cx, names, rv);
+            self->GetOwnPropertyNames(cx, properties, rv);
             if (rv.MaybeSetPendingException(cx)) {
               return false;
             }
-            bool dummy;
-            for (uint32_t i = 0; i < names.Length(); ++i) {
-              if (!JS_HasUCProperty(cx, obj, names[i].get(), names[i].Length(), &dummy)) {
-                return false;
-              }
-            }
             return true;
             """))
 
     def definition_body(self):
         if self.descriptor.isGlobal():
             # Enumerate standard classes
             prefix = dedent("""
+                // This is OK even though we're a newEnumerate hook: this will
+                // define the relevant properties on the global, and the JS
+                // engine will pick those up, because it looks at the object's
+                // properties after this hook has returned.
                 if (!EnumerateGlobal(cx, obj)) {
                   return false;
                 }
 
                 """)
         else:
             prefix = ""
         return prefix + CGAbstractBindingMethod.definition_body(self)
@@ -11165,25 +11190,22 @@ class CGEnumerateOwnPropertiesViaGetOwnP
                 Argument('JS::AutoIdVector&', 'props')]
         CGAbstractBindingMethod.__init__(self, descriptor,
                                          "EnumerateOwnPropertiesViaGetOwnPropertyNames",
                                          args, getThisObj="",
                                          callArgs="")
 
     def generate_code(self):
         return CGGeneric(dedent("""
-            AutoTArray<nsString, 8> names;
             binding_detail::FastErrorResult rv;
-            self->GetOwnPropertyNames(cx, names, rv);
+            self->GetOwnPropertyNames(cx, props, rv);
             if (rv.MaybeSetPendingException(cx)) {
               return false;
             }
-            // OK to pass null as "proxy" because it's ignored if
-            // shadowPrototypeProperties is true
-            return AppendNamedPropertyIds(cx, nullptr, names, true, props);
+            return true;
             """))
 
 
 class CGPrototypeTraitsClass(CGClass):
     def __init__(self, descriptor, indent=''):
         templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
         templateSpecialization = ['prototypes::id::' + descriptor.name]
         enums = [ClassEnum('', ['Depth'],
@@ -13763,17 +13785,18 @@ class CGRegisterGlobalNames(CGAbstractMe
             if not desc.isExposedConditionally():
                 return "nullptr"
             return "%sBinding::ConstructorEnabled" % desc.name
 
         define = ""
         currentOffset = 0
         for (name, desc) in getGlobalNames(self.config):
             length = len(name)
-            define += "WebIDLGlobalNameHash::Register(%i, %i, %sBinding::DefineDOMInterface, %s);\n" % (currentOffset, length, desc.name, getCheck(desc))
+            define += "WebIDLGlobalNameHash::Register(%i, %i, %sBinding::DefineDOMInterface, %s, constructors::id::%s);\n" % (
+                currentOffset, length, desc.name, getCheck(desc), desc.name)
             currentOffset += length + 1 # Add trailing null.
         return define
 
 
 def dependencySortObjects(objects, dependencyGetter, nameGetter):
     """
     Sort IDL objects with dependencies on each other such that if A
     depends on B then B will come before A.  This is needed for
@@ -16997,16 +17020,17 @@ class GlobalGenRoots():
         curr = CGWrapper(curr, post='\n')
 
         # Add the includes
         defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
                           for desc in config.getDescriptors(hasInterfaceObject=True,
                                                             isExposedInWindow=True,
                                                             register=True)]
         defineIncludes.append('mozilla/dom/WebIDLGlobalNameHash.h')
+        defineIncludes.append('mozilla/dom/PrototypeList.h')
         defineIncludes.extend([CGHeaders.getDeclarationFilename(desc.interface)
                                for desc in config.getDescriptors(isNavigatorProperty=True,
                                                                  register=True)])
         curr = CGHeaders([], [], [], [], [], defineIncludes, 'RegisterBindings',
                          curr)
 
         # Add include guards.
         curr = CGIncludeGuard('RegisterBindings', curr)
--- a/dom/bindings/WebIDLGlobalNameHash.cpp
+++ b/dom/bindings/WebIDLGlobalNameHash.cpp
@@ -3,17 +3,19 @@
 /* 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 "WebIDLGlobalNameHash.h"
 #include "js/GCAPI.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/Maybe.h"
+#include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/DOMJSProxyHandler.h"
+#include "mozilla/dom/PrototypeList.h"
 #include "mozilla/dom/RegisterBindings.h"
 #include "nsIMemoryReporter.h"
 #include "nsTHashtable.h"
 
 namespace mozilla {
 namespace dom {
 
 struct MOZ_STACK_CLASS WebIDLNameTableKey
@@ -53,22 +55,24 @@ struct MOZ_STACK_CLASS WebIDLNameTableKe
 struct WebIDLNameTableEntry : public PLDHashEntryHdr
 {
   typedef const WebIDLNameTableKey& KeyType;
   typedef const WebIDLNameTableKey* KeyTypePointer;
 
   explicit WebIDLNameTableEntry(KeyTypePointer aKey)
     : mNameOffset(0),
       mNameLength(0),
+      mConstructorId(constructors::id::_ID_Count),
       mDefine(nullptr),
       mEnabled(nullptr)
   {}
   WebIDLNameTableEntry(WebIDLNameTableEntry&& aEntry)
     : mNameOffset(aEntry.mNameOffset),
       mNameLength(aEntry.mNameLength),
+      mConstructorId(aEntry.mConstructorId),
       mDefine(aEntry.mDefine),
       mEnabled(aEntry.mEnabled)
   {}
   ~WebIDLNameTableEntry()
   {}
 
   bool KeyEquals(KeyTypePointer aKey) const
   {
@@ -95,16 +99,17 @@ struct WebIDLNameTableEntry : public PLD
   {
     return aKey->mHash;
   }
 
   enum { ALLOW_MEMMOVE = true };
 
   uint16_t mNameOffset;
   uint16_t mNameLength;
+  constructors::id::ID mConstructorId;
   WebIDLGlobalNameHash::DefineGlobalName mDefine;
   // May be null if enabled unconditionally
   WebIDLGlobalNameHash::ConstructorEnabled* mEnabled;
 };
 
 static nsTHashtable<WebIDLNameTableEntry>* sWebIDLGlobalNames;
 
 class WebIDLGlobalNamesHashReporter final : public nsIMemoryReporter
@@ -149,25 +154,27 @@ WebIDLGlobalNameHash::Shutdown()
 {
   delete sWebIDLGlobalNames;
 }
 
 /* static */
 void
 WebIDLGlobalNameHash::Register(uint16_t aNameOffset, uint16_t aNameLength,
                                DefineGlobalName aDefine,
-                               ConstructorEnabled* aEnabled)
+                               ConstructorEnabled* aEnabled,
+                               constructors::id::ID aConstructorId)
 {
   const char* name = sNames + aNameOffset;
   WebIDLNameTableKey key(name, aNameLength);
   WebIDLNameTableEntry* entry = sWebIDLGlobalNames->PutEntry(key);
   entry->mNameOffset = aNameOffset;
   entry->mNameLength = aNameLength;
   entry->mDefine = aDefine;
   entry->mEnabled = aEnabled;
+  entry->mConstructorId = aConstructorId;
 }
 
 /* static */
 void
 WebIDLGlobalNameHash::Remove(const char* aName, uint32_t aLength)
 {
   WebIDLNameTableKey key(aName, aLength);
   sWebIDLGlobalNames->RemoveEntry(key);
@@ -295,24 +302,34 @@ WebIDLGlobalNameHash::MayResolve(jsid aI
   // Rooting analysis thinks nsTHashtable<...>::Contains may GC because it ends
   // up calling through PLDHashTableOps' matchEntry function pointer, but we
   // know WebIDLNameTableEntry::KeyEquals can't cause a GC.
   JS::AutoSuppressGCAnalysis suppress;
   return sWebIDLGlobalNames->Contains(key);
 }
 
 /* static */
-void
+bool
 WebIDLGlobalNameHash::GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj,
-                               nsTArray<nsString>& aNames)
+                               NameType aNameType, JS::AutoIdVector& aNames)
 {
+  // aObj is always a Window here, so GetProtoAndIfaceCache on it is safe.
+  ProtoAndIfaceCache* cache = GetProtoAndIfaceCache(aObj);
   for (auto iter = sWebIDLGlobalNames->Iter(); !iter.Done(); iter.Next()) {
     const WebIDLNameTableEntry* entry = iter.Get();
-    if (!entry->mEnabled || entry->mEnabled(aCx, aObj)) {
-      AppendASCIItoUTF16(nsDependentCString(sNames + entry->mNameOffset,
-                                            entry->mNameLength),
-                         *aNames.AppendElement());
+    // If aNameType is not AllNames, only include things whose entry slot in the
+    // ProtoAndIfaceCache is null.
+    if ((aNameType == AllNames ||
+         !cache->EntrySlotIfExists(entry->mConstructorId)) &&
+        (!entry->mEnabled || entry->mEnabled(aCx, aObj))) {
+      JSString* str = JS_AtomizeStringN(aCx, sNames + entry->mNameOffset,
+                                        entry->mNameLength);
+      if (!str || !aNames.append(NON_INTEGER_ATOM_TO_JSID(str))) {
+        return false;
+      }
     }
   }
+
+  return true;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/WebIDLGlobalNameHash.h
+++ b/dom/bindings/WebIDLGlobalNameHash.h
@@ -10,16 +10,22 @@
 #include "js/RootingAPI.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 
 struct WebIDLNameTableEntry;
 
+namespace constructors {
+namespace id {
+enum ID : uint16_t;
+} // namespace id
+} // namespace constructors
+
 class WebIDLGlobalNameHash
 {
 public:
   static void Init();
   static void Shutdown();
 
   typedef JSObject*
   (*DefineGlobalName)(JSContext* cx, JS::Handle<JSObject*> global,
@@ -30,31 +36,42 @@ public:
   // defining constructors on the underlying object.
   // This is a typedef for the function type itself, not the function
   // pointer, so it's more obvious that pointers to a ConstructorEnabled
   // can be null.
   typedef bool
   (ConstructorEnabled)(JSContext* cx, JS::Handle<JSObject*> obj);
 
   static void Register(uint16_t aNameOffset, uint16_t aNameLength,
-                       DefineGlobalName aDefine, ConstructorEnabled* aEnabled);
+                       DefineGlobalName aDefine, ConstructorEnabled* aEnabled,
+                       constructors::id::ID aConstructorId);
 
   static void Remove(const char* aName, uint32_t aLength);
 
   // Returns false if something failed. aFound is set to true if the name is in
   // the hash, whether it's enabled or not.
   static bool DefineIfEnabled(JSContext* aCx, JS::Handle<JSObject*> aObj,
                               JS::Handle<jsid> aId,
                               JS::MutableHandle<JS::PropertyDescriptor> aDesc,
                               bool* aFound);
 
   static bool MayResolve(jsid aId);
 
-  static void GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj,
-                       nsTArray<nsString>& aNames);
+  // The type of names we're asking for.
+  enum NameType {
+    // All WebIDL names enabled for aObj.
+    AllNames,
+    // Only the names that are enabled for aObj and have not been resolved for
+    // aObj in the past (and therefore can't have been deleted).
+    UnresolvedNamesOnly
+  };
+  // Returns false if an exception has been thrown on aCx.
+  static bool GetNames(JSContext* aCx, JS::Handle<JSObject*> aObj,
+                       NameType aNameType,
+                       JS::AutoIdVector& aNames);
 
 private:
   friend struct WebIDLNameTableEntry;
 
   // The total number of names that we will add to the hash.
   // The value of sCount is generated by Codegen.py in RegisterBindings.cpp.
   static const uint32_t sCount;
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -123,16 +123,17 @@
 #include "nsThreadManager.h"
 #include "nsAnonymousTemporaryFile.h"
 #include "nsISpellChecker.h"
 #include "nsClipboardProxy.h"
 #include "nsDirectoryService.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsContentPermissionHelper.h"
+#include "nsPluginHost.h"
 #ifdef NS_PRINTING
 #include "nsPrintingProxy.h"
 #endif
 
 #include "IHistory.h"
 #include "nsNetUtil.h"
 
 #include "base/message_loop.h"
@@ -3379,10 +3380,20 @@ ContentChild::RecvRefreshScreens(nsTArra
 }
 
 already_AddRefed<nsIEventTarget>
 ContentChild::GetEventTargetFor(TabChild* aTabChild)
 {
   return IToplevelProtocol::GetActorEventTarget(aTabChild);
 }
 
+mozilla::ipc::IPCResult
+ContentChild::RecvSetPluginList(const uint32_t& aPluginEpoch,
+                                nsTArray<plugins::PluginTag>&& aPluginTags,
+                                nsTArray<plugins::FakePluginTag>&& aFakePluginTags)
+{
+  RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
+  host->SetPluginsInContent(aPluginEpoch, aPluginTags, aFakePluginTags);
+  return IPC_OK();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -656,16 +656,19 @@ public:
                       const Optional<int64_t>& aLastModified,
                       bool aExistenceCheck, bool aIsFromNsIFile);
 
   typedef std::function<void(PRFileDesc*)> AnonymousTemporaryFileCallback;
   nsresult AsyncOpenAnonymousTemporaryFile(const AnonymousTemporaryFileCallback& aCallback);
 
   virtual already_AddRefed<nsIEventTarget> GetEventTargetFor(TabChild* aTabChild) override;
 
+  mozilla::ipc::IPCResult
+  RecvSetPluginList(const uint32_t& aPluginEpoch, nsTArray<PluginTag>&& aPluginTags, nsTArray<FakePluginTag>&& aFakePluginTags) override;
+
 private:
   static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
   void StartForceKillTimer();
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   virtual void ProcessingError(Result aCode, const char* aReason) override;
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1157,27 +1157,16 @@ ContentParent::RecvGetBlocklistState(con
   }
 
   if (NS_FAILED(tag->GetBlocklistState(aState))) {
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
-mozilla::ipc::IPCResult
-ContentParent::RecvFindPlugins(const uint32_t& aPluginEpoch,
-                               nsresult* aRv,
-                               nsTArray<PluginTag>* aPlugins,
-                               nsTArray<FakePluginTag>* aFakePlugins,
-                               uint32_t* aNewPluginEpoch)
-{
-  *aRv = mozilla::plugins::FindPluginsForContent(aPluginEpoch, aPlugins, aFakePlugins, aNewPluginEpoch);
-  return IPC_OK();
-}
-
 /*static*/ TabParent*
 ContentParent::CreateBrowser(const TabContext& aContext,
                              Element* aFrameElement,
                              ContentParent* aOpenerContentParent,
                              TabParent* aSameTabGroupAs,
                              uint64_t aNextTabParentId)
 {
   PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
@@ -2443,16 +2432,21 @@ ContentParent::InitInternal(ProcessPrior
 
   {
     nsTArray<BlobURLRegistrationData> registrations;
     if (nsHostObjectProtocolHandler::GetAllBlobURLEntries(registrations,
                                                           this)) {
       Unused << SendInitBlobURLs(registrations);
     }
   }
+
+  // Start up nsPluginHost and run FindPlugins to cache the plugin list.
+  // If this isn't our first content process, just send over cached list.
+  RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
+  pluginHost->SendPluginsToContent();
 }
 
 bool
 ContentParent::IsAlive() const
 {
   return mIsAlive;
 }
 
@@ -5292,8 +5286,16 @@ ContentParent::CanCommunicateWith(Conten
   if (!cpm->GetParentProcessId(ChildID(), &parentId)) {
     return false;
   }
   if (IsForJSPlugin()) {
     return parentId == ContentParentId(0);
   }
   return parentId == aOtherProcess;
 }
+
+mozilla::ipc::IPCResult
+ContentParent::RecvMaybeReloadPlugins()
+{
+  RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
+  pluginHost->ReloadPlugins();
+  return IPC_OK();
+}
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -293,29 +293,25 @@ public:
                                                            Endpoint<PContentBridgeParent>* aEndpoint) override;
 
   virtual mozilla::ipc::IPCResult RecvCreateGMPService() override;
 
   virtual mozilla::ipc::IPCResult RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv,
                                                  uint32_t* aRunID,
                                                  Endpoint<PPluginModuleParent>* aEndpoint) override;
 
+  virtual mozilla::ipc::IPCResult RecvMaybeReloadPlugins() override;
+
   virtual mozilla::ipc::IPCResult RecvConnectPluginBridge(const uint32_t& aPluginId,
                                                           nsresult* aRv,
                                                           Endpoint<PPluginModuleParent>* aEndpoint) override;
 
   virtual mozilla::ipc::IPCResult RecvGetBlocklistState(const uint32_t& aPluginId,
                                                         uint32_t* aIsBlocklisted) override;
 
-  virtual mozilla::ipc::IPCResult RecvFindPlugins(const uint32_t& aPluginEpoch,
-                                                  nsresult* aRv,
-                                                  nsTArray<PluginTag>* aPlugins,
-                                                  nsTArray<FakePluginTag>* aFakePlugins,
-                                                  uint32_t* aNewPluginEpoch) override;
-
   virtual mozilla::ipc::IPCResult RecvUngrabPointer(const uint32_t& aTime) override;
 
   virtual mozilla::ipc::IPCResult RecvRemovePermission(const IPC::Principal& aPrincipal,
                                                        const nsCString& aPermissionType,
                                                        nsresult* aRv) override;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -606,16 +606,27 @@ child:
     async ProvideAnonymousTemporaryFile(uint64_t aID, FileDescOrError aFD);
 
     async SetPermissionsWithKey(nsCString aPermissionKey, Permission[] aPermissions);
 
     async RefreshScreens(ScreenDetails[] aScreens);
 
     async PIPCBlobInputStream(nsID aID, uint64_t aSize);
 
+    /**
+     * This call takes the set of plugins loaded in the chrome process, and
+     * sends them to the content process. However, in many cases this set will
+     * not have changed since the last SetPluginList message. To keep track of
+     * this, the chrome process increments an epoch number every time the set of
+     * plugins changes. The chrome process sends up the last epoch it observed.
+     * If the epoch last seen by the content process is the same, the content
+     * process ignores the update. Otherwise the content process updates its
+     * list and reloads its plugins.
+     **/
+    async SetPluginList(uint32_t pluginEpoch, PluginTag[] plugins, FakePluginTag[] fakePlugins);
 parent:
     async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
 
     sync CreateChildProcess(IPCTabContext context,
                             ProcessPriority priority,
                             TabId openerTabId,
                             TabId tabId)
         returns (ContentParentId cpId, bool isForBrowser);
@@ -641,30 +652,16 @@ parent:
     sync ConnectPluginBridge(uint32_t aPluginId)
         returns (nsresult rv, Endpoint<PPluginModuleParent> aEndpoint);
 
     /**
      * Return the current blocklist state for a particular plugin.
      */
     sync GetBlocklistState(uint32_t aPluginId) returns (uint32_t aState);
 
-    /**
-     * This call returns the set of plugins loaded in the chrome
-     * process. However, in many cases this set will not have changed since the
-     * last FindPlugins message. Consequently, the chrome process increments an
-     * epoch number every time the set of plugins changes. The content process
-     * sends up the last epoch it observed. If the epochs are the same, the
-     * chrome process returns no plugins. Otherwise it returns a complete list.
-     *
-     * |pluginEpoch| is the epoch last observed by the content
-     * process. |newPluginEpoch| is the current epoch in the chrome process. If
-     * |pluginEpoch == newPluginEpoch|, then |plugins| will be left empty.
-     */
-    sync FindPlugins(uint32_t pluginEpoch) returns (nsresult aResult, PluginTag[] plugins, FakePluginTag[] fakePlugins, uint32_t newPluginEpoch);
-
     async PJavaScript();
 
     async PRemoteSpellcheckEngine();
 
     async InitCrashReporter(Shmem shmem, NativeThreadId tid);
 
     /**
      * Is this token compatible with the provided version?
@@ -1089,16 +1086,17 @@ parent:
 
     sync GetA11yContentId() returns (uint32_t aContentId);
     async A11yHandlerControl(uint32_t aPid,
                              IHandlerControlHolder aHandlerControl);
 
     async AddMemoryReport(MemoryReport aReport);
     async FinishMemoryReport(uint32_t aGeneration);
 
+    async MaybeReloadPlugins();
 both:
      async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
                         Principal aPrincipal, ClonedMessageData aData);
 
     /**
      * Notify `push-subscription-modified` observers in the parent and child.
      */
     async NotifyPushSubscriptionModifiedObservers(nsCString scope,
--- a/dom/locales/en-US/chrome/security/security.properties
+++ b/dom/locales/en-US/chrome/security/security.properties
@@ -57,17 +57,17 @@ BothAllowScriptsAndSameOriginPresent=An 
 
 # Sub-Resource Integrity
 # LOCALIZATION NOTE: Do not translate "script" or "integrity". "%1$S" is the invalid token found in the attribute.
 MalformedIntegrityHash=The script element has a malformed hash in its integrity attribute: “%1$S”. The correct format is “<hash algorithm>-<hash value>”.
 # LOCALIZATION NOTE: Do not translate "integrity"
 InvalidIntegrityLength=The hash contained in the integrity attribute has the wrong length.
 # LOCALIZATION NOTE: Do not translate "integrity"
 InvalidIntegrityBase64=The hash contained in the integrity attribute could not be decoded.
-# LOCALIZATION NOTE: Do not translate "integrity". "%1$S" is the type of hash algorigthm in use (e.g. "sha256").
+# LOCALIZATION NOTE: Do not translate "integrity". "%1$S" is the type of hash algorithm in use (e.g. "sha256").
 IntegrityMismatch=None of the “%1$S” hashes in the integrity attribute match the content of the subresource.
 # LOCALIZATION NOTE: "%1$S" is the URI of the sub-resource that cannot be protected using SRI.
 IneligibleResource=“%1$S” is not eligible for integrity checks since it’s neither CORS-enabled nor same-origin.
 # LOCALIZATION NOTE: Do not translate "integrity". "%1$S" is the invalid hash algorithm found in the attribute.
 UnsupportedHashAlg=Unsupported hash algorithm in the integrity attribute: “%1$S”
 # LOCALIZATION NOTE: Do not translate "integrity"
 NoValidMetadata=The integrity attribute does not contain any valid metadata.
 
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -46,16 +46,17 @@
 #include "nsIScriptChannel.h"
 #include "nsIBlocklistService.h"
 #include "nsVersionComparator.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsICategoryManager.h"
 #include "nsPluginStreamListenerPeer.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/FakePluginTagInitBinding.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/plugins/PluginAsyncSurrogate.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/plugins/PluginTypes.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ipc/URIUtils.h"
 
@@ -262,24 +263,16 @@ static bool UnloadPluginsASAP()
 }
 
 nsPluginHost::nsPluginHost()
   : mPluginsLoaded(false)
   , mOverrideInternalTypes(false)
   , mPluginsDisabled(false)
   , mPluginEpoch(0)
 {
-  // Bump the pluginchanged epoch on startup. This insures content gets a
-  // good plugin list the first time it requests it. Normally we'd just
-  // init this to 1, but due to the unique nature of our ctor we need to do
-  // this manually.
-  if (XRE_IsParentProcess()) {
-    IncrementChromeEpoch();
-  }
-
   // check to see if pref is set at startup to let plugins take over in
   // full page mode for certain image mime types that we handle internally
   mOverrideInternalTypes =
     Preferences::GetBool("plugin.override_internal_types", false);
 
   mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
 
   Preferences::AddStrongObserver(this, "plugin.disable");
@@ -298,16 +291,29 @@ nsPluginHost::nsPluginHost()
 #ifdef PLUGIN_LOGGING
   MOZ_LOG(nsPluginLogging::gNPNLog, PLUGIN_LOG_ALWAYS,("NPN Logging Active!\n"));
   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_ALWAYS,("General Plugin Logging Active! (nsPluginHost::ctor)\n"));
   MOZ_LOG(nsPluginLogging::gNPPLog, PLUGIN_LOG_ALWAYS,("NPP Logging Active!\n"));
 
   PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::ctor\n"));
   PR_LogFlush();
 #endif
+
+  // Load plugins on creation, as there's a good chance we'll need to send them
+  // to content processes directly after creation.
+  if (XRE_IsParentProcess())
+  {
+    // Always increment the chrome epoch when we bring up the nsPluginHost in
+    // the parent process. If the only plugins we have are cached in
+    // pluginreg.dat, we won't see any plugin changes in LoadPlugins and the
+    // epoch will stay the same between the parent and child process, meaning
+    // plugins will never update in the child process.
+    IncrementChromeEpoch();
+    LoadPlugins();
+  }
 }
 
 nsPluginHost::~nsPluginHost()
 {
   PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::dtor\n"));
 
   UnloadPlugins();
   sInst = nullptr;
@@ -355,18 +361,30 @@ bool nsPluginHost::IsRunningPlugin(nsPlu
   return false;
 }
 
 nsresult nsPluginHost::ReloadPlugins()
 {
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   ("nsPluginHost::ReloadPlugins Begin\n"));
 
-  nsresult rv = NS_OK;
-
+  // If we're calling this from a content process, forward the reload request to
+  // the parent process. If plugins actually changed, it will notify us
+  // asynchronously later.
+  if (XRE_IsContentProcess())
+  {
+    Unused << mozilla::dom::ContentChild::GetSingleton()->SendMaybeReloadPlugins();
+    // In content processes, always signal that plugins have not changed. We
+    // will never know if they changed here unless we make slow synchronous
+    // calls. This information will hopefully only be wrong once, as if there
+    // has been a plugin update, we expect to have gotten notification from the
+    // parent process and everything should be updated by the next time this is
+    // called. See Bug 1337058 for more info.
+    return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
+  }
   // this will create the initial plugin list out of cache
   // if it was not created yet
   if (!mPluginsLoaded)
     return LoadPlugins();
 
   // we are re-scanning plugins. New plugins may have been added, also some
   // plugins may have been removed, so we should probably shut everything down
   // but don't touch running (active and not stopped) plugins
@@ -377,16 +395,24 @@ nsresult nsPluginHost::ReloadPlugins()
   // look for possible changes
   bool pluginschanged = true;
   FindPlugins(false, &pluginschanged);
 
   // if no changed detected, return an appropriate error code
   if (!pluginschanged)
     return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
 
+  return ActuallyReloadPlugins();
+}
+
+nsresult
+nsPluginHost::ActuallyReloadPlugins()
+{
+  nsresult rv = NS_OK;
+
   // shutdown plugins and kill the list if there are no running plugins
   RefPtr<nsPluginTag> prev;
   RefPtr<nsPluginTag> next;
 
   for (RefPtr<nsPluginTag> p = mPlugins; p != nullptr;) {
     next = p->mNext;
 
     // only remove our plugin from the list if it's not running.
@@ -410,16 +436,23 @@ nsresult nsPluginHost::ReloadPlugins()
   }
 
   // set flags
   mPluginsLoaded = false;
 
   // load them again
   rv = LoadPlugins();
 
+  if (XRE_IsParentProcess())
+  {
+    // If the plugin list changed, update content. If the plugin list changed
+    // for the content process, it will also reload plugins.
+    SendPluginsToContent();
+  }
+
   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   ("nsPluginHost::ReloadPlugins End\n"));
 
   return rv;
 }
 
 #define NS_RETURN_UASTRING_SIZE 128
 
@@ -2271,21 +2304,21 @@ WatchRegKey(uint32_t aRoot, nsCOMPtr<nsI
     return;
   }
   aKey->StartWatching(true);
 }
 #endif
 
 nsresult nsPluginHost::LoadPlugins()
 {
-#ifdef ANDROID
+  // This should only be run in the parent process. On plugin list change, we'll
+  // update observers in the content process as part of SetPluginsInContent
   if (XRE_IsContentProcess()) {
     return NS_OK;
   }
-#endif
   // do not do anything if it is already done
   // use ReloadPlugins() to enforce loading
   if (mPluginsLoaded)
     return NS_OK;
 
   if (mPluginsDisabled)
     return NS_OK;
 
@@ -2310,42 +2343,34 @@ nsresult nsPluginHost::LoadPlugins()
     if (obsService)
       obsService->NotifyObservers(nullptr, "plugins-list-updated", nullptr);
   }
 
   return NS_OK;
 }
 
 nsresult
-nsPluginHost::FindPluginsInContent(bool aCreatePluginList, bool* aPluginsChanged)
+nsPluginHost::SetPluginsInContent(uint32_t aPluginEpoch,
+                                  nsTArray<mozilla::plugins::PluginTag>& aPlugins,
+                                  nsTArray<mozilla::plugins::FakePluginTag>& aFakePlugins)
 {
   MOZ_ASSERT(XRE_IsContentProcess());
 
-  dom::ContentChild* cp = dom::ContentChild::GetSingleton();
-  nsresult rv;
   nsTArray<PluginTag> plugins;
+
   nsTArray<FakePluginTag> fakePlugins;
-  uint32_t parentEpoch;
-  if (!cp->SendFindPlugins(ChromeEpochForContent(), &rv, &plugins, &fakePlugins, &parentEpoch) ||
-      NS_FAILED(rv)) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  if (parentEpoch != ChromeEpochForContent()) {
-    *aPluginsChanged = true;
-    if (!aCreatePluginList) {
-      return NS_OK;
-    }
-
-    // Don't do this if aCreatePluginList is false. Otherwise, when we actually
-    // want to create the list, we'll come back here and do nothing.
-    SetChromeEpochForContent(parentEpoch);
-
-    for (size_t i = 0; i < plugins.Length(); i++) {
-      PluginTag& tag = plugins[i];
+
+  if (aPluginEpoch != ChromeEpochForContent()) {
+    // Since we know we're going to be repopulating the lists anyways, trigger a
+    // reload now to clear out all old entries.
+    ActuallyReloadPlugins();
+
+    SetChromeEpochForContent(aPluginEpoch);
+
+    for (auto tag : aPlugins) {
 
       // Don't add the same plugin again.
       if (nsPluginTag* existing = PluginWithId(tag.id())) {
         UpdateInMemoryPluginInfo(existing);
         continue;
       }
 
       nsPluginTag *pluginTag = new nsPluginTag(tag.id(),
@@ -2362,17 +2387,17 @@ nsPluginHost::FindPluginsInContent(bool 
                                                tag.supportsAsyncInit(),
                                                tag.supportsAsyncRender(),
                                                tag.lastModifiedTime(),
                                                tag.isFromExtension(),
                                                tag.sandboxLevel());
       AddPluginTag(pluginTag);
     }
 
-    for (const auto& tag : fakePlugins) {
+    for (const auto& tag : aFakePlugins) {
       // Don't add the same plugin again.
       for (const auto& existingTag : mFakePlugins) {
         if (existingTag->Id() == tag.id()) {
           continue;
         }
       }
 
       RefPtr<nsFakePluginTag> pluginTag =
@@ -2389,16 +2414,22 @@ nsPluginHost::FindPluginsInContent(bool 
         Preferences::GetCString(kPrefDisableFullPage);
       for (uint32_t i = 0; i < pluginTag->MimeTypes().Length(); i++) {
         if (!IsTypeInList(pluginTag->MimeTypes()[i], disableFullPage)) {
           RegisterWithCategoryManager(pluginTag->MimeTypes()[i],
                                       ePluginRegister);
         }
       }
     }
+
+    nsCOMPtr<nsIObserverService> obsService =
+      mozilla::services::GetObserverService();
+    if (obsService) {
+      obsService->NotifyObservers(nullptr, "plugins-list-updated", nullptr);
+    }
   }
 
   mPluginsLoaded = true;
   return NS_OK;
 }
 
 // if aCreatePluginList is false we will just scan for plugins
 // and see if any changes have been made to the plugins.
@@ -2406,18 +2437,20 @@ nsPluginHost::FindPluginsInContent(bool 
 nsresult nsPluginHost::FindPlugins(bool aCreatePluginList, bool * aPluginsChanged)
 {
   Telemetry::AutoTimer<Telemetry::FIND_PLUGINS> telemetry;
 
   NS_ENSURE_ARG_POINTER(aPluginsChanged);
 
   *aPluginsChanged = false;
 
+  // If plugins are found or change, the content process will be notified by the
+  // parent process. Bail out early if this is called from the content process.
   if (XRE_IsContentProcess()) {
-    return FindPluginsInContent(aCreatePluginList, aPluginsChanged);
+    return NS_OK;
   }
 
   nsresult rv;
 
   // Read cached plugins info. If the profile isn't yet available then don't
   // scan for plugins
   if (ReadPluginInfo() == NS_ERROR_NOT_AVAILABLE)
     return NS_OK;
@@ -2536,90 +2569,80 @@ nsresult nsPluginHost::FindPlugins(bool 
   // No more need for cached plugins. Clear it up.
   NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
   NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
 
   return NS_OK;
 }
 
 nsresult
-mozilla::plugins::FindPluginsForContent(uint32_t aPluginEpoch,
-                                        nsTArray<PluginTag>* aPlugins,
-                                        nsTArray<FakePluginTag>* aFakePlugins,
-                                        uint32_t* aNewPluginEpoch)
+nsPluginHost::SendPluginsToContent()
 {
   MOZ_ASSERT(XRE_IsParentProcess());
 
-  RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
-  return host->FindPluginsForContent(aPluginEpoch, aPlugins, aFakePlugins, aNewPluginEpoch);
-}
-
-nsresult
-nsPluginHost::FindPluginsForContent(uint32_t aPluginEpoch,
-                                    nsTArray<PluginTag>* aPlugins,
-                                    nsTArray<FakePluginTag>* aFakePlugins,
-                                    uint32_t* aNewPluginEpoch)
-{
-  MOZ_ASSERT(XRE_IsParentProcess());
-
+  nsTArray<PluginTag> pluginTags;
+  nsTArray<FakePluginTag> fakePluginTags;
   // Load plugins so that the epoch is correct.
   nsresult rv = LoadPlugins();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  *aNewPluginEpoch = ChromeEpoch();
-  if (aPluginEpoch == ChromeEpoch()) {
-    return NS_OK;
-  }
+  uint32_t newPluginEpoch = ChromeEpoch();
 
   nsTArray<nsCOMPtr<nsIInternalPluginTag>> plugins;
   GetPlugins(plugins, true);
 
   for (size_t i = 0; i < plugins.Length(); i++) {
     nsCOMPtr<nsIInternalPluginTag> basetag = plugins[i];
 
     nsCOMPtr<nsIFakePluginTag> faketag = do_QueryInterface(basetag);
     if (faketag) {
       /// FIXME-jsplugins - We need to add a nsIInternalPluginTag->AsNative() to
       /// avoid this hacky static cast
       nsFakePluginTag* tag = static_cast<nsFakePluginTag*>(basetag.get());
       mozilla::ipc::URIParams handlerURI;
       SerializeURI(tag->HandlerURI(), handlerURI);
-      aFakePlugins->AppendElement(FakePluginTag(tag->Id(),
-                                                handlerURI,
-                                                tag->Name(),
-                                                tag->Description(),
-                                                tag->MimeTypes(),
-                                                tag->MimeDescriptions(),
-                                                tag->Extensions(),
-                                                tag->GetNiceFileName(),
-                                                tag->SandboxScript()));
+      fakePluginTags.AppendElement(FakePluginTag(tag->Id(),
+                                                 handlerURI,
+                                                 tag->Name(),
+                                                 tag->Description(),
+                                                 tag->MimeTypes(),
+                                                 tag->MimeDescriptions(),
+                                                 tag->Extensions(),
+                                                 tag->GetNiceFileName(),
+                                                 tag->SandboxScript()));
       continue;
     }
 
     /// FIXME-jsplugins - We need to cleanup the various plugintag classes
     /// to be more sane and avoid this dance
     nsPluginTag *tag = static_cast<nsPluginTag *>(basetag.get());
 
-    aPlugins->AppendElement(PluginTag(tag->mId,
-                                      tag->Name(),
-                                      tag->Description(),
-                                      tag->MimeTypes(),
-                                      tag->MimeDescriptions(),
-                                      tag->Extensions(),
-                                      tag->mIsJavaPlugin,
-                                      tag->mIsFlashPlugin,
-                                      tag->mSupportsAsyncInit,
-                                      tag->mSupportsAsyncRender,
-                                      tag->FileName(),
-                                      tag->Version(),
-                                      tag->mLastModifiedTime,
-                                      tag->IsFromExtension(),
-                                      tag->mSandboxLevel));
+    pluginTags.AppendElement(PluginTag(tag->mId,
+                                       tag->Name(),
+                                       tag->Description(),
+                                       tag->MimeTypes(),
+                                       tag->MimeDescriptions(),
+                                       tag->Extensions(),
+                                       tag->mIsJavaPlugin,
+                                       tag->mIsFlashPlugin,
+                                       tag->mSupportsAsyncInit,
+                                       tag->mSupportsAsyncRender,
+                                       tag->FileName(),
+                                       tag->Version(),
+                                       tag->mLastModifiedTime,
+                                       tag->IsFromExtension(),
+                                       tag->mSandboxLevel));
+  }
+  nsTArray<dom::ContentParent*> parents;
+  dom::ContentParent::GetAll(parents);
+  for (auto p : parents)
+  {
+    Unused << p->SendSetPluginList(newPluginEpoch, pluginTags, fakePluginTags);
   }
   return NS_OK;
 }
 
 void
 nsPluginHost::UpdateInMemoryPluginInfo(nsPluginTag* aPluginTag)
 {
   NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
--- a/dom/plugins/base/nsPluginHost.h
+++ b/dom/plugins/base/nsPluginHost.h
@@ -247,16 +247,20 @@ public:
 
   void CreateWidget(nsPluginInstanceOwner* aOwner);
 
   nsresult EnumerateSiteData(const nsACString& domain,
                              const InfallibleTArray<nsCString>& sites,
                              InfallibleTArray<nsCString>& result,
                              bool firstMatchOnly);
 
+  nsresult SendPluginsToContent();
+  nsresult SetPluginsInContent(uint32_t aPluginEpoch,
+                               nsTArray<mozilla::plugins::PluginTag>& aPlugins,
+                               nsTArray<mozilla::plugins::FakePluginTag>& aFakePlugins);
 private:
   friend class nsPluginUnloadRunnable;
 
   void DestroyRunningInstances(nsPluginTag* aPluginTag);
 
   // Writes updated plugins settings to disk and unloads the plugin
   // if it is now disabled. Should only be called by the plugin tag in question
   void UpdatePluginInfo(nsPluginTag* aPluginTag);
@@ -296,18 +300,16 @@ private:
   // be filled in with the MIME type the plugin is registered for.
   nsPluginTag* FindNativePluginForExtension(const nsACString & aExtension,
                                             /* out */ nsACString & aMimeType,
                                             bool aCheckEnabled);
 
   nsresult
   FindStoppedPluginForURL(nsIURI* aURL, nsIPluginInstanceOwner *aOwner);
 
-  nsresult FindPluginsInContent(bool aCreatePluginList, bool * aPluginsChanged);
-
   nsresult
   FindPlugins(bool aCreatePluginList, bool * aPluginsChanged);
 
   // FIXME revisit, no ns prefix
   // Registers or unregisters the given mime type with the category manager
   enum nsRegisterType { ePluginRegister,
                         ePluginUnregister,
                         // Checks if this type should still be registered first
@@ -363,16 +365,18 @@ private:
 
   // To be used by the content process to get/set the last observed epoch value
   // from the chrome process.
   uint32_t ChromeEpochForContent();
   void SetChromeEpochForContent(uint32_t aEpoch);
 
   void UpdateInMemoryPluginInfo(nsPluginTag* aPluginTag);
 
+  nsresult ActuallyReloadPlugins();
+
   RefPtr<nsPluginTag> mPlugins;
   RefPtr<nsPluginTag> mCachedPlugins;
   RefPtr<nsInvalidPluginTag> mInvalidPlugins;
 
   nsTArray< RefPtr<nsFakePluginTag> > mFakePlugins;
 
   bool mPluginsLoaded;
 
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -860,18 +860,16 @@ description =
 [PContent::BridgeToChildProcess]
 description =
 [PContent::LoadPlugin]
 description =
 [PContent::ConnectPluginBridge]
 description =
 [PContent::GetBlocklistState]
 description =
-[PContent::FindPlugins]
-description =
 [PContent::NSSU2FTokenIsCompatibleVersion]
 description =
 [PContent::NSSU2FTokenIsRegistered]
 description =
 [PContent::NSSU2FTokenRegister]
 description =
 [PContent::NSSU2FTokenSign]
 description =
--- a/ipc/mscom/Interceptor.cpp
+++ b/ipc/mscom/Interceptor.cpp
@@ -13,57 +13,122 @@
 #include "mozilla/mscom/MainThreadInvoker.h"
 #include "mozilla/mscom/Registration.h"
 #include "mozilla/mscom/Utils.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
+#include "nsRefPtrHashtable.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace mscom {
 
+class LiveSet final
+{
+public:
+  LiveSet()
+    : mMutex("mozilla::mscom::LiveSet::mMutex")
+  {
+  }
+
+  void Lock()
+  {
+    mMutex.Lock();
+  }
+
+  void Unlock()
+  {
+    mMutex.Unlock();
+  }
+
+  void Put(IUnknown* aKey, already_AddRefed<IWeakReference> aValue)
+  {
+    mMutex.AssertCurrentThreadOwns();
+    mLiveSet.Put(aKey, Move(aValue));
+  }
+
+  RefPtr<IWeakReference> Get(IUnknown* aKey)
+  {
+    mMutex.AssertCurrentThreadOwns();
+    RefPtr<IWeakReference> result;
+    mLiveSet.Get(aKey, getter_AddRefs(result));
+    return result;
+  }
+
+  void Remove(IUnknown* aKey)
+  {
+    mMutex.AssertCurrentThreadOwns();
+    mLiveSet.Remove(aKey);
+  }
+
+  typedef BaseAutoLock<LiveSet> AutoLock;
+
+private:
+  Mutex mMutex;
+  nsRefPtrHashtable<nsPtrHashKey<IUnknown>, IWeakReference> mLiveSet;
+};
+
+static LiveSet&
+GetLiveSet()
+{
+  static LiveSet sLiveSet;
+  return sLiveSet;
+}
+
 /* static */ HRESULT
 Interceptor::Create(STAUniquePtr<IUnknown> aTarget, IInterceptorSink* aSink,
-                    REFIID aIid, void** aOutput)
+                    REFIID aInitialIid, void** aOutInterface)
 {
-  MOZ_ASSERT(aOutput && aTarget && aSink);
-  if (!aOutput) {
+  MOZ_ASSERT(aOutInterface && aTarget && aSink);
+  if (!aOutInterface) {
     return E_INVALIDARG;
   }
 
-  *aOutput = nullptr;
+  LiveSet::AutoLock lock(GetLiveSet());
+
+  RefPtr<IWeakReference> existingInterceptor(Move(GetLiveSet().Get(aTarget.get())));
+  if (existingInterceptor &&
+      SUCCEEDED(existingInterceptor->Resolve(aInitialIid, aOutInterface))) {
+    return S_OK;
+  }
+
+  *aOutInterface = nullptr;
 
   if (!aTarget || !aSink) {
     return E_INVALIDARG;
   }
 
-  RefPtr<WeakReferenceSupport> intcpt(new Interceptor(Move(aTarget), aSink));
-  return intcpt->QueryInterface(aIid, aOutput);
+  RefPtr<Interceptor> intcpt(new Interceptor(aSink));
+  return intcpt->GetInitialInterceptorForIID(aInitialIid, Move(aTarget),
+                                             aOutInterface);
 }
 
-Interceptor::Interceptor(STAUniquePtr<IUnknown> aTarget, IInterceptorSink* aSink)
+Interceptor::Interceptor(IInterceptorSink* aSink)
   : WeakReferenceSupport(WeakReferenceSupport::Flags::eDestroyOnMainThread)
-  , mTarget(Move(aTarget))
   , mEventSink(aSink)
   , mMutex("mozilla::mscom::Interceptor::mMutex")
   , mStdMarshal(nullptr)
 {
   MOZ_ASSERT(aSink);
-  MOZ_ASSERT(!IsProxy(mTarget.get()));
   RefPtr<IWeakReference> weakRef;
   if (SUCCEEDED(GetWeakReference(getter_AddRefs(weakRef)))) {
     aSink->SetInterceptor(weakRef);
   }
 }
 
 Interceptor::~Interceptor()
 {
+  { // Scope for lock
+    LiveSet::AutoLock lock(GetLiveSet());
+    GetLiveSet().Remove(mTarget.get());
+  }
+
   // This needs to run on the main thread because it releases target interface
   // reference counts which may not be thread-safe.
   MOZ_ASSERT(NS_IsMainThread());
   for (uint32_t index = 0, len = mInterceptorMap.Length(); index < len; ++index) {
     MapEntry& entry = mInterceptorMap[index];
     entry.mInterceptor = nullptr;
     entry.mTargetInterface->Release();
   }
@@ -200,16 +265,72 @@ Interceptor::CreateInterceptor(REFIID aI
                                       (void**)aOutput);
   // If this assert fires then the interceptor doesn't like something about
   // the format of the typelib. One thing in particular that it doesn't like
   // is complex types that contain unions.
   MOZ_ASSERT(SUCCEEDED(hr));
   return hr;
 }
 
+HRESULT
+Interceptor::GetInitialInterceptorForIID(REFIID aTargetIid,
+                                         STAUniquePtr<IUnknown> aTarget,
+                                         void** aOutInterceptor)
+{
+  MOZ_ASSERT(aOutInterceptor);
+  MOZ_ASSERT(aTargetIid != IID_IUnknown && aTargetIid != IID_IMarshal);
+  MOZ_ASSERT(!IsProxy(aTarget.get()));
+
+  // Raise the refcount for stabilization purposes during aggregation
+  RefPtr<IUnknown> kungFuDeathGrip(static_cast<IUnknown*>(
+        static_cast<WeakReferenceSupport*>(this)));
+
+  RefPtr<IUnknown> unkInterceptor;
+  HRESULT hr = CreateInterceptor(aTargetIid, kungFuDeathGrip,
+                                 getter_AddRefs(unkInterceptor));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  RefPtr<ICallInterceptor> interceptor;
+  hr = unkInterceptor->QueryInterface(IID_ICallInterceptor,
+                                      getter_AddRefs(interceptor));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = interceptor->RegisterSink(mEventSink);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  RefPtr<IWeakReference> weakRef;
+  hr = GetWeakReference(getter_AddRefs(weakRef));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // mTarget is a weak reference to aTarget. This is safe because we transfer
+  // ownership of aTarget into mInterceptorMap which remains live for the
+  // lifetime of this Interceptor.
+  mTarget = ToInterceptorTargetPtr(aTarget);
+  GetLiveSet().Put(mTarget.get(), weakRef.forget());
+
+  // Now we transfer aTarget's ownership into mInterceptorMap.
+  mInterceptorMap.AppendElement(MapEntry(aTargetIid,
+                                         unkInterceptor,
+                                         aTarget.release()));
+
+  if (mEventSink->MarshalAs(aTargetIid) == aTargetIid) {
+    return unkInterceptor->QueryInterface(aTargetIid, aOutInterceptor);
+  }
+
+  return GetInterceptorForIID(aTargetIid, aOutInterceptor);
+}
+
 /**
  * This method contains the core guts of the handling of QueryInterface calls
  * that are delegated to us from the ICallInterceptor.
  *
  * @param aIid ID of the desired interface
  * @param aOutInterceptor The resulting emulated vtable that corresponds to
  * the interface specified by aIid.
  */
--- a/ipc/mscom/Interceptor.h
+++ b/ipc/mscom/Interceptor.h
@@ -62,17 +62,17 @@ struct IInterceptor : public IUnknown
  */
 class Interceptor final : public WeakReferenceSupport
                         , public IStdMarshalInfo
                         , public IMarshal
                         , public IInterceptor
 {
 public:
   static HRESULT Create(STAUniquePtr<IUnknown> aTarget, IInterceptorSink* aSink,
-                        REFIID aIid, void** aOutput);
+                        REFIID aInitialIid, void** aOutInterface);
 
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
   STDMETHODIMP_(ULONG) AddRef() override;
   STDMETHODIMP_(ULONG) Release() override;
 
   // IStdMarshalInfo
   STDMETHODIMP GetClassForHandler(DWORD aDestContext, void* aDestContextPtr,
@@ -101,32 +101,54 @@ public:
 private:
   struct MapEntry
   {
     MapEntry(REFIID aIid, IUnknown* aInterceptor, IUnknown* aTargetInterface)
       : mIID(aIid)
       , mInterceptor(aInterceptor)
       , mTargetInterface(aTargetInterface)
     {}
-    IID               mIID;
+
+    MapEntry(const MapEntry& aOther)
+      : mIID(aOther.mIID)
+      , mInterceptor(aOther.mInterceptor)
+      , mTargetInterface(aOther.mTargetInterface)
+    {
+    }
+
+    MapEntry(MapEntry&& aOther)
+      : mIID(aOther.mIID)
+      , mInterceptor(Move(aOther.mInterceptor))
+      , mTargetInterface(aOther.mTargetInterface)
+    {
+      aOther.mTargetInterface = nullptr;
+    }
+
+    MapEntry& operator=(const MapEntry& aOther) = delete;
+    MapEntry& operator=(MapEntry&& aOther) = delete;
+
+    REFIID            mIID;
     RefPtr<IUnknown>  mInterceptor;
     IUnknown*         mTargetInterface;
   };
 
 private:
-  Interceptor(STAUniquePtr<IUnknown> aTarget, IInterceptorSink* aSink);
+  explicit Interceptor(IInterceptorSink* aSink);
   ~Interceptor();
+  HRESULT GetInitialInterceptorForIID(REFIID aTargetIid,
+                                      STAUniquePtr<IUnknown> aTarget,
+                                      void** aOutInterface);
   MapEntry* Lookup(REFIID aIid);
   HRESULT QueryInterfaceTarget(REFIID aIid, void** aOutput);
   HRESULT ThreadSafeQueryInterface(REFIID aIid,
                                    IUnknown** aOutInterface) override;
   HRESULT CreateInterceptor(REFIID aIid, IUnknown* aOuter, IUnknown** aOutput);
 
 private:
-  STAUniquePtr<IUnknown>    mTarget;
+  InterceptorTargetPtr<IUnknown>  mTarget;
   RefPtr<IInterceptorSink>  mEventSink;
   mozilla::Mutex            mMutex; // Guards mInterceptorMap
   // Using a nsTArray since the # of interfaces is not going to be very high
   nsTArray<MapEntry>        mInterceptorMap;
   RefPtr<IUnknown>          mStdMarshalUnk;
   IMarshal*                 mStdMarshal; // WEAK
 };
 
--- a/ipc/mscom/MainThreadHandoff.cpp
+++ b/ipc/mscom/MainThreadHandoff.cpp
@@ -500,17 +500,20 @@ MainThreadHandoff::OnWalkInterface(REFII
 
   if (!origInterface) {
     // Nothing to wrap.
     return S_OK;
   }
 
   // First make sure that aInterface isn't a proxy - we don't want to wrap
   // those.
-  MOZ_ASSERT(!IsProxy(origInterface.get()));
+  if (IsProxy(origInterface.get())) {
+    *aInterface = origInterface.release();
+    return S_OK;
+  }
 
   RefPtr<IInterceptor> interceptor;
   HRESULT hr = mInterceptor->Resolve(IID_IInterceptor,
                                      (void**) getter_AddRefs(interceptor));
   MOZ_ASSERT(SUCCEEDED(hr));
   if (FAILED(hr)) {
     return hr;
   }
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1297,16 +1297,22 @@ js::GetDOMProxyShadowsCheck()
 }
 
 bool
 js::detail::IdMatchesAtom(jsid id, JSAtom* atom)
 {
     return id == INTERNED_STRING_TO_JSID(nullptr, atom);
 }
 
+bool
+js::detail::IdMatchesAtom(jsid id, JSString* atom)
+{
+    return id == INTERNED_STRING_TO_JSID(nullptr, atom);
+}
+
 JS_FRIEND_API(void)
 js::PrepareScriptEnvironmentAndInvoke(JSContext* cx, HandleObject scope, ScriptEnvironmentPreparer::Closure& closure)
 {
     MOZ_ASSERT(!cx->isExceptionPending());
 
     MOZ_RELEASE_ASSERT(cx->runtime()->scriptEnvironmentPreparer,
                        "Embedding needs to set a scriptEnvironmentPreparer callback");
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -2597,16 +2597,17 @@ JSID_FROM_BITS(size_t bits)
     jsid id;
     JSID_BITS(id) = bits;
     return id;
 }
 
 namespace js {
 namespace detail {
 bool IdMatchesAtom(jsid id, JSAtom* atom);
+bool IdMatchesAtom(jsid id, JSString* atom);
 } // namespace detail
 } // namespace js
 
 /**
  * Must not be used on atoms that are representable as integer jsids.
  * Prefer NameToId or AtomToId over this function:
  *
  * A PropertyName is an atom that does not contain an integer in the range
@@ -2630,16 +2631,25 @@ static MOZ_ALWAYS_INLINE jsid
 NON_INTEGER_ATOM_TO_JSID(JSAtom* atom)
 {
     MOZ_ASSERT(((size_t)atom & 0x7) == 0);
     jsid id = JSID_FROM_BITS((size_t)atom);
     MOZ_ASSERT(js::detail::IdMatchesAtom(id, atom));
     return id;
 }
 
+static MOZ_ALWAYS_INLINE jsid
+NON_INTEGER_ATOM_TO_JSID(JSString* atom)
+{
+    MOZ_ASSERT(((size_t)atom & 0x7) == 0);
+    jsid id = JSID_FROM_BITS((size_t)atom);
+    MOZ_ASSERT(js::detail::IdMatchesAtom(id, atom));
+    return id;
+}
+
 /* All strings stored in jsids are atomized, but are not necessarily property names. */
 static MOZ_ALWAYS_INLINE bool
 JSID_IS_ATOM(jsid id)
 {
     return JSID_IS_STRING(id);
 }
 
 static MOZ_ALWAYS_INLINE bool
--- a/mfbt/WindowsVersion.h
+++ b/mfbt/WindowsVersion.h
@@ -79,16 +79,54 @@ IsWindowsBuildOrLater(uint32_t aBuild)
     minBuild = aBuild;
     return true;
   }
 
   maxBuild = aBuild;
   return false;
 }
 
+inline bool
+IsWindows10BuildOrLater(uint32_t aBuild)
+{
+  static uint32_t minBuild = 0;
+  static uint32_t maxBuild = UINT32_MAX;
+
+  if (minBuild >= aBuild) {
+    return true;
+  }
+
+  if (aBuild >= maxBuild) {
+    return false;
+  }
+
+  OSVERSIONINFOEX info;
+  ZeroMemory(&info, sizeof(OSVERSIONINFOEX));
+  info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+  info.dwMajorVersion = 10;
+  info.dwBuildNumber = aBuild;
+
+  DWORDLONG conditionMask = 0;
+  VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
+  VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
+  VER_SET_CONDITION(conditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
+  VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
+  VER_SET_CONDITION(conditionMask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
+
+  if (VerifyVersionInfo(&info, VER_MAJORVERSION | VER_MINORVERSION |
+                        VER_BUILDNUMBER | VER_SERVICEPACKMAJOR |
+                        VER_SERVICEPACKMINOR, conditionMask)) {
+    minBuild = aBuild;
+    return true;
+  }
+
+  maxBuild = aBuild;
+  return false;
+}
+
 MOZ_ALWAYS_INLINE bool
 IsWin7SP1OrLater()
 {
   return IsWindowsVersionOrLater(0x06010100ul);
 }
 
 MOZ_ALWAYS_INLINE bool
 IsWin8OrLater()
@@ -104,16 +142,22 @@ IsWin8Point1OrLater()
 
 MOZ_ALWAYS_INLINE bool
 IsWin10OrLater()
 {
   return IsWindowsVersionOrLater(0x0a000000ul);
 }
 
 MOZ_ALWAYS_INLINE bool
+IsWin10CreatorsUpdateOrLater()
+{
+  return IsWindows10BuildOrLater(15063);
+}
+
+MOZ_ALWAYS_INLINE bool
 IsNotWin7PreRTM()
 {
   return IsWin7SP1OrLater() || IsWindowsBuildOrLater(7600);
 }
 
 } // namespace mozilla
 
 #endif /* mozilla_WindowsVersion_h */
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -280,17 +280,17 @@ nsresult nsZipHandle::Init(const uint8_t
 //                                    format version. Currently equal to 2.
 //    32 bits       : pubKeyLength  - Unsigned integer representing the length
 //                                    of the public key in bytes.
 //    32 bits       : sigLength     - Unsigned integer representing the length
 //                                    of the signature in bytes.
 //    pubKeyLength  : publicKey     - Contents of the author's public key.
 //    sigLength     : signature     - Signature of the ZIP content.
 //                                    Signature is created using the RSA
-//                                    algorighm with the SHA-1 hash function.
+//                                    algorithm with the SHA-1 hash function.
 nsresult nsZipHandle::findDataStart()
 {
   // In the CRX header, integers are 32 bits. Our pointer to the file is of
   // type |uint8_t|, which is guaranteed to be 8 bits.
   const uint32_t CRXIntSize = 4;
 
 MOZ_WIN_MEM_TRY_BEGIN
   if (mTotalLen > CRXIntSize * 4 && xtolong(mFileStart) == kCRXMagic) {
--- a/taskcluster/taskgraph/transforms/job/mozharness_test.py
+++ b/taskcluster/taskgraph/transforms/job/mozharness_test.py
@@ -442,17 +442,17 @@ def mozharness_test_buildbot_bridge(conf
         variant = ''
         if m and m.group(1):
             variant = m.group(1) + ' '
         # On beta and release, we run nightly builds on-push; the talos
         # builders need to run against non-nightly buildernames
         if variant == 'nightly ':
             variant = ''
         # this variant name has branch after the variant type in BBB bug 1338871
-        if variant == 'stylo ' or 'stylo-sequential':
+        if variant in ('stylo', 'stylo-sequential'):
             buildername = '{} {}{} talos {}'.format(
                 BUILDER_NAME_PREFIX[platform],
                 variant,
                 branch,
                 test_name
             )
         else:
             buildername = '{} {} {}talos {}'.format(
--- a/toolkit/components/extensions/ExtensionStorage.jsm
+++ b/toolkit/components/extensions/ExtensionStorage.jsm
@@ -137,21 +137,21 @@ this.ExtensionStorage = {
       "ExtensionStorage: Finish writing extension data",
       promise);
 
     return promise.then(() => {
       AsyncShutdown.profileBeforeChange.removeBlocker(promise);
     });
   },
 
-  set(extensionId, items, context) {
+  set(extensionId, items) {
     return this.read(extensionId).then(extData => {
       let changes = {};
       for (let prop in items) {
-        let item = this.sanitize(items[prop], context);
+        let item = items[prop];
         changes[prop] = {oldValue: extData[prop], newValue: item};
         extData[prop] = item;
       }
 
       this.notifyListeners(extensionId, changes);
 
       return this.write(extensionId);
     });
--- a/toolkit/components/extensions/ext-storage.js
+++ b/toolkit/components/extensions/ext-storage.js
@@ -26,17 +26,17 @@ this.storage = class extends ExtensionAP
     let {extension} = context;
     return {
       storage: {
         local: {
           get: function(spec) {
             return ExtensionStorage.get(extension.id, spec);
           },
           set: function(items) {
-            return ExtensionStorage.set(extension.id, items, context);
+            return ExtensionStorage.set(extension.id, items);
           },
           remove: function(keys) {
             return ExtensionStorage.remove(extension.id, keys);
           },
           clear: function() {
             return ExtensionStorage.clear(extension.id);
           },
         },
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -949,17 +949,17 @@ function handleUpdateFailure(update, err
       }
     }
 
     let cancelations = getPref("getIntPref", PREF_APP_UPDATE_CANCELATIONS, 0);
     cancelations++;
     Services.prefs.setIntPref(PREF_APP_UPDATE_CANCELATIONS, cancelations);
     if (AppConstants.platform == "macosx") {
       let osxCancelations = getPref("getIntPref",
-                                  PREF_APP_UPDATE_CANCELATIONS_OSX, 0);
+                                    PREF_APP_UPDATE_CANCELATIONS_OSX, 0);
       osxCancelations++;
       Services.prefs.setIntPref(PREF_APP_UPDATE_CANCELATIONS_OSX,
                                 osxCancelations);
       let maxCancels = getPref("getIntPref",
                                PREF_APP_UPDATE_CANCELATIONS_OSX_MAX,
                                DEFAULT_CANCELATIONS_OSX_MAX);
       // Prevent the preference from setting a value greater than 5.
       maxCancels = Math.min(maxCancels, 5);
@@ -1781,16 +1781,19 @@ UpdateService.prototype = {
       // current state to the updates.xml so it is possible to track failures.
       um.saveUpdates();
       // Rotate the update logs so the update log isn't removed. By passing
       // false the patch directory won't be removed.
       cleanUpUpdatesDir(false);
     }
 
     if (status == STATE_SUCCEEDED) {
+      if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CANCELATIONS)) {
+        Services.prefs.clearUserPref(PREF_APP_UPDATE_CANCELATIONS);
+      }
       update.statusText = gUpdateBundle.GetStringFromName("installSuccess");
 
       // Update the patch's metadata.
       um.activeUpdate = update;
 
       // Done with this update. Clean it up.
       cleanupActiveUpdate();
 
--- a/toolkit/mozapps/update/tests/data/shared.js
+++ b/toolkit/mozapps/update/tests/data/shared.js
@@ -6,16 +6,17 @@
 /* eslint-disable no-undef */
 
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const PREF_APP_UPDATE_AUTO                       = "app.update.auto";
 const PREF_APP_UPDATE_BACKGROUNDERRORS           = "app.update.backgroundErrors";
 const PREF_APP_UPDATE_BACKGROUNDMAXERRORS        = "app.update.backgroundMaxErrors";
+const PREF_APP_UPDATE_CANCELATIONS               = "app.update.cancelations";
 const PREF_APP_UPDATE_CHANNEL                    = "app.update.channel";
 const PREF_APP_UPDATE_DOORHANGER                 = "app.update.doorhanger";
 const PREF_APP_UPDATE_DOWNLOADPROMPTATTEMPTS     = "app.update.download.attempts";
 const PREF_APP_UPDATE_DOWNLOADPROMPTMAXATTEMPTS  = "app.update.download.maxAttempts";
 const PREF_APP_UPDATE_DOWNLOADBACKGROUNDINTERVAL = "app.update.download.backgroundInterval";
 const PREF_APP_UPDATE_ENABLED                    = "app.update.enabled";
 const PREF_APP_UPDATE_IDLETIME                   = "app.update.idletime";
 const PREF_APP_UPDATE_LOG                        = "app.update.log";
--- a/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js
+++ b/toolkit/mozapps/update/tests/unit_aus_update/cleanupSuccessLogMove.js
@@ -3,28 +3,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 function run_test() {
   setupTestCommon();
 
   debugDump("testing that the update.log is moved after a successful update");
 
+  Services.prefs.setIntPref(PREF_APP_UPDATE_CANCELATIONS, 5);
+
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(""), false);
   let patches = getLocalPatchString(null, null, null, null, null, null,
                                     STATE_PENDING);
   let updates = getLocalUpdateString(patches);
   writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true);
   writeStatusFile(STATE_SUCCEEDED);
 
   let log = getUpdateLog(FILE_UPDATE_LOG);
   writeFile(log, "Last Update Log");
 
   standardInit();
 
+  let cancelations = Services.prefs.getIntPref(PREF_APP_UPDATE_CANCELATIONS, 0);
+  Assert.equal(cancelations, 0,
+               "the " + PREF_APP_UPDATE_CANCELATIONS + " preference " +
+               MSG_SHOULD_EQUAL);
+
   Assert.ok(!log.exists(), MSG_SHOULD_NOT_EXIST);
 
   log = getUpdateLog(FILE_LAST_UPDATE_LOG);
   Assert.ok(log.exists(), MSG_SHOULD_EXIST);
   Assert.equal(readFile(log), "Last Update Log",
                "the last update log contents" + MSG_SHOULD_EQUAL);
 
   log = getUpdateLog(FILE_BACKUP_UPDATE_LOG);
--- a/toolkit/mozapps/update/updater/updater.cpp
+++ b/toolkit/mozapps/update/updater/updater.cpp
@@ -62,23 +62,22 @@
 #include "mozilla/UniquePtr.h"
 
 // Amount of the progress bar to use in each of the 3 update stages,
 // should total 100.0.
 #define PROGRESS_PREPARE_SIZE 20.0f
 #define PROGRESS_EXECUTE_SIZE 75.0f
 #define PROGRESS_FINISH_SIZE   5.0f
 
-// Amount of time in ms to wait for the parent process to close
-#ifdef DEBUG
-// Use a large value for debug builds since the xpcshell tests take a long time.
-#define PARENT_WAIT 30000
-#else
-#define PARENT_WAIT 10000
-#endif
+// Maximum amount of time in ms to wait for the parent process to close. The
+// value should be the same or larger than the application's watchdog timeout
+// which is 60 seconds plus 3 additional seconds (see nsTerminator.cpp). This
+// makes it so when the application has a shutdown hang it won't break launching
+// the application after it has been updated.
+#define PARENT_WAIT 70000
 
 #if defined(XP_MACOSX)
 // These functions are defined in launchchild_osx.mm
 void CleanupElevatedMacUpdate(bool aFailureOccurred);
 bool IsOwnedByGroupAdmin(const char* aAppBundle);
 bool IsRecursivelyWritable(const char* aPath);
 void LaunchChild(int argc, const char** argv);
 void LaunchMacPostProcess(const char* aAppBundle);
--- a/tools/profiler/core/ProfileBuffer.h
+++ b/tools/profiler/core/ProfileBuffer.h
@@ -37,26 +37,28 @@ public:
 
   // Add |aTag| to the buffer, ignoring what kind of entry it is.
   void addTag(const ProfileBufferEntry& aTag);
 
   // Add to the buffer a sample start (ThreadId) entry for aThreadId. Also,
   // record the resulting generation and index in |aLS| if it's non-null.
   void addTagThreadId(int aThreadId, LastSample* aLS);
 
-  void StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId, double aSinceTime,
-                           JSContext* cx, UniqueStacks& aUniqueStacks);
+  void StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
+                           double aSinceTime, JSContext* cx,
+                           UniqueStacks& aUniqueStacks);
   void StreamMarkersToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
-                           const mozilla::TimeStamp& aStartTime,
+                           const mozilla::TimeStamp& aProcessStartTime,
                            double aSinceTime,
                            UniqueStacks& aUniqueStacks);
 
   // Find (via |aLS|) the most recent sample for the thread denoted by
-  // |aThreadId| and clone it, patching in |aStartTime| as appropriate.
-  bool DuplicateLastSample(int aThreadId, const mozilla::TimeStamp& aStartTime,
+  // |aThreadId| and clone it, patching in |aProcessStartTime| as appropriate.
+  bool DuplicateLastSample(int aThreadId,
+                           const mozilla::TimeStamp& aProcessStartTime,
                            LastSample& aLS);
 
   void addStoredMarker(ProfilerMarker* aStoredMarker);
 
   // The following two methods are not signal safe! They delete markers.
   void deleteExpiredStoredMarkers();
   void reset();
 
--- a/tools/profiler/core/ProfileBufferEntry.cpp
+++ b/tools/profiler/core/ProfileBufferEntry.cpp
@@ -707,30 +707,31 @@ void ProfileBuffer::StreamSamplesToJSON(
   if (sample.isSome()) {
     WriteSample(aWriter, *sample);
   }
 }
 
 void
 ProfileBuffer::StreamMarkersToJSON(SpliceableJSONWriter& aWriter,
                                    int aThreadId,
-                                   const TimeStamp& aStartTime,
+                                   const TimeStamp& aProcessStartTime,
                                    double aSinceTime,
                                    UniqueStacks& aUniqueStacks)
 {
   int readPos = mReadPos;
   int currentThreadID = -1;
   while (readPos != mWritePos) {
     ProfileBufferEntry entry = mEntries[readPos];
     if (entry.isThreadId()) {
       currentThreadID = entry.mTagInt;
     } else if (currentThreadID == aThreadId && entry.isMarker()) {
       const ProfilerMarker* marker = entry.getMarker();
       if (marker->GetTime() >= aSinceTime) {
-        entry.getMarker()->StreamJSON(aWriter, aStartTime, aUniqueStacks);
+        entry.getMarker()->StreamJSON(aWriter, aProcessStartTime,
+                                      aUniqueStacks);
       }
     }
     readPos = (readPos + 1) % mEntrySize;
   }
 }
 
 int
 ProfileBuffer::FindLastSampleOfThread(int aThreadId, const LastSample& aLS)
@@ -759,17 +760,18 @@ ProfileBuffer::FindLastSampleOfThread(in
 
   // |aLS| denotes a sample which is older than either two wraparounds or one
   // call to ProfileBuffer::reset.  In either case it is no longer valid.
   MOZ_ASSERT(aLS.mGeneration <= mGeneration - 2);
   return -1;
 }
 
 bool
-ProfileBuffer::DuplicateLastSample(int aThreadId, const TimeStamp& aStartTime,
+ProfileBuffer::DuplicateLastSample(int aThreadId,
+                                   const TimeStamp& aProcessStartTime,
                                    LastSample& aLS)
 {
   int lastSampleStartPos = FindLastSampleOfThread(aThreadId, aLS);
   if (lastSampleStartPos == -1) {
     return false;
   }
 
   MOZ_ASSERT(mEntries[lastSampleStartPos].isThreadId() &&
@@ -783,17 +785,17 @@ ProfileBuffer::DuplicateLastSample(int a
        readPos = (readPos + 1) % mEntrySize) {
     switch (mEntries[readPos].kind()) {
       case ProfileBufferEntry::Kind::ThreadId:
         // We're done.
         return true;
       case ProfileBufferEntry::Kind::Time:
         // Copy with new time
         addTag(ProfileBufferEntry::Time((TimeStamp::Now() -
-                                         aStartTime).ToMilliseconds()));
+                                         aProcessStartTime).ToMilliseconds()));
         break;
       case ProfileBufferEntry::Kind::Marker:
         // Don't copy markers
         break;
       default:
         // Copy anything else we don't know about.
         addTag(mEntries[readPos]);
         break;
--- a/tools/profiler/core/ProfilerBacktrace.cpp
+++ b/tools/profiler/core/ProfilerBacktrace.cpp
@@ -21,22 +21,22 @@ ProfilerBacktrace::ProfilerBacktrace(con
 ProfilerBacktrace::~ProfilerBacktrace()
 {
   MOZ_COUNT_DTOR(ProfilerBacktrace);
   delete mBuffer;
 }
 
 void
 ProfilerBacktrace::StreamJSON(SpliceableJSONWriter& aWriter,
-                              const TimeStamp& aStartTime,
+                              const TimeStamp& aProcessStartTime,
                               UniqueStacks& aUniqueStacks)
 {
   // This call to StreamSamplesAndMarkers() can safely pass in a non-null
   // JSContext. That's because StreamSamplesAndMarkers() only accesses the
   // JSContext when streaming JitReturnAddress entries, and such entries
   // never appear in synchronous samples.
   StreamSamplesAndMarkers(mName.get(), mThreadId,
-                          mBuffer, aWriter, aStartTime,
+                          mBuffer, aWriter, aProcessStartTime,
                           /* aSinceTime */ 0, /* aContext */ nullptr,
                           /* aSavedStreamedSamples */ nullptr,
                           /* aSavedStreamedMarkers */ nullptr,
                           aUniqueStacks);
 }
--- a/tools/profiler/core/ProfilerBacktrace.h
+++ b/tools/profiler/core/ProfilerBacktrace.h
@@ -23,17 +23,17 @@ public:
 
   // ProfilerBacktraces' stacks are deduplicated in the context of the
   // profile that contains the backtrace as a marker payload.
   //
   // That is, markers that contain backtraces should not need their own stack,
   // frame, and string tables. They should instead reuse their parent
   // profile's tables.
   void StreamJSON(SpliceableJSONWriter& aWriter,
-                  const mozilla::TimeStamp& aStartTime,
+                  const mozilla::TimeStamp& aProcessStartTime,
                   UniqueStacks& aUniqueStacks);
 
 private:
   ProfilerBacktrace(const ProfilerBacktrace&);
   ProfilerBacktrace& operator=(const ProfilerBacktrace&);
 
   mozilla::UniqueFreePtr<char> mName;
   int mThreadId;
--- a/tools/profiler/core/ProfilerMarker.h
+++ b/tools/profiler/core/ProfilerMarker.h
@@ -31,33 +31,33 @@ public:
 
   void SetGeneration(uint32_t aGenID) { mGenID = aGenID; }
 
   bool HasExpired(uint32_t aGenID) const { return mGenID + 2 <= aGenID; }
 
   double GetTime() const { return mTime; }
 
   void StreamJSON(SpliceableJSONWriter& aWriter,
-                  const mozilla::TimeStamp& aStartTime,
+                  const mozilla::TimeStamp& aProcessStartTime,
                   UniqueStacks& aUniqueStacks) const
   {
     // Schema:
     //   [name, time, data]
 
     aWriter.StartArrayElement();
     {
       aUniqueStacks.mUniqueStrings.WriteElement(aWriter, mMarkerName.get());
       aWriter.DoubleElement(mTime);
       // TODO: Store the callsite for this marker if available:
       // if have location data
       //   b.NameValue(marker, "location", ...);
       if (mPayload) {
         aWriter.StartObjectElement();
         {
-          mPayload->StreamPayload(aWriter, aStartTime, aUniqueStacks);
+          mPayload->StreamPayload(aWriter, aProcessStartTime, aUniqueStacks);
         }
         aWriter.EndObject();
       }
     }
     aWriter.EndArray();
   }
 
 private:
--- a/tools/profiler/core/ProfilerMarkerPayload.cpp
+++ b/tools/profiler/core/ProfilerMarkerPayload.cpp
@@ -24,32 +24,33 @@ ProfilerMarkerPayload::ProfilerMarkerPay
 
 ProfilerMarkerPayload::~ProfilerMarkerPayload()
 {
 }
 
 void
 ProfilerMarkerPayload::streamCommonProps(const char* aMarkerType,
                                          SpliceableJSONWriter& aWriter,
-                                         const TimeStamp& aStartTime,
+                                         const TimeStamp& aProcessStartTime,
                                          UniqueStacks& aUniqueStacks)
 {
   MOZ_ASSERT(aMarkerType);
   aWriter.StringProperty("type", aMarkerType);
   if (!mStartTime.IsNull()) {
     aWriter.DoubleProperty("startTime",
-                           (mStartTime - aStartTime).ToMilliseconds());
+                           (mStartTime - aProcessStartTime).ToMilliseconds());
   }
   if (!mEndTime.IsNull()) {
-    aWriter.DoubleProperty("endTime", (mEndTime - aStartTime).ToMilliseconds());
+    aWriter.DoubleProperty("endTime",
+                           (mEndTime - aProcessStartTime).ToMilliseconds());
   }
   if (mStack) {
     aWriter.StartObjectProperty("stack");
     {
-      mStack->StreamJSON(aWriter, aStartTime, aUniqueStacks);
+      mStack->StreamJSON(aWriter, aProcessStartTime, aUniqueStacks);
     }
     aWriter.EndObject();
   }
 }
 
 ProfilerMarkerTracing::ProfilerMarkerTracing(const char* aCategory,
                                              TracingKind aKind)
   : mCategory(aCategory)
@@ -65,20 +66,20 @@ ProfilerMarkerTracing::ProfilerMarkerTra
 {
   if (aCause) {
     SetStack(mozilla::Move(aCause));
   }
 }
 
 void
 ProfilerMarkerTracing::StreamPayload(SpliceableJSONWriter& aWriter,
-                                     const TimeStamp& aStartTime,
+                                     const TimeStamp& aProcessStartTime,
                                      UniqueStacks& aUniqueStacks)
 {
-  streamCommonProps("tracing", aWriter, aStartTime, aUniqueStacks);
+  streamCommonProps("tracing", aWriter, aProcessStartTime, aUniqueStacks);
 
   if (GetCategory()) {
     aWriter.StringProperty("category", GetCategory());
   }
 
   if (GetKind() == TRACING_INTERVAL_START) {
     aWriter.StringProperty("interval", "start");
   } else if (GetKind() == TRACING_INTERVAL_END) {
@@ -96,39 +97,40 @@ GPUMarkerPayload::GPUMarkerPayload(
   , mCpuTimeStart(aCpuTimeStart)
   , mCpuTimeEnd(aCpuTimeEnd)
   , mGpuTimeStart(aGpuTimeStart)
   , mGpuTimeEnd(aGpuTimeEnd)
 { }
 
 void
 GPUMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                const TimeStamp& aStartTime,
+                                const TimeStamp& aProcessStartTime,
                                 UniqueStacks& aUniqueStacks)
 {
-  streamCommonProps("gpu_timer_query", aWriter, aStartTime, aUniqueStacks);
+  streamCommonProps("gpu_timer_query", aWriter, aProcessStartTime,
+                    aUniqueStacks);
 
   aWriter.DoubleProperty("cpustart",
-                         (mCpuTimeStart - aStartTime).ToMilliseconds());
+                         (mCpuTimeStart - aProcessStartTime).ToMilliseconds());
   aWriter.DoubleProperty("cpuend",
-                         (mCpuTimeEnd - aStartTime).ToMilliseconds());
+                         (mCpuTimeEnd - aProcessStartTime).ToMilliseconds());
   aWriter.IntProperty("gpustart", (int)mGpuTimeStart);
   aWriter.IntProperty("gpuend", (int)mGpuTimeEnd);
 }
 
 ProfilerMarkerImagePayload::ProfilerMarkerImagePayload(gfxASurface *aImg)
   : mImg(aImg)
 { }
 
 void
 ProfilerMarkerImagePayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                          const TimeStamp& aStartTime,
+                                          const TimeStamp& aProcessStartTime,
                                           UniqueStacks& aUniqueStacks)
 {
-  streamCommonProps("innerHTML", aWriter, aStartTime, aUniqueStacks);
+  streamCommonProps("innerHTML", aWriter, aProcessStartTime, aUniqueStacks);
   // TODO: Finish me
   //aWriter.NameValue("innerHTML", "<img src=''/>");
 }
 
 IOMarkerPayload::IOMarkerPayload(const char* aSource,
                                  const char* aFilename,
                                  const mozilla::TimeStamp& aStartTime,
                                  const mozilla::TimeStamp& aEndTime,
@@ -142,20 +144,20 @@ IOMarkerPayload::IOMarkerPayload(const c
 }
 
 IOMarkerPayload::~IOMarkerPayload(){
   free(mFilename);
 }
 
 void
 IOMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                               const TimeStamp& aStartTime,
+                               const TimeStamp& aProcessStartTime,
                                UniqueStacks& aUniqueStacks)
 {
-  streamCommonProps("io", aWriter, aStartTime, aUniqueStacks);
+  streamCommonProps("io", aWriter, aProcessStartTime, aUniqueStacks);
   aWriter.StringProperty("source", mSource);
   if (mFilename != nullptr) {
     aWriter.StringProperty("filename", mFilename);
   }
 }
 
 UserTimingMarkerPayload::UserTimingMarkerPayload(const nsAString& aName,
                                                  const mozilla::TimeStamp& aStartTime)
@@ -175,20 +177,20 @@ UserTimingMarkerPayload::UserTimingMarke
 }
 
 UserTimingMarkerPayload::~UserTimingMarkerPayload()
 {
 }
 
 void
 UserTimingMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                       const TimeStamp& aStartTime,
+                                       const TimeStamp& aProcessStartTime,
                                        UniqueStacks& aUniqueStacks)
 {
-  streamCommonProps("UserTiming", aWriter, aStartTime, aUniqueStacks);
+  streamCommonProps("UserTiming", aWriter, aProcessStartTime, aUniqueStacks);
   aWriter.StringProperty("name", NS_ConvertUTF16toUTF8(mName).get());
   aWriter.StringProperty("entryType", mEntryType);
 }
 
 DOMEventMarkerPayload::DOMEventMarkerPayload(const nsAString& aType, uint16_t aPhase,
                                              const mozilla::TimeStamp& aStartTime,
                                              const mozilla::TimeStamp& aEndTime)
   : ProfilerMarkerPayload(aStartTime, aEndTime, nullptr)
@@ -198,20 +200,20 @@ DOMEventMarkerPayload::DOMEventMarkerPay
 }
 
 DOMEventMarkerPayload::~DOMEventMarkerPayload()
 {
 }
 
 void
 DOMEventMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                     const TimeStamp& aStartTime,
+                                     const TimeStamp& aProcessStartTime,
                                      UniqueStacks& aUniqueStacks)
 {
-  streamCommonProps("DOMEvent", aWriter, aStartTime, aUniqueStacks);
+  streamCommonProps("DOMEvent", aWriter, aProcessStartTime, aUniqueStacks);
   aWriter.StringProperty("type", NS_ConvertUTF16toUTF8(mType).get());
   aWriter.IntProperty("phase", mPhase);
 }
 
 void
 ProfilerJSEventMarker(const char *event)
 {
     PROFILER_MARKER(event);
@@ -222,17 +224,17 @@ LayerTranslationPayload::LayerTranslatio
   : ProfilerMarkerPayload(mozilla::TimeStamp::Now(), mozilla::TimeStamp::Now(), nullptr)
   , mLayer(aLayer)
   , mPoint(aPoint)
 {
 }
 
 void
 LayerTranslationPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                       const TimeStamp& aStartTime,
+                                       const TimeStamp& aProcessStartTime,
                                        UniqueStacks& aUniqueStacks)
 {
   const size_t bufferSize = 32;
   char buffer[bufferSize];
   SprintfLiteral(buffer, "%p", mLayer);
 
   aWriter.StringProperty("layer", buffer);
   aWriter.IntProperty("x", mPoint.x);
@@ -243,72 +245,72 @@ LayerTranslationPayload::StreamPayload(S
 TouchDataPayload::TouchDataPayload(const mozilla::ScreenIntPoint& aPoint)
   : ProfilerMarkerPayload(mozilla::TimeStamp::Now(), mozilla::TimeStamp::Now(), nullptr)
 {
   mPoint = aPoint;
 }
 
 void
 TouchDataPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                const TimeStamp& aStartTime,
+                                const TimeStamp& aProcessStartTime,
                                 UniqueStacks& aUniqueStacks)
 {
   aWriter.IntProperty("x", mPoint.x);
   aWriter.IntProperty("y", mPoint.y);
 }
 
 VsyncPayload::VsyncPayload(mozilla::TimeStamp aVsyncTimestamp)
   : ProfilerMarkerPayload(aVsyncTimestamp, aVsyncTimestamp, nullptr)
   , mVsyncTimestamp(aVsyncTimestamp)
 {
 }
 
 void
 VsyncPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                            const TimeStamp& aStartTime,
+                            const TimeStamp& aProcessStartTime,
                             UniqueStacks& aUniqueStacks)
 {
   aWriter.DoubleProperty("vsync",
-                         (mVsyncTimestamp - aStartTime).ToMilliseconds());
+                         (mVsyncTimestamp - aProcessStartTime).ToMilliseconds());
   aWriter.StringProperty("category", "VsyncTimestamp");
 }
 
 void
 GCSliceMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                    const mozilla::TimeStamp& aStartTime,
+                                    const mozilla::TimeStamp& aProcessStartTime,
                                     UniqueStacks& aUniqueStacks)
 {
   MOZ_ASSERT(mTimingJSON);
-  streamCommonProps("GCSlice", aWriter, aStartTime, aUniqueStacks);
+  streamCommonProps("GCSlice", aWriter, aProcessStartTime, aUniqueStacks);
   if (mTimingJSON) {
     aWriter.SplicedJSONProperty("timings", mTimingJSON.get());
   } else {
     aWriter.NullProperty("timings");
   }
 }
 
 void
 GCMajorMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                    const mozilla::TimeStamp& aStartTime,
+                                    const mozilla::TimeStamp& aProcessStartTime,
                                     UniqueStacks& aUniqueStacks)
 {
   MOZ_ASSERT(mTimingJSON);
-  streamCommonProps("GCMajor", aWriter, aStartTime, aUniqueStacks);
+  streamCommonProps("GCMajor", aWriter, aProcessStartTime, aUniqueStacks);
   if (mTimingJSON) {
     aWriter.SplicedJSONProperty("timings", mTimingJSON.get());
   } else {
     aWriter.NullProperty("timings");
   }
 }
 
 void
 GCMinorMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
-                                    const mozilla::TimeStamp& aStartTime,
+                                    const mozilla::TimeStamp& aProcessStartTime,
                                     UniqueStacks& aUniqueStacks)
 {
   MOZ_ASSERT(mTimingData);
-  streamCommonProps("GCMinor", aWriter, aStartTime, aUniqueStacks);
+  streamCommonProps("GCMinor", aWriter, aProcessStartTime, aUniqueStacks);
   if (mTimingData) {
     aWriter.SplicedJSONProperty("nurseryTimings", mTimingData.get());
   } else {
     aWriter.NullProperty("nurseryTimings");
   }
 }
--- a/tools/profiler/core/ThreadInfo.cpp
+++ b/tools/profiler/core/ThreadInfo.cpp
@@ -66,27 +66,27 @@ void
 ThreadInfo::StopProfiling()
 {
   mResponsiveness.reset();
   mIsBeingProfiled = false;
 }
 
 void
 ThreadInfo::StreamJSON(ProfileBuffer* aBuffer, SpliceableJSONWriter& aWriter,
-                       const TimeStamp& aStartTime, double aSinceTime)
+                       const TimeStamp& aProcessStartTime, double aSinceTime)
 {
   // mUniqueStacks may already be emplaced from FlushSamplesAndMarkers.
   if (!mUniqueStacks.isSome()) {
     mUniqueStacks.emplace(mContext);
   }
 
   aWriter.Start(SpliceableJSONWriter::SingleLineStyle);
   {
-    StreamSamplesAndMarkers(Name(), ThreadId(), aBuffer, aWriter, aStartTime,
-                            aSinceTime, mContext,
+    StreamSamplesAndMarkers(Name(), ThreadId(), aBuffer, aWriter,
+                            aProcessStartTime, aSinceTime, mContext,
                             mSavedStreamedSamples.get(),
                             mSavedStreamedMarkers.get(), *mUniqueStacks);
     mSavedStreamedSamples.reset();
     mSavedStreamedMarkers.reset();
 
     aWriter.StartObjectProperty("stackTable");
     {
       {
@@ -133,17 +133,17 @@ ThreadInfo::StreamJSON(ProfileBuffer* aB
   mUniqueStacks.reset();
 }
 
 void
 StreamSamplesAndMarkers(const char* aName,
                         int aThreadId,
                         ProfileBuffer* aBuffer,
                         SpliceableJSONWriter& aWriter,
-                        const TimeStamp& aStartTime,
+                        const TimeStamp& aProcessStartTime,
                         double aSinceTime,
                         JSContext* aContext,
                         char* aSavedStreamedSamples,
                         char* aSavedStreamedMarkers,
                         UniqueStacks& aUniqueStacks)
 {
   aWriter.StringProperty("processType",
                          XRE_ChildProcessTypeToString(XRE_GetProcessType()));
@@ -189,27 +189,27 @@ StreamSamplesAndMarkers(const char* aNam
     }
 
     aWriter.StartArrayProperty("data");
     {
       if (aSavedStreamedMarkers) {
         MOZ_ASSERT(aSinceTime == 0);
         aWriter.Splice(aSavedStreamedMarkers);
       }
-      aBuffer->StreamMarkersToJSON(aWriter, aThreadId, aStartTime, aSinceTime,
-                                   aUniqueStacks);
+      aBuffer->StreamMarkersToJSON(aWriter, aThreadId, aProcessStartTime,
+                                   aSinceTime, aUniqueStacks);
     }
     aWriter.EndArray();
   }
   aWriter.EndObject();
 }
 
 void
 ThreadInfo::FlushSamplesAndMarkers(ProfileBuffer* aBuffer,
-                                   const TimeStamp& aStartTime)
+                                   const TimeStamp& aProcessStartTime)
 {
   // This function is used to serialize the current buffer just before
   // JSContext destruction.
   MOZ_ASSERT(mContext);
 
   // Unlike StreamJSObject, do not surround the samples in brackets by calling
   // aWriter.{Start,End}BareList. The result string will be a comma-separated
   // list of JSON object literals that will prepended by StreamJSObject into
@@ -229,17 +229,17 @@ ThreadInfo::FlushSamplesAndMarkers(Profi
     b.EndBareList();
     mSavedStreamedSamples = b.WriteFunc()->CopyData();
   }
 
   {
     SpliceableChunkedJSONWriter b;
     b.StartBareList();
     {
-      aBuffer->StreamMarkersToJSON(b, mThreadId, aStartTime,
+      aBuffer->StreamMarkersToJSON(b, mThreadId, aProcessStartTime,
                                    /* aSinceTime = */ 0, *mUniqueStacks);
     }
     b.EndBareList();
     mSavedStreamedMarkers = b.WriteFunc()->CopyData();
   }
 
   // Reset the buffer. Attempting to symbolicate JS samples after mContext has
   // gone away will crash.
--- a/tools/profiler/core/ThreadInfo.h
+++ b/tools/profiler/core/ThreadInfo.h
@@ -199,22 +199,23 @@ private:
 
   //
   // The following code is only used for threads that are being profiled, i.e.
   // for which IsBeingProfiled() returns true.
   //
 
 public:
   void StreamJSON(ProfileBuffer* aBuffer, SpliceableJSONWriter& aWriter,
-                  const mozilla::TimeStamp& aStartTime, double aSinceTime);
+                  const mozilla::TimeStamp& aProcessStartTime,
+                  double aSinceTime);
 
   // Call this method when the JS entries inside the buffer are about to
   // become invalid, i.e., just before JS shutdown.
   void FlushSamplesAndMarkers(ProfileBuffer* aBuffer,
-                              const mozilla::TimeStamp& aStartTime);
+                              const mozilla::TimeStamp& aProcessStartTime);
 
   // Returns nullptr if this is not the main thread or if this thread is not
   // being profiled.
   ThreadResponsiveness* GetThreadResponsiveness()
   {
     ThreadResponsiveness* responsiveness = mResponsiveness.ptrOr(nullptr);
     MOZ_ASSERT(!!responsiveness == (mIsMainThread && mIsBeingProfiled));
     return responsiveness;
@@ -361,16 +362,16 @@ private:
   // of the most recent sample for this thread.
   ProfileBuffer::LastSample mLastSample;
 };
 
 void
 StreamSamplesAndMarkers(const char* aName, int aThreadId,
                         ProfileBuffer* aBuffer,
                         SpliceableJSONWriter& aWriter,
-                        const mozilla::TimeStamp& aStartTime,
+                        const mozilla::TimeStamp& aProcessStartTime,
                         double aSinceTime,
                         JSContext* aContext,
                         char* aSavedStreamedSamples,
                         char* aSavedStreamedMarkers,
                         UniqueStacks& aUniqueStacks);
 
 #endif  // ThreadInfo_h
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -78,37 +78,37 @@
 #endif
 
 #if defined(GP_OS_linux) || defined(GP_OS_android)
 #include <ucontext.h>
 #endif
 
 using namespace mozilla;
 
-mozilla::LazyLogModule gProfilerLog("prof");
+LazyLogModule gProfilerLog("prof");
 
 #if defined(GP_OS_android)
-class GeckoJavaSampler : public mozilla::java::GeckoJavaSampler::Natives<GeckoJavaSampler>
+class GeckoJavaSampler : public java::GeckoJavaSampler::Natives<GeckoJavaSampler>
 {
 private:
   GeckoJavaSampler();
 
 public:
   static double GetProfilerTime() {
     if (!profiler_is_active()) {
       return 0.0;
     }
     return profiler_time();
   };
 };
 #endif
 
-class PSMutex : public mozilla::StaticMutex {};
-
-typedef mozilla::BaseAutoLock<PSMutex> PSAutoLock;
+class PSMutex : public StaticMutex {};
+
+typedef BaseAutoLock<PSMutex> PSAutoLock;
 
 // Only functions that take a PSLockRef arg can access CorePS's and ActivePS's
 // fields.
 typedef const PSAutoLock& PSLockRef;
 
 #define PS_GET(type_, name_) \
   static type_ name_(PSLockRef) { return sInstance->m##name_; } \
 
@@ -140,17 +140,17 @@ typedef const PSAutoLock& PSLockRef;
 // - mProcessStartTime, because it's immutable;
 //
 // - each thread's RacyThreadInfo object is accessible without locking via
 //   TLSInfo::RacyThreadInfo().
 class CorePS
 {
 private:
   CorePS()
-    : mProcessStartTime(mozilla::TimeStamp::ProcessCreation())
+    : mProcessStartTime(TimeStamp::ProcessCreation())
 #ifdef USE_LUL_STACKWALK
     , mLul(nullptr)
 #endif
   {}
 
   ~CorePS()
   {
     while (mLiveThreads.size() > 0) {
@@ -223,17 +223,17 @@ public:
   PS_GET_AND_SET(lul::LUL*, Lul)
 #endif
 
 private:
   // The singleton instance
   static CorePS* sInstance;
 
   // The time that the process started.
-  const mozilla::TimeStamp mProcessStartTime;
+  const TimeStamp mProcessStartTime;
 
   // Info on all the registered threads, both live and dead. ThreadIds in
   // mLiveThreads are unique. ThreadIds in mDeadThreads may not be, because
   // ThreadIds can be reused. IsBeingProfiled() is true for all ThreadInfos in
   // mDeadThreads because we don't hold on to ThreadInfos for non-profiled dead
   // threads.
   ThreadVector mLiveThreads;
   ThreadVector mDeadThreads;
@@ -261,17 +261,17 @@ class ActivePS
 {
 private:
   static uint32_t AdjustFeatures(uint32_t aFeatures, uint32_t aFilterCount)
   {
     // Filter out any features unavailable in this platform/configuration.
     aFeatures &= profiler_get_available_features();
 
 #if defined(GP_OS_android)
-    if (!mozilla::jni::IsFennec()) {
+    if (!jni::IsFennec()) {
       aFeatures &= ~ProfilerFeature::Java;
     }
 #endif
 
     // Always enable ProfilerFeature::Threads if we have a filter, because
     // users sometimes ask to filter by a list of threads but forget to
     // explicitly specify ProfilerFeature::Threads.
     if (aFilterCount > 0) {
@@ -288,17 +288,17 @@ private:
     , mInterval(aInterval)
     , mFeatures(AdjustFeatures(aFeatures, aFilterCount))
     , mBuffer(new ProfileBuffer(aEntries))
       // The new sampler thread doesn't start sampling immediately because the
       // main loop within Run() is blocked until this function's caller unlocks
       // gPSMutex.
     , mSamplerThread(NewSamplerThread(aLock, mGeneration, aInterval))
     , mInterposeObserver(ProfilerFeature::HasMainThreadIO(aFeatures)
-                         ? new mozilla::ProfilerIOInterposeObserver()
+                         ? new ProfilerIOInterposeObserver()
                          : nullptr)
 #undef HAS_FEATURE
     , mIsPaused(false)
 #if defined(GP_OS_linux)
     , mWasPaused(false)
 #endif
   {
     // Deep copy aFilters.
@@ -467,17 +467,17 @@ private:
   const UniquePtr<ProfileBuffer> mBuffer;
 
   // The current sampler thread. This class is not responsible for destroying
   // the SamplerThread object; the Destroy() method returns it so the caller
   // can destroy it.
   SamplerThread* const mSamplerThread;
 
   // The interposer that records main thread I/O.
-  const RefPtr<mozilla::ProfilerIOInterposeObserver> mInterposeObserver;
+  const RefPtr<ProfilerIOInterposeObserver> mInterposeObserver;
 
   // Is the profiler paused?
   bool mIsPaused;
 
 #if defined(GP_OS_linux)
   // Used to record whether the profiler was paused just before forking. False
   // at all times except just before/after forking.
   bool mWasPaused;
@@ -609,17 +609,17 @@ static const char* const kMainThreadName
 // call to Tick().
 class TickSample {
 public:
   // This constructor is for periodic samples, i.e. those performed in response
   // to a timer firing. Periodic samples are performed off-thread, i.e. the
   // SamplerThread samples the thread in question.
   TickSample(ThreadInfo* aThreadInfo, int64_t aRSSMemory, int64_t aUSSMemory)
     : mIsSynchronous(false)
-    , mTimeStamp(mozilla::TimeStamp::Now())
+    , mTimeStamp(TimeStamp::Now())
     , mThreadId(aThreadInfo->ThreadId())
     , mRacyInfo(aThreadInfo->RacyInfo())
     , mJSContext(aThreadInfo->mContext)
     , mStackTop(aThreadInfo->StackTop())
     , mLastSample(&aThreadInfo->LastSample())
     , mPlatformData(aThreadInfo->GetPlatformData())
     , mResponsiveness(aThreadInfo->GetThreadResponsiveness())
     , mRSSMemory(aRSSMemory)    // may be zero
@@ -634,17 +634,17 @@ public:
   {}
 
   // This constructor is for synchronous samples, i.e. those performed in
   // response to an explicit sampling request via the API. Synchronous samples
   // are performed on-thread, i.e. the thread samples itself.
   TickSample(NotNull<RacyThreadInfo*> aRacyInfo, JSContext* aJSContext,
              PlatformData* aPlatformData)
     : mIsSynchronous(true)
-    , mTimeStamp(mozilla::TimeStamp::Now())
+    , mTimeStamp(TimeStamp::Now())
     , mThreadId(Thread::GetCurrentId())
     , mRacyInfo(aRacyInfo)
     , mJSContext(aJSContext)
     , mStackTop(nullptr)
     , mLastSample(nullptr)
     , mPlatformData(aPlatformData)
     , mResponsiveness(nullptr)
     , mRSSMemory(0)
@@ -663,17 +663,17 @@ public:
   void PopulateContext(ucontext_t* aContext);
 #else
   void PopulateContext();
 #endif
 
   // False for periodic samples, true for synchronous samples.
   const bool mIsSynchronous;
 
-  const mozilla::TimeStamp mTimeStamp;
+  const TimeStamp mTimeStamp;
 
   const int mThreadId;
 
   const NotNull<RacyThreadInfo*> mRacyInfo;
 
   JSContext* const mJSContext;
 
   void* const mStackTop;
@@ -791,25 +791,35 @@ AddPseudoEntry(PSLockRef aLock, ProfileB
 
   if (lineno != -1) {
     aBuffer->addTag(ProfileBufferEntry::LineNumber(lineno));
   }
 
   aBuffer->addTag(ProfileBufferEntry::Category(uint32_t(entry.category())));
 }
 
+// Setting MAX_NATIVE_FRAMES too high risks the unwinder wasting a lot of time
+// looping on corrupted stacks.
+//
+// The PseudoStack frame size is found in PseudoStack::MaxEntries.
+static const size_t MAX_NATIVE_FRAMES = 1024;
+static const size_t MAX_JS_FRAMES     = 1024;
+
 struct NativeStack
 {
-  void** pc_array;
-  void** sp_array;
-  size_t size;
-  size_t count;
+  void* mPCs[MAX_NATIVE_FRAMES];
+  void* mSPs[MAX_NATIVE_FRAMES];
+  size_t mCount;  // Number of entries filled.
+
+  NativeStack()
+    : mCount(0)
+  {}
 };
 
-mozilla::Atomic<bool> WALKING_JS_STACK(false);
+Atomic<bool> WALKING_JS_STACK(false);
 
 struct AutoWalkJSStack
 {
   bool walkAllowed;
 
   AutoWalkJSStack() : walkAllowed(false) {
     walkAllowed = WALKING_JS_STACK.compareExchange(false, true);
   }
@@ -838,22 +848,22 @@ MergeStacksIntoProfile(PSLockRef aLock, 
   // ProfilingFrameIterator to avoid incorrectly resetting the generation of
   // sampled JIT entries inside the JS engine. See note below concerning 'J'
   // entries.
   uint32_t startBufferGen;
   startBufferGen = aSample.mIsSynchronous
                  ? UINT32_MAX
                  : aBuffer->mGeneration;
   uint32_t jsCount = 0;
-  JS::ProfilingFrameIterator::Frame jsFrames[1000];
+  JS::ProfilingFrameIterator::Frame jsFrames[MAX_JS_FRAMES];
 
   // Only walk jit stack if profiling frame iterator is turned on.
   if (context && JS::IsProfilingEnabledForContext(context)) {
     AutoWalkJSStack autoWalkJSStack;
-    const uint32_t maxFrames = mozilla::ArrayLength(jsFrames);
+    const uint32_t maxFrames = ArrayLength(jsFrames);
 
     if (autoWalkJSStack.walkAllowed) {
       JS::ProfilingFrameIterator::RegisterState registerState;
       registerState.pc = aSample.mPC;
       registerState.sp = aSample.mSP;
       registerState.lr = aSample.mLR;
       registerState.fp = aSample.mFP;
 
@@ -864,17 +874,17 @@ MergeStacksIntoProfile(PSLockRef aLock, 
         if (aSample.mIsSynchronous || jsIter.isWasm()) {
           uint32_t extracted =
             jsIter.extractStack(jsFrames, jsCount, maxFrames);
           jsCount += extracted;
           if (jsCount == maxFrames) {
             break;
           }
         } else {
-          mozilla::Maybe<JS::ProfilingFrameIterator::Frame> frame =
+          Maybe<JS::ProfilingFrameIterator::Frame> frame =
             jsIter.getPhysicalFrameWithoutLabel();
           if (frame.isSome()) {
             jsFrames[jsCount++] = frame.value();
           }
         }
       }
     }
   }
@@ -884,17 +894,17 @@ MergeStacksIntoProfile(PSLockRef aLock, 
 
   // While the pseudo-stack array is ordered oldest-to-youngest, the JS and
   // native arrays are ordered youngest-to-oldest. We must add frames to aInfo
   // oldest-to-youngest. Thus, iterate over the pseudo-stack forwards and JS
   // and native arrays backwards. Note: this means the terminating condition
   // jsIndex and nativeIndex is being < 0.
   uint32_t pseudoIndex = 0;
   int32_t jsIndex = jsCount - 1;
-  int32_t nativeIndex = aNativeStack.count - 1;
+  int32_t nativeIndex = aNativeStack.mCount - 1;
 
   uint8_t* lastPseudoCppStackAddr = nullptr;
 
   // Iterate as long as there is at least one frame remaining.
   while (pseudoIndex != pseudoCount || jsIndex >= 0 || nativeIndex >= 0) {
     // There are 1 to 3 frames available. Find and add the oldest.
     uint8_t* pseudoStackAddr = nullptr;
     uint8_t* jsStackAddr = nullptr;
@@ -921,17 +931,17 @@ MergeStacksIntoProfile(PSLockRef aLock, 
       pseudoStackAddr = lastPseudoCppStackAddr;
     }
 
     if (jsIndex >= 0) {
       jsStackAddr = (uint8_t*) jsFrames[jsIndex].stackAddress;
     }
 
     if (nativeIndex >= 0) {
-      nativeStackAddr = (uint8_t*) aNativeStack.sp_array[nativeIndex];
+      nativeStackAddr = (uint8_t*) aNativeStack.mSPs[nativeIndex];
     }
 
     // If there's a native stack entry which has the same SP as a pseudo stack
     // entry, pretend we didn't see the native stack entry.  Ditto for a native
     // stack entry which has the same SP as a JS stack entry.  In effect this
     // means pseudo or JS entries trump conflicting native entries.
     if (nativeStackAddr && (pseudoStackAddr == nativeStackAddr ||
                             jsStackAddr == nativeStackAddr)) {
@@ -993,17 +1003,17 @@ MergeStacksIntoProfile(PSLockRef aLock, 
       jsIndex--;
       continue;
     }
 
     // If we reach here, there must be a native stack entry and it must be the
     // greatest entry.
     if (nativeStackAddr) {
       MOZ_ASSERT(nativeIndex >= 0);
-      void* addr = (void*)aNativeStack.pc_array[nativeIndex];
+      void* addr = (void*)aNativeStack.mPCs[nativeIndex];
       aBuffer->addTag(ProfileBufferEntry::NativeLeafAddr(addr));
     }
     if (nativeIndex >= 0) {
       nativeIndex--;
     }
   }
 
   // Update the JS context with the current profile sample buffer generation.
@@ -1022,42 +1032,35 @@ MergeStacksIntoProfile(PSLockRef aLock, 
 static uintptr_t GetThreadHandle(PlatformData* aData);
 #endif
 
 #ifdef USE_NS_STACKWALK
 static void
 StackWalkCallback(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
 {
   NativeStack* nativeStack = static_cast<NativeStack*>(aClosure);
-  MOZ_ASSERT(nativeStack->count < nativeStack->size);
-  nativeStack->sp_array[nativeStack->count] = aSP;
-  nativeStack->pc_array[nativeStack->count] = aPC;
-  nativeStack->count++;
+  MOZ_ASSERT(nativeStack->mCount < MAX_NATIVE_FRAMES);
+  nativeStack->mSPs[nativeStack->mCount] = aSP;
+  nativeStack->mPCs[nativeStack->mCount] = aPC;
+  nativeStack->mCount++;
 }
 
 static void
 DoNativeBacktrace(PSLockRef aLock, ProfileBuffer* aBuffer,
                   const TickSample& aSample)
 {
-  void* pc_array[1000];
-  void* sp_array[1000];
-  NativeStack nativeStack = {
-    pc_array,
-    sp_array,
-    mozilla::ArrayLength(pc_array),
-    0
-  };
+  NativeStack nativeStack;
 
   // Start with the current function. We use 0 as the frame number here because
   // the FramePointerStackWalk() and MozStackWalk() calls below will use 1..N.
   // This is a bit weird but it doesn't matter because StackWalkCallback()
   // doesn't use the frame number argument.
   StackWalkCallback(/* frameNum */ 0, aSample.mPC, aSample.mSP, &nativeStack);
 
-  uint32_t maxFrames = uint32_t(nativeStack.size - nativeStack.count);
+  uint32_t maxFrames = uint32_t(MAX_NATIVE_FRAMES - nativeStack.mCount);
 
 #if defined(GP_OS_darwin) || (defined(GP_PLAT_x86_windows))
   void* stackEnd = aSample.mStackTop;
   if (aSample.mFP >= aSample.mSP && aSample.mFP <= stackEnd) {
     FramePointerStackWalk(StackWalkCallback, /* skipFrames */ 0, maxFrames,
                           &nativeStack, reinterpret_cast<void**>(aSample.mFP),
                           stackEnd);
   }
@@ -1074,24 +1077,17 @@ DoNativeBacktrace(PSLockRef aLock, Profi
 }
 #endif
 
 #ifdef USE_EHABI_STACKWALK
 static void
 DoNativeBacktrace(PSLockRef aLock, ProfileBuffer* aBuffer,
                   const TickSample& aSample)
 {
-  void* pc_array[1000];
-  void* sp_array[1000];
-  NativeStack nativeStack = {
-    pc_array,
-    sp_array,
-    mozilla::ArrayLength(pc_array),
-    0
-  };
+  NativeStack nativeStack;
 
   const mcontext_t* mcontext = &aSample.mContext->uc_mcontext;
   mcontext_t savedContext;
   NotNull<RacyThreadInfo*> racyInfo = aSample.mRacyInfo;
 
   // The pseudostack contains an "EnterJIT" frame whenever we enter
   // JIT code with profiling enabled; the stack pointer value points
   // the saved registers.  We use this to unwind resume unwinding
@@ -1102,21 +1098,21 @@ DoNativeBacktrace(PSLockRef aLock, Profi
     js::ProfileEntry& entry = racyInfo->entries[i - 1];
     if (!entry.isJs() && strcmp(entry.label(), "EnterJIT") == 0) {
       // Found JIT entry frame.  Unwind up to that point (i.e., force
       // the stack walk to stop before the block of saved registers;
       // note that it yields nondecreasing stack pointers), then restore
       // the saved state.
       uint32_t* vSP = reinterpret_cast<uint32_t*>(entry.stackAddress());
 
-      nativeStack.count += EHABIStackWalk(*mcontext,
-                                          /* stackBase = */ vSP,
-                                          sp_array + nativeStack.count,
-                                          pc_array + nativeStack.count,
-                                          nativeStack.size - nativeStack.count);
+      nativeStack.mCount +=
+        EHABIStackWalk(*mcontext, /* stackBase = */ vSP,
+                       nativeStack.mSPs + nativeStack.mCount,
+                       nativeStack.mPCs + nativeStack.mCount,
+                       MAX_NATIVE_FRAMES - nativeStack.mCount);
 
       memset(&savedContext, 0, sizeof(savedContext));
 
       // See also: struct EnterJITStack in js/src/jit/arm/Trampoline-arm.cpp
       savedContext.arm_r4  = *vSP++;
       savedContext.arm_r5  = *vSP++;
       savedContext.arm_r6  = *vSP++;
       savedContext.arm_r7  = *vSP++;
@@ -1128,21 +1124,21 @@ DoNativeBacktrace(PSLockRef aLock, Profi
       savedContext.arm_sp  = reinterpret_cast<uint32_t>(vSP);
       savedContext.arm_pc  = savedContext.arm_lr;
       mcontext = &savedContext;
     }
   }
 
   // Now unwind whatever's left (starting from either the last EnterJIT frame
   // or, if no EnterJIT was found, the original registers).
-  nativeStack.count += EHABIStackWalk(*mcontext,
-                                      aSample.mStackTop,
-                                      sp_array + nativeStack.count,
-                                      pc_array + nativeStack.count,
-                                      nativeStack.size - nativeStack.count);
+  nativeStack.mCount +=
+    EHABIStackWalk(*mcontext, aSample.mStackTop,
+                   nativeStack.mSPs + nativeStack.mCount,
+                   nativeStack.mPCs + nativeStack.mCount,
+                   MAX_NATIVE_FRAMES - nativeStack.mCount);
 
   MergeStacksIntoProfile(aLock, aBuffer, aSample, nativeStack);
 }
 #endif
 
 #ifdef USE_LUL_STACKWALK
 
 // See the comment at the callsite for why this function is necessary.
@@ -1264,75 +1260,64 @@ DoNativeBacktrace(PSLockRef aLock, Profi
       ASAN_memcpy(&stackImg.mContents[0], (void*)start, nToCopy);
 #else
       memcpy(&stackImg.mContents[0], (void*)start, nToCopy);
 #endif
       (void)VALGRIND_MAKE_MEM_DEFINED(&stackImg.mContents[0], nToCopy);
     }
   }
 
-  // The maximum number of frames that LUL will produce.  Setting it
-  // too high gives a risk of it wasting a lot of time looping on
-  // corrupted stacks.
-  const int MAX_NATIVE_FRAMES = 256;
+  NativeStack nativeStack;
 
   size_t scannedFramesAllowed = 0;
 
-  uintptr_t framePCs[MAX_NATIVE_FRAMES];
-  uintptr_t frameSPs[MAX_NATIVE_FRAMES];
-  size_t framesAvail = mozilla::ArrayLength(framePCs);
-  size_t framesUsed  = 0;
   size_t scannedFramesAcquired = 0, framePointerFramesAcquired = 0;
   lul::LUL* lul = CorePS::Lul(aLock);
-  lul->Unwind(&framePCs[0], &frameSPs[0],
-              &framesUsed, &framePointerFramesAcquired, &scannedFramesAcquired,
-              framesAvail, scannedFramesAllowed,
+  lul->Unwind(reinterpret_cast<uintptr_t*>(nativeStack.mPCs),
+              reinterpret_cast<uintptr_t*>(nativeStack.mSPs),
+              &nativeStack.mCount, &framePointerFramesAcquired,
+              &scannedFramesAcquired,
+              MAX_NATIVE_FRAMES, scannedFramesAllowed,
               &startRegs, &stackImg);
 
-  NativeStack nativeStack = {
-    reinterpret_cast<void**>(framePCs),
-    reinterpret_cast<void**>(frameSPs),
-    mozilla::ArrayLength(framePCs),
-    framesUsed
-  };
-
   MergeStacksIntoProfile(aLock, aBuffer, aSample, nativeStack);
 
   // Update stats in the LUL stats object.  Unfortunately this requires
   // three global memory operations.
   lul->mStats.mContext += 1;
-  lul->mStats.mCFI     += framesUsed - 1 - framePointerFramesAcquired -
-                                           scannedFramesAcquired;
+  lul->mStats.mCFI     += nativeStack.mCount - 1 - framePointerFramesAcquired -
+                          scannedFramesAcquired;
   lul->mStats.mFP      += framePointerFramesAcquired;
   lul->mStats.mScanned += scannedFramesAcquired;
 }
 
 #endif
 
 static void
 DoSampleStackTrace(PSLockRef aLock, ProfileBuffer* aBuffer,
                    const TickSample& aSample)
 {
-  NativeStack nativeStack = { nullptr, nullptr, 0, 0 };
+  NativeStack nativeStack;
+
+  // |nativeStack| is empty at this point.
   MergeStacksIntoProfile(aLock, aBuffer, aSample, nativeStack);
 
   if (ActivePS::FeatureLeaf(aLock)) {
     aBuffer->addTag(ProfileBufferEntry::NativeLeafAddr((void*)aSample.mPC));
   }
 }
 
 // This function is called for each sampling period with the current program
 // counter. It is called within a signal and so must be re-entrant.
 static void
 Tick(PSLockRef aLock, ProfileBuffer* aBuffer, const TickSample& aSample)
 {
   aBuffer->addTagThreadId(aSample.mThreadId, aSample.mLastSample);
 
-  mozilla::TimeDuration delta =
-    aSample.mTimeStamp - CorePS::ProcessStartTime();
+  TimeDuration delta = aSample.mTimeStamp - CorePS::ProcessStartTime();
   aBuffer->addTag(ProfileBufferEntry::Time(delta.ToMilliseconds()));
 
 #if defined(HAVE_NATIVE_UNWIND)
   if (ActivePS::FeatureStackWalk(aLock)) {
     DoNativeBacktrace(aLock, aBuffer, aSample);
   } else
 #endif
   {
@@ -1347,17 +1332,17 @@ Tick(PSLockRef aLock, ProfileBuffer* aBu
     while (pendingMarkersList && pendingMarkersList->peek()) {
       ProfilerMarker* marker = pendingMarkersList->popHead();
       aBuffer->addStoredMarker(marker);
       aBuffer->addTag(ProfileBufferEntry::Marker(marker));
     }
   }
 
   if (aSample.mResponsiveness && aSample.mResponsiveness->HasData()) {
-    mozilla::TimeDuration delta =
+    TimeDuration delta =
       aSample.mResponsiveness->GetUnresponsiveDuration(aSample.mTimeStamp);
     aBuffer->addTag(ProfileBufferEntry::Responsiveness(delta.ToMilliseconds()));
   }
 
   // rssMemory is equal to 0 when we are not recording.
   if (aSample.mRSSMemory != 0) {
     double rssMemory = static_cast<double>(aSample.mRSSMemory);
     aBuffer->addTag(ProfileBufferEntry::ResidentMemory(rssMemory));
@@ -1431,17 +1416,17 @@ static void
 StreamTaskTracer(PSLockRef aLock, SpliceableJSONWriter& aWriter)
 {
 #ifdef MOZ_TASK_TRACER
   MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
 
   aWriter.StartArrayProperty("data");
   {
     UniquePtr<nsTArray<nsCString>> data =
-      mozilla::tasktracer::GetLoggedData(CorePS::ProcessStartTime());
+      tasktracer::GetLoggedData(CorePS::ProcessStartTime());
     for (uint32_t i = 0; i < data->Length(); ++i) {
       aWriter.StringElement((data->ElementAt(i)).get());
     }
   }
   aWriter.EndArray();
 
   aWriter.StartArrayProperty("threads");
   {
@@ -1455,32 +1440,31 @@ StreamTaskTracer(PSLockRef aLock, Splice
     for (size_t i = 0; i < deadThreads.size(); i++) {
       ThreadInfo* info = deadThreads.at(i);
       StreamNameAndThreadId(aWriter, info->Name(), info->ThreadId());
     }
   }
   aWriter.EndArray();
 
   aWriter.DoubleProperty(
-    "start", static_cast<double>(mozilla::tasktracer::GetStartTime()));
+    "start", static_cast<double>(tasktracer::GetStartTime()));
 #endif
 }
 
 static void
 StreamMetaJSCustomObject(PSLockRef aLock, SpliceableJSONWriter& aWriter)
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
 
   aWriter.IntProperty("version", 6);
 
   // The "startTime" field holds the number of milliseconds since midnight
   // January 1, 1970 GMT. This grotty code computes (Now - (Now -
   // ProcessStartTime)) to convert CorePS::ProcessStartTime() into that form.
-  mozilla::TimeDuration delta =
-    mozilla::TimeStamp::Now() - CorePS::ProcessStartTime();
+  TimeDuration delta = TimeStamp::Now() - CorePS::ProcessStartTime();
   aWriter.DoubleProperty(
     "startTime", static_cast<double>(PR_Now()/1000.0 - delta.ToMilliseconds()));
 
   if (!NS_IsMainThread()) {
     // Leave the rest of the properties out if we're not on the main thread.
     // At the moment, the only case in which this function is called on a
     // background thread is if we're in a content process and are going to
     // send this profile to the parent process. In that case, the parent
@@ -2013,28 +1997,28 @@ FindLiveThreadInfo(PSLockRef aLock, int*
       break;
     }
   }
 
   return ret;
 }
 
 static void
-locked_register_thread(PSLockRef aLock, const char* aName, void* stackTop)
+locked_register_thread(PSLockRef aLock, const char* aName, void* aStackTop)
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   MOZ_RELEASE_ASSERT(!FindLiveThreadInfo(aLock));
 
   if (!TLSInfo::Init(aLock)) {
     return;
   }
 
   ThreadInfo* info = new ThreadInfo(aName, Thread::GetCurrentId(),
-                                    NS_IsMainThread(), stackTop);
+                                    NS_IsMainThread(), aStackTop);
   TLSInfo::SetInfo(aLock, info);
 
   if (ActivePS::Exists(aLock) && ActivePS::ShouldProfileThread(aLock, info)) {
     info->StartProfiling();
     if (ActivePS::FeatureJS(aLock)) {
       // This StartJSSampling() call is on-thread, so we can poll manually to
       // start JS sampling immediately.
       info->StartJSSampling();
@@ -2122,21 +2106,21 @@ profiler_init(void* aStackTop)
     CorePS::Create(lock);
 
     locked_register_thread(lock, kMainThreadName, aStackTop);
 
     // Platform-specific initialization.
     PlatformInit(lock);
 
 #ifdef MOZ_TASK_TRACER
-    mozilla::tasktracer::InitTaskTracer();
+    tasktracer::InitTaskTracer();
 #endif
 
 #if defined(GP_OS_android)
-    if (mozilla::jni::IsFennec()) {
+    if (jni::IsFennec()) {
       GeckoJavaSampler::Init();
     }
 #endif
 
     // (Linux-only) We could create CorePS::mLul and read unwind info into it
     // at this point. That would match the lifetime implied by destruction of
     // it in profiler_shutdown() just below. However, that gives a big delay on
     // startup, even if no profiling is actually to be done. So, instead, it is
@@ -2214,17 +2198,17 @@ profiler_shutdown()
 
     CorePS::Destroy(lock);
 
     // We just destroyed CorePS and the ThreadInfos it contains, so we can
     // clear this thread's TLSInfo.
     TLSInfo::SetInfo(lock, nullptr);
 
 #ifdef MOZ_TASK_TRACER
-    mozilla::tasktracer::ShutdownTaskTracer();
+    tasktracer::ShutdownTaskTracer();
 #endif
   }
 
   // We do these operations with gPSMutex unlocked. The comments in
   // profiler_stop() explain why.
   if (samplerThread) {
     ProfilerParent::ProfilerStopped();
     NotifyObservers("profiler-stopped");
@@ -2253,17 +2237,17 @@ profiler_get_profile(double aSinceTime)
   }
   b.End();
 
   return b.WriteFunc()->CopyData();
 }
 
 void
 profiler_get_start_params(int* aEntries, double* aInterval, uint32_t* aFeatures,
-                          mozilla::Vector<const char*>* aFilters)
+                          Vector<const char*>* aFilters)
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   if (NS_WARN_IF(!aEntries) || NS_WARN_IF(!aInterval) ||
       NS_WARN_IF(!aFeatures) || NS_WARN_IF(!aFilters)) {
     return;
   }
 
@@ -2293,17 +2277,17 @@ locked_profiler_save_profile_to_file(PSL
 {
   LOG("locked_profiler_save_profile_to_file(%s)", aFilename);
 
   MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
 
   std::ofstream stream;
   stream.open(aFilename);
   if (stream.is_open()) {
-    SpliceableJSONWriter w(mozilla::MakeUnique<OStreamJSONWriteFunc>(stream));
+    SpliceableJSONWriter w(MakeUnique<OStreamJSONWriteFunc>(stream));
     w.Start(SpliceableJSONWriter::SingleLineStyle);
     {
       locked_profiler_stream_json_for_this_process(aLock, w, /* sinceTime */ 0);
 
       // Don't include profiles from other processes because this is a
       // synchronous function.
       w.StartArrayProperty("processes");
       w.EndArray();
@@ -2432,28 +2416,28 @@ locked_profiler_start(PSLockRef aLock, i
 
   // Dead ThreadInfos are deleted in profiler_stop(), and dead ThreadInfos
   // aren't saved when the profiler is inactive. Therefore the dead threads
   // vector should be empty here.
   MOZ_RELEASE_ASSERT(CorePS::DeadThreads(aLock).empty());
 
 #ifdef MOZ_TASK_TRACER
   if (ActivePS::FeatureTaskTracer(aLock)) {
-    mozilla::tasktracer::StartLogging();
+    tasktracer::StartLogging();
   }
 #endif
 
 #if defined(GP_OS_android)
   if (ActivePS::FeatureJava(aLock)) {
     int javaInterval = interval;
     // Java sampling doesn't accurately keep up with 1ms sampling.
     if (javaInterval < 10) {
       javaInterval = 10;
     }
-    mozilla::java::GeckoJavaSampler::Start(javaInterval, 1000);
+    java::GeckoJavaSampler::Start(javaInterval, 1000);
   }
 #endif
 
   // At the very end, set up RacyFeatures.
   RacyFeatures::SetActive(ActivePS::Features(aLock));
 }
 
 void
@@ -2499,17 +2483,17 @@ locked_profiler_stop(PSLockRef aLock)
 
   MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
 
   // At the very start, clear RacyFeatures.
   RacyFeatures::SetInactive();
 
 #ifdef MOZ_TASK_TRACER
   if (ActivePS::FeatureTaskTracer(aLock)) {
-    mozilla::tasktracer::StopLogging();
+    tasktracer::StopLogging();
   }
 #endif
 
   // Stop sampling live threads.
   Thread::tid_t tid = Thread::GetCurrentId();
   CorePS::ThreadVector& liveThreads = CorePS::LiveThreads(aLock);
   for (uint32_t i = 0; i < liveThreads.size(); i++) {
     ThreadInfo* info = liveThreads.at(i);
@@ -2775,18 +2759,17 @@ profiler_js_interrupt_callback()
   info->PollJSSampling();
 }
 
 double
 profiler_time()
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
-  mozilla::TimeDuration delta =
-    mozilla::TimeStamp::Now() - CorePS::ProcessStartTime();
+  TimeDuration delta = TimeStamp::Now() - CorePS::ProcessStartTime();
   return delta.ToMilliseconds();
 }
 
 UniqueProfilerBacktrace
 profiler_get_backtrace()
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
@@ -2893,45 +2876,45 @@ profiler_get_backtrace_noalloc(char *out
 
 static void
 racy_profiler_add_marker(const char* aMarkerName,
                          ProfilerMarkerPayload* aPayload)
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   // aPayload must be freed if we return early.
-  mozilla::UniquePtr<ProfilerMarkerPayload> payload(aPayload);
+  UniquePtr<ProfilerMarkerPayload> payload(aPayload);
 
   // We don't assert that RacyFeatures::IsActiveWithoutPrivacy() is true here,
   // because it's possible that the result has changed since we tested it in
   // the caller.
   //
   // Because of this imprecision it's possible to miss a marker or record one
   // we shouldn't. Either way is not a big deal.
 
   RacyThreadInfo* racyInfo = TLSInfo::RacyInfo();
   if (!racyInfo) {
     return;
   }
 
-  mozilla::TimeStamp origin = (payload && !payload->GetStartTime().IsNull())
-                            ? payload->GetStartTime()
-                            : mozilla::TimeStamp::Now();
-  mozilla::TimeDuration delta = origin - CorePS::ProcessStartTime();
+  TimeStamp origin = (payload && !payload->GetStartTime().IsNull())
+                   ? payload->GetStartTime()
+                   : TimeStamp::Now();
+  TimeDuration delta = origin - CorePS::ProcessStartTime();
   racyInfo->AddPendingMarker(aMarkerName, payload.release(),
                              delta.ToMilliseconds());
 }
 
 void
 profiler_add_marker(const char* aMarkerName, ProfilerMarkerPayload* aPayload)
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   // aPayload must be freed if we return early.
-  mozilla::UniquePtr<ProfilerMarkerPayload> payload(aPayload);
+  UniquePtr<ProfilerMarkerPayload> payload(aPayload);
 
   // This function is hot enough that we use RacyFeatures, notActivePS.
   if (!RacyFeatures::IsActiveWithoutPrivacy()) {
     return;
   }
 
   racy_profiler_add_marker(aMarkerName, payload.release());
 }
@@ -2957,18 +2940,17 @@ profiler_tracing(const char* aCategory, 
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   // This function is hot enough that we use RacyFeatures, notActivePS.
   if (!RacyFeatures::IsActiveWithoutPrivacy()) {
     return;
   }
 
-  auto payload =
-    new ProfilerMarkerTracing(aCategory, aKind, mozilla::Move(aCause));
+  auto payload = new ProfilerMarkerTracing(aCategory, aKind, Move(aCause));
   racy_profiler_add_marker(aMarkerName, payload);
 }
 
 void
 profiler_log(const char* aStr)
 {
   profiler_tracing("log", aStr);
 }
--- a/tools/profiler/public/ProfilerMarkerPayload.h
+++ b/tools/profiler/public/ProfilerMarkerPayload.h
@@ -49,28 +49,28 @@ public:
    * Called from the main thread
    */
   virtual ~ProfilerMarkerPayload();
 
   /**
    * Called from the main thread
    */
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aStartTime,
+                             const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) = 0;
 
   mozilla::TimeStamp GetStartTime() const { return mStartTime; }
 
 protected:
   /**
    * Called from the main thread
    */
   void streamCommonProps(const char* aMarkerType,
                          SpliceableJSONWriter& aWriter,
-                         const mozilla::TimeStamp& aStartTime,
+                         const mozilla::TimeStamp& aProcessStartTime,
                          UniqueStacks& aUniqueStacks);
 
   void SetStack(UniqueProfilerBacktrace aStack) { mStack = mozilla::Move(aStack); }
 
 private:
   mozilla::TimeStamp  mStartTime;
   mozilla::TimeStamp  mEndTime;
   UniqueProfilerBacktrace  mStack;
@@ -82,64 +82,65 @@ public:
   ProfilerMarkerTracing(const char* aCategory, TracingKind aKind);
   ProfilerMarkerTracing(const char* aCategory, TracingKind aKind,
                         UniqueProfilerBacktrace aCause);
 
   const char *GetCategory() const { return mCategory; }
   TracingKind GetKind() const { return mKind; }
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aStartTime,
+                             const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   const char *mCategory;
   TracingKind mKind;
 };
 
 class ProfilerMarkerImagePayload : public ProfilerMarkerPayload
 {
 public:
   explicit ProfilerMarkerImagePayload(gfxASurface *aImg);
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aStartTime,
+                             const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   RefPtr<gfxASurface> mImg;
 };
 
 class IOMarkerPayload : public ProfilerMarkerPayload
 {
 public:
-  IOMarkerPayload(const char* aSource, const char* aFilename, const mozilla::TimeStamp& aStartTime,
+  IOMarkerPayload(const char* aSource, const char* aFilename,
+                  const mozilla::TimeStamp& aStartTime,
                   const mozilla::TimeStamp& aEndTime,
                   UniqueProfilerBacktrace aStack);
   ~IOMarkerPayload();
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aStartTime,
+                             const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   const char* mSource;
   char* mFilename;
 };
 
 class DOMEventMarkerPayload : public ProfilerMarkerPayload
 {
 public:
   DOMEventMarkerPayload(const nsAString& aType, uint16_t aPhase,
                         const mozilla::TimeStamp& aStartTime,
                         const mozilla::TimeStamp& aEndTime);
   ~DOMEventMarkerPayload();
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aStartTime,
+                             const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   nsString mType;
   uint16_t mPhase;
 };
 
 class UserTimingMarkerPayload : public ProfilerMarkerPayload
@@ -148,17 +149,17 @@ public:
   UserTimingMarkerPayload(const nsAString& aName,
                           const mozilla::TimeStamp& aStartTime);
   UserTimingMarkerPayload(const nsAString& aName,
                           const mozilla::TimeStamp& aStartTime,
                           const mozilla::TimeStamp& aEndTime);
   ~UserTimingMarkerPayload();
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aStartTime,
+                             const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   // Either "mark" or "measure".
   const char* mEntryType;
   nsString mName;
 };
 
@@ -168,17 +169,17 @@ private:
  */
 class LayerTranslationPayload : public ProfilerMarkerPayload
 {
 public:
   LayerTranslationPayload(mozilla::layers::Layer* aLayer,
                           mozilla::gfx::Point aPoint);
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aStartTime,
+                             const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   mozilla::layers::Layer* mLayer;
   mozilla::gfx::Point mPoint;
 };
 
 #include "Units.h"    // For ScreenIntPoint
@@ -189,51 +190,51 @@ private:
  */
 class TouchDataPayload : public ProfilerMarkerPayload
 {
 public:
   explicit TouchDataPayload(const mozilla::ScreenIntPoint& aPoint);
   virtual ~TouchDataPayload() {}
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aStartTime,
+                             const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   mozilla::ScreenIntPoint mPoint;
 };
 
 /**
  * Tracks when a vsync occurs according to the HardwareComposer.
  */
 class VsyncPayload : public ProfilerMarkerPayload
 {
 public:
   explicit VsyncPayload(mozilla::TimeStamp aVsyncTimestamp);
   virtual ~VsyncPayload() {}
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aStartTime,
+                             const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   mozilla::TimeStamp mVsyncTimestamp;
 };
 
 class GPUMarkerPayload : public ProfilerMarkerPayload
 {
 public:
   GPUMarkerPayload(const mozilla::TimeStamp& aCpuTimeStart,
                    const mozilla::TimeStamp& aCpuTimeEnd,
                    uint64_t aGpuTimeStart,
                    uint64_t aGpuTimeEnd);
   ~GPUMarkerPayload() {}
 
   virtual void StreamPayload(SpliceableJSONWriter& aWriter,
-                             const mozilla::TimeStamp& aStartTime,
+                             const mozilla::TimeStamp& aProcessStartTime,
                              UniqueStacks& aUniqueStacks) override;
 
 private:
   mozilla::TimeStamp mCpuTimeStart;
   mozilla::TimeStamp mCpuTimeEnd;
   uint64_t mGpuTimeStart;
   uint64_t mGpuTimeEnd;
 };
@@ -246,17 +247,17 @@ public:
                        JS::UniqueChars&& aTimingJSON)
    : ProfilerMarkerPayload(aStartTime, aEndTime, nullptr),
      mTimingJSON(mozilla::Move(aTimingJSON))
   {}
 
   virtual ~GCSliceMarkerPayload() {}
 
   void StreamPayload(SpliceableJSONWriter& aWriter,
-                     const mozilla::TimeStamp& aStartTime,
+                     const mozilla::TimeStamp& aProcessStartTime,
                      UniqueStacks& aUniqueStacks) override;
 
 private:
   JS::UniqueChars mTimingJSON;
 };
 
 class GCMajorMarkerPayload : public ProfilerMarkerPayload
 {
@@ -266,17 +267,17 @@ public:
                        JS::UniqueChars&& aTimingJSON)
    : ProfilerMarkerPayload(aStartTime, aEndTime, nullptr),
      mTimingJSON(mozilla::Move(aTimingJSON))
   {}
 
   virtual ~GCMajorMarkerPayload() {}
 
   void StreamPayload(SpliceableJSONWriter& aWriter,
-                     const mozilla::TimeStamp& aStartTime,
+                     const mozilla::TimeStamp& aProcessStartTime,
                      UniqueStacks& aUniqueStacks) override;
 
 private:
   JS::UniqueChars mTimingJSON;
 };
 
 class GCMinorMarkerPayload : public ProfilerMarkerPayload
 {
@@ -286,17 +287,17 @@ public:
                        JS::UniqueChars&& aTimingData)
    : ProfilerMarkerPayload(aStartTime, aEndTime, nullptr),
      mTimingData(mozilla::Move(aTimingData))
   {}
 
   virtual ~GCMinorMarkerPayload() {};
 
   void StreamPayload(SpliceableJSONWriter& aWriter,
-                     const mozilla::TimeStamp& aStartTime,
+                     const mozilla::TimeStamp& aProcessStartTime,
                      UniqueStacks& aUniqueStacks) override;
 
 private:
   JS::UniqueChars mTimingData;
 };
 
 
 #endif // PROFILER_MARKERS_H
--- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
@@ -1649,17 +1649,17 @@ nsOfflineCacheUpdate::LoadCompleted(nsOf
 
             // Retry this item.
             ProcessNextURI();
             return;
         }
     }
 
     // According to parallelism this may imply more pinned retries count,
-    // but that is not critical, since at one moment the algoritm will
+    // but that is not critical, since at one moment the algorithm will
     // stop anyway.  Also, this code may soon be completely removed
     // after we have a separate storage for pinned apps.
     mPinnedEntryRetriesCount = 0;
 
     // Check for failures.  3XX, 4XX and 5XX errors on items explicitly
     // listed in the manifest will cause the update to fail.
     if (NS_FAILED(rv) || !succeeded) {
         if (aItem->mItemType &
--- a/xpcom/ds/nsRefPtrHashtable.h
+++ b/xpcom/ds/nsRefPtrHashtable.h
@@ -152,17 +152,17 @@ nsRefPtrHashtable<KeyClass, PtrType>::Pu
 }
 
 template<class KeyClass, class PtrType>
 bool
 nsRefPtrHashtable<KeyClass, PtrType>::Put(KeyType aKey,
                                           already_AddRefed<PtrType> aData,
                                           const mozilla::fallible_t&)
 {
-  typename base_type::EntryType* ent = this->PutEntry(aKey);
+  typename base_type::EntryType* ent = this->PutEntry(aKey, mozilla::fallible);
 
   if (!ent) {
     return false;
   }
 
   ent->mData = aData;
 
   return true;
@@ -173,17 +173,17 @@ bool
 nsRefPtrHashtable<KeyClass, PtrType>::Remove(KeyType aKey,
                                              UserDataType* aRefPtr)
 {
   MOZ_ASSERT(aRefPtr);
   typename base_type::EntryType* ent = this->GetEntry(aKey);
 
   if (ent) {
     ent->mData.forget(aRefPtr);
-    this->Remove(aKey);
+    this->RemoveEntry(ent);
     return true;
   }
 
   // If the key doesn't exist, set *aRefPtr to null
   // so that it is a valid XPCOM getter.
   *aRefPtr = nullptr;
   return false;
 }