Merge inbound to mozilla-central. a=merge
authorMargareta Eliza Balazs <ebalazs@mozilla.com>
Mon, 05 Mar 2018 11:41:34 +0200
changeset 461548 51200c0fdaddb2749549a82596da5323a4cbd499
parent 461537 e365d166458b434e2968657b158db9adddb33c2b (current diff)
parent 461547 99fd2c41687b7a9f7912a2b74b1eaaf4fa7a96f9 (diff)
child 461549 13a58c13967f9e10e36aac6f72f2f02429e959ee
child 461556 d611ebace04d202ff01d8e5100689f43736edc51
child 461557 b1431462ceaf023d852bf52a7608307a3fd4b33f
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone60.0a1
first release with
nightly linux32
51200c0fdadd / 60.0a1 / 20180305100134 / files
nightly linux64
51200c0fdadd / 60.0a1 / 20180305100134 / files
nightly mac
51200c0fdadd / 60.0a1 / 20180305100134 / files
nightly win32
51200c0fdadd / 60.0a1 / 20180305100134 / files
nightly win64
51200c0fdadd / 60.0a1 / 20180305100134 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -229,17 +229,17 @@ partial interface Document {
   readonly attribute unsigned long referrerPolicy;
 
 };
 
 // https://fullscreen.spec.whatwg.org/#api
 partial interface Document {
   // Note: Per spec the 'S' in these two is lowercase, but the "Moz"
   // versions have it uppercase.
-  [LenientSetter, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
+  [LenientSetter, Unscopable, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
   readonly attribute boolean fullscreen;
   [BinaryName="fullscreen"]
   readonly attribute boolean mozFullScreen;
   [LenientSetter, Func="nsDocument::IsUnprefixedFullscreenEnabled", NeedsCallerType]
   readonly attribute boolean fullscreenEnabled;
   [BinaryName="fullscreenEnabled", NeedsCallerType]
   readonly attribute boolean mozFullScreenEnabled;
 
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -300,28 +300,30 @@ struct PrefsSizes
 {
   PrefsSizes()
     : mHashTable(0)
     , mPrefValues(0)
     , mStringValues(0)
     , mCacheData(0)
     , mRootBranches(0)
     , mPrefNameArena(0)
-    , mCallbacks(0)
+    , mCallbacksObjects(0)
+    , mCallbacksDomains(0)
     , mMisc(0)
   {
   }
 
   size_t mHashTable;
   size_t mPrefValues;
   size_t mStringValues;
   size_t mCacheData;
   size_t mRootBranches;
   size_t mPrefNameArena;
-  size_t mCallbacks;
+  size_t mCallbacksObjects;
+  size_t mCallbacksDomains;
   size_t mMisc;
 };
 }
 
 static ArenaAllocator<8192, 1> gPrefNameArena;
 
 class Pref
 {
@@ -712,17 +714,17 @@ private:
 
   PrefValue mDefaultValue;
   PrefValue mUserValue;
 };
 
 class PrefEntry : public PLDHashEntryHdr
 {
 public:
-  Pref* mPref;  // Note: this is never null in a live entry.
+  Pref* mPref; // Note: this is never null in a live entry.
 
   static bool MatchEntry(const PLDHashEntryHdr* aEntry, const void* aKey)
   {
     auto entry = static_cast<const PrefEntry*>(aEntry);
     auto prefName = static_cast<const char*>(aKey);
 
     return entry->mPref->MatchEntry(prefName);
   }
@@ -739,59 +741,99 @@ public:
   {
     auto entry = static_cast<PrefEntry*>(aEntry);
 
     delete entry->mPref;
     entry->mPref = nullptr;
   }
 };
 
-struct CallbackNode
+class CallbackNode
 {
+public:
   CallbackNode(const char* aDomain,
                PrefChangedFunc aFunc,
                void* aData,
                Preferences::MatchKind aMatchKind)
     : mDomain(moz_xstrdup(aDomain))
     , mFunc(aFunc)
     , mData(aData)
-    , mMatchKind(aMatchKind)
-    , mNext(nullptr)
+    , mNextAndMatchKind(aMatchKind)
   {
   }
 
+  // mDomain is a UniquePtr<>, so any uses of Domain() should only be temporary
+  // borrows.
+  const char* Domain() const { return mDomain.get(); }
+
+  PrefChangedFunc Func() const { return mFunc; }
+  void ClearFunc() { mFunc = nullptr; }
+
+  void* Data() const { return mData; }
+
+  Preferences::MatchKind MatchKind() const
+  {
+    return static_cast<Preferences::MatchKind>(mNextAndMatchKind &
+                                               kMatchKindMask);
+  }
+
+  CallbackNode* Next() const
+  {
+    return reinterpret_cast<CallbackNode*>(mNextAndMatchKind & kNextMask);
+  }
+
+  void SetNext(CallbackNode* aNext)
+  {
+    uintptr_t matchKind = mNextAndMatchKind & kMatchKindMask;
+    mNextAndMatchKind = reinterpret_cast<uintptr_t>(aNext);
+    MOZ_ASSERT((mNextAndMatchKind & kMatchKindMask) == 0);
+    mNextAndMatchKind |= matchKind;
+  }
+
+  void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes)
+  {
+    aSizes.mCallbacksObjects += aMallocSizeOf(this);
+    aSizes.mCallbacksDomains += aMallocSizeOf(mDomain.get());
+  }
+
+private:
+  static const uintptr_t kMatchKindMask = uintptr_t(0x1);
+  static const uintptr_t kNextMask = ~kMatchKindMask;
+
   UniqueFreePtr<const char> mDomain;
 
   // If someone attempts to remove the node from the callback list while
   // NotifyCallbacks() is running, |func| is set to nullptr. Such nodes will
   // be removed at the end of NotifyCallbacks().
   PrefChangedFunc mFunc;
   void* mData;
-  Preferences::MatchKind mMatchKind;
-  CallbackNode* mNext;
+
+  // Conceptually this is two fields:
+  // - CallbackNode* mNext;
+  // - Preferences::MatchKind mMatchKind;
+  // They are combined into a tagged pointer to save memory.
+  uintptr_t mNextAndMatchKind;
 };
 
 static PLDHashTable* gHashTable;
 
 // The callback list contains all the priority callbacks followed by the
 // non-priority callbacks. gLastPriorityNode records where the first part ends.
 static CallbackNode* gFirstCallback = nullptr;
 static CallbackNode* gLastPriorityNode = nullptr;
 
 static bool gIsAnyPrefLocked = false;
 
 // These are only used during the call to NotifyCallbacks().
 static bool gCallbacksInProgress = false;
 static bool gShouldCleanupDeadNodes = false;
 
 static PLDHashTableOps pref_HashTableOps = {
-  PLDHashTable::HashStringKey,
-  PrefEntry::MatchEntry,
-  PLDHashTable::MoveEntryStub,
-  PrefEntry::ClearEntry,
+  PLDHashTable::HashStringKey, PrefEntry::MatchEntry,
+  PLDHashTable::MoveEntryStub, PrefEntry::ClearEntry,
   PrefEntry::InitEntry,
 };
 
 static Pref*
 pref_HashTableLookup(const char* aPrefName);
 
 static void
 NotifyCallbacks(const char* aPrefName);
@@ -953,26 +995,23 @@ pref_SetPref(const char* aPrefName,
 
   return NS_OK;
 }
 
 // Removes |node| from callback list. Returns the node after the deleted one.
 static CallbackNode*
 pref_RemoveCallbackNode(CallbackNode* aNode, CallbackNode* aPrevNode)
 {
-  NS_PRECONDITION(!aPrevNode || aPrevNode->mNext == aNode, "invalid params");
-  NS_PRECONDITION(aPrevNode || gFirstCallback == aNode, "invalid params");
-
-  NS_ASSERTION(
-    !gCallbacksInProgress,
-    "modifying the callback list while gCallbacksInProgress is true");
-
-  CallbackNode* next_node = aNode->mNext;
+  MOZ_ASSERT(!aPrevNode || aPrevNode->Next() == aNode);
+  MOZ_ASSERT(aPrevNode || gFirstCallback == aNode);
+  MOZ_ASSERT(!gCallbacksInProgress);
+
+  CallbackNode* next_node = aNode->Next();
   if (aPrevNode) {
-    aPrevNode->mNext = next_node;
+    aPrevNode->SetNext(next_node);
   } else {
     gFirstCallback = next_node;
   }
   if (gLastPriorityNode == aNode) {
     gLastPriorityNode = aPrevNode;
   }
   delete aNode;
   return next_node;
@@ -984,41 +1023,40 @@ NotifyCallbacks(const char* aPrefName)
   bool reentered = gCallbacksInProgress;
 
   // Nodes must not be deleted while gCallbacksInProgress is true.
   // Nodes that need to be deleted are marked for deletion by nulling
   // out the |func| pointer. We release them at the end of this function
   // if we haven't reentered.
   gCallbacksInProgress = true;
 
-  for (CallbackNode* node = gFirstCallback; node; node = node->mNext) {
-    if (node->mFunc) {
-      bool matches = node->mMatchKind == Preferences::ExactMatch
-                       ? strcmp(node->mDomain.get(), aPrefName) == 0
-                       : strncmp(node->mDomain.get(),
-                                 aPrefName,
-                                 strlen(node->mDomain.get())) == 0;
+  for (CallbackNode* node = gFirstCallback; node; node = node->Next()) {
+    if (node->Func()) {
+      bool matches =
+        node->MatchKind() == Preferences::ExactMatch
+          ? strcmp(node->Domain(), aPrefName) == 0
+          : strncmp(node->Domain(), aPrefName, strlen(node->Domain())) == 0;
       if (matches) {
-        (node->mFunc)(aPrefName, node->mData);
+        (node->Func())(aPrefName, node->Data());
       }
     }
   }
 
   gCallbacksInProgress = reentered;
 
   if (gShouldCleanupDeadNodes && !gCallbacksInProgress) {
     CallbackNode* prev_node = nullptr;
     CallbackNode* node = gFirstCallback;
 
     while (node) {
-      if (!node->mFunc) {
+      if (!node->Func()) {
         node = pref_RemoveCallbackNode(node, prev_node);
       } else {
         prev_node = node;
-        node = node->mNext;
+        node = node->Next();
       }
     }
     gShouldCleanupDeadNodes = false;
   }
 }
 
 //===========================================================================
 // Prefs parsing
@@ -2260,17 +2298,17 @@ nsPrefBranch::FreeObserverList()
     iter.Remove();
   }
   mFreeingObserverList = false;
 }
 
 void
 nsPrefBranch::RemoveExpiredCallback(PrefCallback* aCallback)
 {
-  NS_PRECONDITION(aCallback->IsExpired(), "Callback should be expired.");
+  MOZ_ASSERT(aCallback->IsExpired());
   mObservers.Remove(aCallback);
 }
 
 nsresult
 nsPrefBranch::GetDefaultFromPropertiesFile(const char* aPrefName,
                                            nsAString& aReturn)
 {
   // The default value contains a URL to a .properties file.
@@ -2296,17 +2334,17 @@ nsPrefBranch::GetDefaultFromPropertiesFi
   }
 
   return bundle->GetStringFromName(aPrefName, aReturn);
 }
 
 nsPrefBranch::PrefName
 nsPrefBranch::GetPrefName(const char* aPrefName) const
 {
-  NS_ASSERTION(aPrefName, "null pref name!");
+  MOZ_ASSERT(aPrefName);
 
   // For speed, avoid strcpy if we can.
   if (mPrefRoot.IsEmpty()) {
     return PrefName(aPrefName);
   }
 
   return PrefName(mPrefRoot + nsDependentCString(aPrefName));
 }
@@ -2498,17 +2536,17 @@ public:
     for (nsCString& pref : aPrefs) {
       outStream->Write(pref.get(), pref.Length(), &writeAmount);
       outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
     }
 
     // Tell the safe output stream to overwrite the real prefs file.
     // (It'll abort if there were any errors during writing.)
     nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
-    NS_ASSERTION(safeStream, "expected a safe output stream!");
+    MOZ_ASSERT(safeStream, "expected a safe output stream!");
     if (safeStream) {
       rv = safeStream->Finish();
     }
 
 #ifdef DEBUG
     if (NS_FAILED(rv)) {
       NS_WARNING("failed to save prefs file! possible data loss");
     }
@@ -2694,19 +2732,18 @@ PreferenceServiceReporter::CollectReport
     sizes.mCacheData += gCacheData->ShallowSizeOfIncludingThis(mallocSizeOf);
     for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
       sizes.mCacheData += mallocSizeOf((*gCacheData)[i]);
     }
   }
 
   sizes.mPrefNameArena += gPrefNameArena.SizeOfExcludingThis(mallocSizeOf);
 
-  for (CallbackNode* node = gFirstCallback; node; node = node->mNext) {
-    sizes.mCallbacks += mallocSizeOf(node);
-    sizes.mCallbacks += mallocSizeOf(node->mDomain.get());
+  for (CallbackNode* node = gFirstCallback; node; node = node->Next()) {
+    node->AddSizeOfIncludingThis(mallocSizeOf, sizes);
   }
 
   MOZ_COLLECT_REPORT("explicit/preferences/hash-table",
                      KIND_HEAP,
                      UNITS_BYTES,
                      sizes.mHashTable,
                      "Memory used by libpref's hash table.");
 
@@ -2735,22 +2772,28 @@ PreferenceServiceReporter::CollectReport
                      "Memory used by libpref's root branches.");
 
   MOZ_COLLECT_REPORT("explicit/preferences/pref-name-arena",
                      KIND_HEAP,
                      UNITS_BYTES,
                      sizes.mPrefNameArena,
                      "Memory used by libpref's arena for pref names.");
 
-  MOZ_COLLECT_REPORT("explicit/preferences/callbacks",
+  MOZ_COLLECT_REPORT("explicit/preferences/callbacks/objects",
                      KIND_HEAP,
                      UNITS_BYTES,
-                     sizes.mCallbacks,
-                     "Memory used by libpref's callbacks list, including "
-                     "pref names and prefixes.");
+                     sizes.mCallbacksObjects,
+                     "Memory used by pref callback objects.");
+
+  MOZ_COLLECT_REPORT("explicit/preferences/callbacks/domains",
+                     KIND_HEAP,
+                     UNITS_BYTES,
+                     sizes.mCallbacksDomains,
+                     "Memory used by pref callback domains (pref names and "
+                     "prefixes).");
 
   MOZ_COLLECT_REPORT("explicit/preferences/misc",
                      KIND_HEAP,
                      UNITS_BYTES,
                      sizes.mMisc,
                      "Miscellaneous memory used by libpref.");
 
   nsPrefBranch* rootBranch =
@@ -2990,22 +3033,21 @@ Preferences::Preferences()
 
 Preferences::~Preferences()
 {
   MOZ_ASSERT(!sPreferences);
 
   delete gCacheData;
   gCacheData = nullptr;
 
-  NS_ASSERTION(!gCallbacksInProgress,
-               "~Preferences was called while gCallbacksInProgress is true!");
+  MOZ_ASSERT(!gCallbacksInProgress);
 
   CallbackNode* node = gFirstCallback;
   while (node) {
-    CallbackNode* next_node = node->mNext;
+    CallbackNode* next_node = node->Next();
     delete node;
     node = next_node;
   }
   gLastPriorityNode = gFirstCallback = nullptr;
 
   delete gHashTable;
   gHashTable = nullptr;
 
@@ -3615,17 +3657,17 @@ pref_LoadPrefsInDir(nsIFile* aDir,
     rv = dirIterator->GetNext(getter_AddRefs(supports));
     prefFile = do_QueryInterface(supports);
     if (NS_FAILED(rv)) {
       break;
     }
 
     nsAutoCString leafName;
     prefFile->GetNativeLeafName(leafName);
-    NS_ASSERTION(
+    MOZ_ASSERT(
       !leafName.IsEmpty(),
       "Failure in default prefs: directory enumerator returned empty file?");
 
     // Skip non-js files.
     if (StringEndsWith(leafName,
                        NS_LITERAL_CSTRING(".js"),
                        nsCaseInsensitiveCStringComparator())) {
       bool shouldParse = true;
@@ -3934,41 +3976,41 @@ Preferences::InitInitialObjects()
     nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nullptr);
 
   return Ok();
 }
 
 /* static */ nsresult
 Preferences::GetBool(const char* aPrefName, bool* aResult, PrefValueKind aKind)
 {
-  NS_PRECONDITION(aResult, "aResult must not be NULL");
+  MOZ_ASSERT(aResult);
   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 
   Pref* pref = pref_HashTableLookup(aPrefName);
   return pref ? pref->GetBoolValue(aKind, aResult) : NS_ERROR_UNEXPECTED;
 }
 
 /* static */ nsresult
 Preferences::GetInt(const char* aPrefName,
                     int32_t* aResult,
                     PrefValueKind aKind)
 {
-  NS_PRECONDITION(aResult, "aResult must not be NULL");
+  MOZ_ASSERT(aResult);
   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 
   Pref* pref = pref_HashTableLookup(aPrefName);
   return pref ? pref->GetIntValue(aKind, aResult) : NS_ERROR_UNEXPECTED;
 }
 
 /* static */ nsresult
 Preferences::GetFloat(const char* aPrefName,
                       float* aResult,
                       PrefValueKind aKind)
 {
-  NS_PRECONDITION(aResult, "aResult must not be NULL");
+  MOZ_ASSERT(aResult);
 
   nsAutoCString result;
   nsresult rv = Preferences::GetCString(aPrefName, result, aKind);
   if (NS_SUCCEEDED(rv)) {
     *aResult = result.ToFloat(&rv);
   }
   return rv;
 }
@@ -4019,17 +4061,17 @@ Preferences::GetLocalizedString(const ch
 {
   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
   nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
   nsresult rv =
     GetRootBranch(aKind)->GetComplexValue(aPrefName,
                                           NS_GET_IID(nsIPrefLocalizedString),
                                           getter_AddRefs(prefLocalString));
   if (NS_SUCCEEDED(rv)) {
-    NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
+    MOZ_ASSERT(prefLocalString, "Succeeded but the result is NULL");
     prefLocalString->GetData(aResult);
   }
   return rv;
 }
 
 /* static */ nsresult
 Preferences::GetComplex(const char* aPrefName,
                         const nsIID& aType,
@@ -4339,28 +4381,28 @@ Preferences::RegisterCallback(PrefChange
   NS_ENSURE_ARG(aCallback);
 
   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 
   auto node = new CallbackNode(aPrefNode, aCallback, aData, aMatchKind);
 
   if (aIsPriority) {
     // Add to the start of the list.
-    node->mNext = gFirstCallback;
+    node->SetNext(gFirstCallback);
     gFirstCallback = node;
     if (!gLastPriorityNode) {
       gLastPriorityNode = node;
     }
   } else {
     // Add to the start of the non-priority part of the list.
     if (gLastPriorityNode) {
-      node->mNext = gLastPriorityNode->mNext;
-      gLastPriorityNode->mNext = node;
+      node->SetNext(gLastPriorityNode->Next());
+      gLastPriorityNode->SetNext(node);
     } else {
-      node->mNext = gFirstCallback;
+      node->SetNext(gFirstCallback);
       gFirstCallback = node;
     }
   }
 
   return NS_OK;
 }
 
 /* static */ nsresult
@@ -4390,33 +4432,33 @@ Preferences::UnregisterCallback(PrefChan
   }
   NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
 
   nsresult rv = NS_ERROR_FAILURE;
   CallbackNode* node = gFirstCallback;
   CallbackNode* prev_node = nullptr;
 
   while (node) {
-    if (node->mFunc == aCallback && node->mData == aData &&
-        node->mMatchKind == aMatchKind &&
-        strcmp(node->mDomain.get(), aPrefNode) == 0) {
+    if (node->Func() == aCallback && node->Data() == aData &&
+        node->MatchKind() == aMatchKind &&
+        strcmp(node->Domain(), aPrefNode) == 0) {
       if (gCallbacksInProgress) {
-        // postpone the node removal until after
-        // callbacks enumeration is finished.
-        node->mFunc = nullptr;
+        // Postpone the node removal until after callbacks enumeration is
+        // finished.
+        node->ClearFunc();
         gShouldCleanupDeadNodes = true;
         prev_node = node;
-        node = node->mNext;
+        node = node->Next();
       } else {
         node = pref_RemoveCallbackNode(node, prev_node);
       }
       rv = NS_OK;
     } else {
       prev_node = node;
-      node = node->mNext;
+      node = node->Next();
     }
   }
   return rv;
 }
 
 static void
 CacheDataAppendElement(CacheData* aData)
 {
@@ -4432,17 +4474,17 @@ BoolVarChanged(const char* aPref, void* 
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *static_cast<bool*>(cache->mCacheLocation) =
     Preferences::GetBool(aPref, cache->mDefaultValueBool);
 }
 
 /* static */ nsresult
 Preferences::AddBoolVarCache(bool* aCache, const char* aPref, bool aDefault)
 {
-  NS_ASSERTION(aCache, "aCache must not be NULL");
+  MOZ_ASSERT(aCache);
 #ifdef DEBUG
   AssertNotAlreadyCached("bool", aPref, aCache);
 #endif
   *aCache = GetBool(aPref, aDefault);
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueBool = aDefault;
   CacheDataAppendElement(data);
@@ -4464,17 +4506,17 @@ AtomicBoolVarChanged(const char* aPref, 
 }
 
 template<MemoryOrdering Order>
 /* static */ nsresult
 Preferences::AddAtomicBoolVarCache(Atomic<bool, Order>* aCache,
                                    const char* aPref,
                                    bool aDefault)
 {
-  NS_ASSERTION(aCache, "aCache must not be NULL");
+  MOZ_ASSERT(aCache);
 #ifdef DEBUG
   AssertNotAlreadyCached("bool", aPref, aCache);
 #endif
   *aCache = Preferences::GetBool(aPref, aDefault);
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueBool = aDefault;
   CacheDataAppendElement(data);
@@ -4494,17 +4536,17 @@ IntVarChanged(const char* aPref, void* a
     Preferences::GetInt(aPref, cache->mDefaultValueInt);
 }
 
 /* static */ nsresult
 Preferences::AddIntVarCache(int32_t* aCache,
                             const char* aPref,
                             int32_t aDefault)
 {
-  NS_ASSERTION(aCache, "aCache must not be NULL");
+  MOZ_ASSERT(aCache);
 #ifdef DEBUG
   AssertNotAlreadyCached("int", aPref, aCache);
 #endif
   *aCache = Preferences::GetInt(aPref, aDefault);
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueInt = aDefault;
   CacheDataAppendElement(data);
@@ -4523,17 +4565,17 @@ AtomicIntVarChanged(const char* aPref, v
 }
 
 template<MemoryOrdering Order>
 /* static */ nsresult
 Preferences::AddAtomicIntVarCache(Atomic<int32_t, Order>* aCache,
                                   const char* aPref,
                                   int32_t aDefault)
 {
-  NS_ASSERTION(aCache, "aCache must not be NULL");
+  MOZ_ASSERT(aCache);
 #ifdef DEBUG
   AssertNotAlreadyCached("int", aPref, aCache);
 #endif
   *aCache = Preferences::GetInt(aPref, aDefault);
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueUint = aDefault;
   CacheDataAppendElement(data);
@@ -4553,17 +4595,17 @@ UintVarChanged(const char* aPref, void* 
     Preferences::GetUint(aPref, cache->mDefaultValueUint);
 }
 
 /* static */ nsresult
 Preferences::AddUintVarCache(uint32_t* aCache,
                              const char* aPref,
                              uint32_t aDefault)
 {
-  NS_ASSERTION(aCache, "aCache must not be NULL");
+  MOZ_ASSERT(aCache);
 #ifdef DEBUG
   AssertNotAlreadyCached("uint", aPref, aCache);
 #endif
   *aCache = Preferences::GetUint(aPref, aDefault);
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueUint = aDefault;
   CacheDataAppendElement(data);
@@ -4585,17 +4627,17 @@ AtomicUintVarChanged(const char* aPref, 
 }
 
 template<MemoryOrdering Order>
 /* static */ nsresult
 Preferences::AddAtomicUintVarCache(Atomic<uint32_t, Order>* aCache,
                                    const char* aPref,
                                    uint32_t aDefault)
 {
-  NS_ASSERTION(aCache, "aCache must not be NULL");
+  MOZ_ASSERT(aCache);
 #ifdef DEBUG
   AssertNotAlreadyCached("uint", aPref, aCache);
 #endif
   *aCache = Preferences::GetUint(aPref, aDefault);
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueUint = aDefault;
   CacheDataAppendElement(data);
@@ -4644,17 +4686,17 @@ FloatVarChanged(const char* aPref, void*
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *static_cast<float*>(cache->mCacheLocation) =
     Preferences::GetFloat(aPref, cache->mDefaultValueFloat);
 }
 
 /* static */ nsresult
 Preferences::AddFloatVarCache(float* aCache, const char* aPref, float aDefault)
 {
-  NS_ASSERTION(aCache, "aCache must not be NULL");
+  MOZ_ASSERT(aCache);
 #ifdef DEBUG
   AssertNotAlreadyCached("float", aPref, aCache);
 #endif
   *aCache = Preferences::GetFloat(aPref, aDefault);
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueFloat = aDefault;
   CacheDataAppendElement(data);
--- a/testing/web-platform/meta/fullscreen/interfaces.html.ini
+++ b/testing/web-platform/meta/fullscreen/interfaces.html.ini
@@ -1,15 +1,12 @@
 [interfaces.html]
   [Document interface: operation exitFullscreen()]
     expected: FAIL
 
-  [Unscopable handled correctly for fullscreen property on Document]
-    expected: FAIL
-
   [ShadowRoot interface: attribute fullscreenElement]
     expected: FAIL
 
   [Element interface: operation requestFullscreen()]
     expected: FAIL
 
   [Element interface: attribute onfullscreenchange]
     expected: FAIL
--- a/testing/web-platform/tests/payment-request/interfaces.https.html
+++ b/testing/web-platform/tests/payment-request/interfaces.https.html
@@ -11,17 +11,17 @@ promise_test(async () => {
   const [dom, payment_request] = await Promise.all(
     urls.map(url => fetch(url).then(r => r.text())));
   const idlArray = new IdlArray();
   idlArray.add_untested_idls(dom);
   idlArray.add_idls(payment_request);
 
   // typedef EventHandler from HTML
   // https://html.spec.whatwg.org/#eventhandler
-  idlArray.add_idls(`
+  idlArray.add_untested_idls(`
     [TreatNonObjectAsNull]
     callback EventHandlerNonNull = any (Event event);
     typedef EventHandlerNonNull? EventHandler;
   `);
   const methods = "[{supportedMethods: 'foo'}]";
   const amount = "{currency: 'USD', value: '0'}";
   const details = `{total: {label: 'bar', amount: ${amount}} }`;
   idlArray.add_objects({
--- a/testing/web-platform/tests/resources/idlharness.js
+++ b/testing/web-platform/tests/resources/idlharness.js
@@ -1602,28 +1602,25 @@ IdlInterface.prototype.test_self = funct
             assert_equals(typeof desc.value, "object",
                           this.name + '.prototype[Symbol.unscopables] should be an object');
             assert_equals(Object.getPrototypeOf(desc.value), null,
                           this.name + '.prototype[Symbol.unscopables] should have a null prototype');
             assert_equals(Object.getOwnPropertySymbols(desc.value).length,
                           0,
                           this.name + '.prototype[Symbol.unscopables] should have the right number of symbol-named properties');
 
-            // Check that we do not have _extra_ unscopables.  Checking that we
-            // have all the ones we should will happen in the per-member tests.
-            var observed = Object.getOwnPropertyNames(desc.value);
-            for (var prop of observed) {
-                assert_not_equals(unscopables.indexOf(prop),
-                                  -1,
-                                  this.name + '.prototype[Symbol.unscopables] has unexpected property "' + prop + '"');
-            }
+            // It would be nice to check that we do not have _extra_
+            // unscopables, but someone might be calling us with only a subset
+            // of the IDL the browser know about, and our subset may exclude
+            // unscopable things that really do exist.
         } else {
-            assert_equals(Object.getOwnPropertyDescriptor(self[this.name].prototype, Symbol.unscopables),
-                          undefined,
-                          this.name + '.prototype should not have @@unscopables');
+            // It would be nice to assert that there is no @@unscopables on this
+            // prototype, but someone might be calling us with only a subset of
+            // the IDL the browser know about, and our subset may exclude
+            // unscopable things that really do exist.
         }
     }.bind(this), this.name + ' interface: existence and properties of interface prototype object\'s @@unscopables property');
 
 };
 
 //@}
 IdlInterface.prototype.test_immutable_prototype = function(type, obj)
 //@{
@@ -1957,16 +1954,18 @@ IdlInterface.prototype.do_member_unscopa
 {
     // Check that if the member is unscopable then it's in the
     // @@unscopables object properly.
     if (!member.isUnscopable) {
         return;
     }
 
     var unscopables = self[this.name].prototype[Symbol.unscopables];
+    assert_equals(typeof unscopables, "object",
+                  this.name + '.prototype[Symbol.unscopables] must exist');
     var prop = member.name;
     var propDesc = Object.getOwnPropertyDescriptor(unscopables, prop);
     assert_equals(typeof propDesc, "object",
                   this.name + '.prototype[Symbol.unscopables].' + prop + ' must exist')
     assert_false("get" in propDesc,
                  this.name + '.prototype[Symbol.unscopables].' + prop + ' must have no getter');
     assert_false("set" in propDesc,
                  this.name + '.prototype[Symbol.unscopables].' + prop + ' must have no setter');
--- a/toolkit/modules/Log.jsm
+++ b/toolkit/modules/Log.jsm
@@ -182,26 +182,26 @@ var Log = {
           str = frame.name + "()@" + str;
         }
 
         if (str) {
           output.push(str);
         }
         frame = frame.caller;
       }
-      return "Stack trace: " + output.join(" < ");
+      return "Stack trace: " + output.join("\n");
     }
     // Standard JS exception
     if (e.stack) {
       let stack = e.stack;
       // Avoid loading Task.jsm if there's no task on the stack.
       if (stack.includes("/Task.jsm:"))
         stack = Task.Debugging.generateReadableStack(stack);
       return "JS Stack trace: " + stack.trim()
-        .replace(/\n/g, " < ").replace(/@[^@]*?([^\/\.]+\.\w+:)/g, "@$1");
+        .replace(/@[^@]*?([^\/\.]+\.\w+:)/g, "@$1");
     }
 
     return "No traceback available";
   }
 };
 
 /*
  * LogMessage