Bug 1174594 (part 1) - Remove uses of PL_DHashTableEnumerate from XPConnect. r=mrbkap.
authorNicholas Nethercote <nnethercote@mozilla.com>
Thu, 18 Jun 2015 15:34:25 -0700
changeset 249678 9eed99d204967b603da7eb343dd04e059db4e01f
parent 249677 9bee343c34ec0bf144f95c277680f7e5263dd24d
child 249679 81945c5fa51dbfe019a8e9161823fdb5c9d0d147
push id28936
push userryanvm@gmail.com
push dateFri, 19 Jun 2015 20:34:42 +0000
treeherdermozilla-central@c319f262ce3e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs1174594
milestone41.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
Bug 1174594 (part 1) - Remove uses of PL_DHashTableEnumerate from XPConnect. r=mrbkap. Each PLDHashTable-based map class in XPCMaps has its Enumerate() function replaced with an Iterator and/or a RemovingIterator.
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCMaps.h
js/xpconnect/src/XPCWrappedNativeScope.cpp
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -109,104 +109,21 @@ static mozilla::Atomic<bool> sExtraWarni
 bool xpc::ExtraWarningsForSystemJS() { return sExtraWarningsForSystemJS; }
 #else
 bool xpc::ExtraWarningsForSystemJS() { return false; }
 #endif
 
 static void * const UNMARK_ONLY = nullptr;
 static void * const UNMARK_AND_SWEEP = (void*)1;
 
-static PLDHashOperator
-NativeInterfaceSweeper(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                       uint32_t number, void* arg)
-{
-    XPCNativeInterface* iface = ((IID2NativeInterfaceMap::Entry*)hdr)->value;
-    if (iface->IsMarked()) {
-        iface->Unmark();
-        return PL_DHASH_NEXT;
-    }
-
-    if (arg == UNMARK_ONLY)
-        return PL_DHASH_NEXT;
-
-    XPCNativeInterface::DestroyInstance(iface);
-    return PL_DHASH_REMOVE;
-}
-
 // *Some* NativeSets are referenced from mClassInfo2NativeSetMap.
 // *All* NativeSets are referenced from mNativeSetMap.
 // So, in mClassInfo2NativeSetMap we just clear references to the unmarked.
 // In mNativeSetMap we clear the references to the unmarked *and* delete them.
 
-static PLDHashOperator
-NativeUnMarkedSetRemover(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                         uint32_t number, void* arg)
-{
-    XPCNativeSet* set = ((ClassInfo2NativeSetMap::Entry*)hdr)->value;
-    if (set->IsMarked())
-        return PL_DHASH_NEXT;
-    return PL_DHASH_REMOVE;
-}
-
-static PLDHashOperator
-NativeSetSweeper(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                 uint32_t number, void* arg)
-{
-    XPCNativeSet* set = ((NativeSetMap::Entry*)hdr)->key_value;
-    if (set->IsMarked()) {
-        set->Unmark();
-        return PL_DHASH_NEXT;
-    }
-
-    if (arg == UNMARK_ONLY)
-        return PL_DHASH_NEXT;
-
-    XPCNativeSet::DestroyInstance(set);
-    return PL_DHASH_REMOVE;
-}
-
-static PLDHashOperator
-JSClassSweeper(PLDHashTable* table, PLDHashEntryHdr* hdr,
-               uint32_t number, void* arg)
-{
-    XPCNativeScriptableShared* shared =
-        ((XPCNativeScriptableSharedMap::Entry*) hdr)->key;
-    if (shared->IsMarked()) {
-        shared->Unmark();
-        return PL_DHASH_NEXT;
-    }
-
-    if (arg == UNMARK_ONLY)
-        return PL_DHASH_NEXT;
-
-    delete shared;
-    return PL_DHASH_REMOVE;
-}
-
-static PLDHashOperator
-DyingProtoKiller(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                 uint32_t number, void* arg)
-{
-    XPCWrappedNativeProto* proto =
-        (XPCWrappedNativeProto*)((PLDHashEntryStub*)hdr)->key;
-    delete proto;
-    return PL_DHASH_REMOVE;
-}
-
-static PLDHashOperator
-DetachedWrappedNativeProtoMarker(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                                 uint32_t number, void* arg)
-{
-    XPCWrappedNativeProto* proto =
-        (XPCWrappedNativeProto*)((PLDHashEntryStub*)hdr)->key;
-
-    proto->Mark();
-    return PL_DHASH_NEXT;
-}
-
 bool
 XPCJSRuntime::CustomContextCallback(JSContext* cx, unsigned operation)
 {
     if (operation == JSCONTEXT_NEW) {
         if (!OnJSContextNew(cx)) {
             return false;
         }
     } else if (operation == JSCONTEXT_DESTROY) {
@@ -838,18 +755,20 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp*
             self->mGCIsRunning = true;
 
             // We use this occasion to mark and sweep NativeInterfaces,
             // NativeSets, and the WrappedNativeJSClasses...
 
             // Do the marking...
             XPCWrappedNativeScope::MarkAllWrappedNativesAndProtos();
 
-            self->mDetachedWrappedNativeProtoMap->
-                Enumerate(DetachedWrappedNativeProtoMarker, nullptr);
+            for (auto i = self->mDetachedWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
+                auto entry = static_cast<XPCWrappedNativeProtoMap::Entry*>(i.Get());
+                static_cast<const XPCWrappedNativeProto*>(entry->key)->Mark();
+            }
 
             // Mark the sets used in the call contexts. There is a small
             // chance that a wrapper's set will change *while* a call is
             // happening which uses that wrapper's old interfface set. So,
             // we need to do this marking to avoid collecting those sets
             // that might no longer be otherwise reachable from the wrappers
             // or the wrapperprotos.
 
@@ -893,30 +812,66 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp*
             // compartments being collected. Currently, though, NativeInterfaces
             // are shared between compartments. This ought to be fixed.
             void* sweepArg = isCompartmentGC ? UNMARK_ONLY : UNMARK_AND_SWEEP;
 
             // We don't want to sweep the JSClasses at shutdown time.
             // At this point there may be JSObjects using them that have
             // been removed from the other maps.
             if (!nsXPConnect::XPConnect()->IsShuttingDown()) {
-                self->mNativeScriptableSharedMap->
-                    Enumerate(JSClassSweeper, sweepArg);
+                for (auto i = self->mNativeScriptableSharedMap->RemovingIter(); !i.Done(); i.Next()) {
+                    auto entry = static_cast<XPCNativeScriptableSharedMap::Entry*>(i.Get());
+                    XPCNativeScriptableShared* shared = entry->key;
+                    if (shared->IsMarked()) {
+                        shared->Unmark();
+                        continue;
+                    }
+                    if (sweepArg == UNMARK_ONLY)
+                        continue;
+
+                    delete shared;
+                    i.Remove();
+                }
             }
 
             if (!isCompartmentGC) {
-                self->mClassInfo2NativeSetMap->
-                    Enumerate(NativeUnMarkedSetRemover, nullptr);
+                for (auto i = self->mClassInfo2NativeSetMap->RemovingIter(); !i.Done(); i.Next()) {
+                    auto entry = static_cast<ClassInfo2NativeSetMap::Entry*>(i.Get());
+                    if (!entry->value->IsMarked())
+                        i.Remove();
+                }
             }
 
-            self->mNativeSetMap->
-                Enumerate(NativeSetSweeper, sweepArg);
-
-            self->mIID2NativeInterfaceMap->
-                Enumerate(NativeInterfaceSweeper, sweepArg);
+            for (auto i = self->mNativeSetMap->RemovingIter(); !i.Done(); i.Next()) {
+                auto entry = static_cast<NativeSetMap::Entry*>(i.Get());
+                XPCNativeSet* set = entry->key_value;
+                if (set->IsMarked()) {
+                    set->Unmark();
+                    continue;
+                }
+                if (sweepArg == UNMARK_ONLY)
+                    continue;
+
+                XPCNativeSet::DestroyInstance(set);
+                i.Remove();
+            }
+
+            for (auto i = self->mIID2NativeInterfaceMap->RemovingIter(); !i.Done(); i.Next()) {
+                auto entry = static_cast<IID2NativeInterfaceMap::Entry*>(i.Get());
+                XPCNativeInterface* iface = entry->value;
+                if (iface->IsMarked()) {
+                    iface->Unmark();
+                    continue;
+                }
+                if (sweepArg == UNMARK_ONLY)
+                    continue;
+
+                XPCNativeInterface::DestroyInstance(iface);
+                i.Remove();
+            }
 
 #ifdef DEBUG
             XPCWrappedNativeScope::ASSERT_NoInterfaceSetsAreMarked();
 #endif
 
             // Now we are going to recycle any unused WrappedNativeTearoffs.
             // We do this by iterating all the live callcontexts
             // and marking the tearoffs in use. And then we
@@ -962,18 +917,21 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp*
             // finalized and destroyed. We *do* know that the protos'
             // JSObjects would not have been finalized if there were any
             // wrappers that referenced the proto but where not themselves
             // slated for finalization in this gc cycle. So... at this point
             // we know that any and all wrappers that might have been
             // referencing the protos in the dying list are themselves dead.
             // So, we can safely delete all the protos in the list.
 
-            self->mDyingWrappedNativeProtoMap->
-                Enumerate(DyingProtoKiller, nullptr);
+            for (auto i = self->mDyingWrappedNativeProtoMap->RemovingIter(); !i.Done(); i.Next()) {
+                auto entry = static_cast<XPCWrappedNativeProtoMap::Entry*>(i.Get());
+                delete static_cast<const XPCWrappedNativeProto*>(entry->key);
+                i.Remove();
+            }
 
             MOZ_ASSERT(self->mGCIsRunning, "bad state");
             self->mGCIsRunning = false;
 
             break;
         }
     }
 }
@@ -1536,37 +1494,29 @@ XPCJSRuntime::SizeOfIncludingThis(Malloc
     // ones have been seen by DMD to be worth measuring.  More stuff may be
     // added later.
 
     return n;
 }
 
 /***************************************************************************/
 
-static PLDHashOperator
-DetachedWrappedNativeProtoShutdownMarker(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                                         uint32_t number, void* arg)
-{
-    XPCWrappedNativeProto* proto =
-        (XPCWrappedNativeProto*)((PLDHashEntryStub*)hdr)->key;
-
-    proto->SystemIsBeingShutDown();
-    return PL_DHASH_NEXT;
-}
-
 void XPCJSRuntime::DestroyJSContextStack()
 {
     delete mJSContextStack;
     mJSContextStack = nullptr;
 }
 
 void XPCJSRuntime::SystemIsBeingShutDown()
 {
-    mDetachedWrappedNativeProtoMap->
-        Enumerate(DetachedWrappedNativeProtoShutdownMarker, nullptr);
+    for (auto i = mDetachedWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
+        auto entry = static_cast<XPCWrappedNativeProtoMap::Entry*>(i.Get());
+        auto proto = const_cast<XPCWrappedNativeProto*>(static_cast<const XPCWrappedNativeProto*>(entry->key));
+        proto->SystemIsBeingShutDown();
+    }
 }
 
 #define JS_OPTIONS_DOT_STR "javascript.options."
 
 static void
 ReloadPrefsCallback(const char* pref, void* data)
 {
     XPCJSRuntime* runtime = reinterpret_cast<XPCJSRuntime*>(data);
@@ -3633,33 +3583,16 @@ XPCJSRuntime::NoteCustomGCThingXPCOMChil
         static_cast<XPCWrappedNativeTearOff*>(xpc_GetJSPrivate(obj));
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "xpc_GetJSPrivate(obj)->mNative");
     cb.NoteXPCOMChild(to->GetNative());
     return true;
 }
 
 /***************************************************************************/
 
-#ifdef DEBUG
-static PLDHashOperator
-WrappedJSClassMapDumpEnumerator(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                                uint32_t number, void* arg)
-{
-    ((IID2WrappedJSClassMap::Entry*)hdr)->value->DebugDump(*(int16_t*)arg);
-    return PL_DHASH_NEXT;
-}
-static PLDHashOperator
-NativeSetDumpEnumerator(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                        uint32_t number, void* arg)
-{
-    ((NativeSetMap::Entry*)hdr)->key_value->DebugDump(*(int16_t*)arg);
-    return PL_DHASH_NEXT;
-}
-#endif
-
 void
 XPCJSRuntime::DebugDump(int16_t depth)
 {
 #ifdef DEBUG
     depth--;
     XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", this));
         XPC_LOG_INDENT();
         XPC_LOG_ALWAYS(("mJSRuntime @ %x", Runtime()));
@@ -3682,17 +3615,20 @@ XPCJSRuntime::DebugDump(int16_t depth)
             XPC_LOG_OUTDENT();
         }
 
         XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %x with %d wrapperclasses(s)",
                         mWrappedJSClassMap, mWrappedJSClassMap->Count()));
         // iterate wrappersclasses...
         if (depth && mWrappedJSClassMap->Count()) {
             XPC_LOG_INDENT();
-            mWrappedJSClassMap->Enumerate(WrappedJSClassMapDumpEnumerator, &depth);
+            for (auto i = mWrappedJSClassMap->Iter(); !i.Done(); i.Next()) {
+                auto entry = static_cast<IID2WrappedJSClassMap::Entry*>(i.Get());
+                entry->value->DebugDump(depth);
+            }
             XPC_LOG_OUTDENT();
         }
         XPC_LOG_ALWAYS(("mWrappedJSMap @ %x with %d wrappers(s)",
                         mWrappedJSMap, mWrappedJSMap->Count()));
         // iterate wrappers...
         if (depth && mWrappedJSMap->Count()) {
             XPC_LOG_INDENT();
             mWrappedJSMap->Dump(depth);
@@ -3711,17 +3647,20 @@ XPCJSRuntime::DebugDump(int16_t depth)
                         mThisTranslatorMap, mThisTranslatorMap->Count()));
 
         XPC_LOG_ALWAYS(("mNativeSetMap @ %x with %d sets(s)",
                         mNativeSetMap, mNativeSetMap->Count()));
 
         // iterate sets...
         if (depth && mNativeSetMap->Count()) {
             XPC_LOG_INDENT();
-            mNativeSetMap->Enumerate(NativeSetDumpEnumerator, &depth);
+            for (auto i = mNativeSetMap->RemovingIter(); !i.Done(); i.Next()) {
+                auto entry = static_cast<NativeSetMap::Entry*>(i.Get());
+                entry->key_value->DebugDump(depth);
+            }
             XPC_LOG_OUTDENT();
         }
 
         XPC_LOG_OUTDENT();
 #endif
 }
 
 /***************************************************************************/
--- a/js/xpconnect/src/XPCMaps.h
+++ b/js/xpconnect/src/XPCMaps.h
@@ -143,18 +143,19 @@ public:
                    "About to remove a different wrapper with the same "
                    "nsISupports identity! This will most likely cause serious "
                    "problems!");
 #endif
         PL_DHashTableRemove(mTable, wrapper->GetIdentityObject());
     }
 
     inline uint32_t Count() { return mTable->EntryCount(); }
-    inline uint32_t Enumerate(PLDHashEnumerator f, void* arg)
-        {return PL_DHashTableEnumerate(mTable, f, arg);}
+
+    PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
+    PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
     ~Native2WrappedNativeMap();
 private:
     Native2WrappedNativeMap();    // no implementation
     explicit Native2WrappedNativeMap(int size);
 
@@ -202,18 +203,18 @@ public:
 
     inline void Remove(nsXPCWrappedJSClass* clazz)
     {
         NS_PRECONDITION(clazz,"bad param");
         PL_DHashTableRemove(mTable, &clazz->GetIID());
     }
 
     inline uint32_t Count() { return mTable->EntryCount(); }
-    inline uint32_t Enumerate(PLDHashEnumerator f, void* arg)
-        {return PL_DHashTableEnumerate(mTable, f, arg);}
+
+    PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
 
     ~IID2WrappedJSClassMap();
 private:
     IID2WrappedJSClassMap();    // no implementation
     explicit IID2WrappedJSClassMap(int size);
 private:
     PLDHashTable* mTable;
 };
@@ -256,18 +257,18 @@ public:
 
     inline void Remove(XPCNativeInterface* iface)
     {
         NS_PRECONDITION(iface,"bad param");
         PL_DHashTableRemove(mTable, iface->GetIID());
     }
 
     inline uint32_t Count() { return mTable->EntryCount(); }
-    inline uint32_t Enumerate(PLDHashEnumerator f, void* arg)
-        {return PL_DHashTableEnumerate(mTable, f, arg);}
+
+    PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
     ~IID2NativeInterfaceMap();
 private:
     IID2NativeInterfaceMap();    // no implementation
     explicit IID2NativeInterfaceMap(int size);
 
@@ -312,18 +313,18 @@ public:
 
     inline void Remove(nsIClassInfo* info)
     {
         NS_PRECONDITION(info,"bad param");
         PL_DHashTableRemove(mTable, info);
     }
 
     inline uint32_t Count() { return mTable->EntryCount(); }
-    inline uint32_t Enumerate(PLDHashEnumerator f, void* arg)
-        {return PL_DHashTableEnumerate(mTable, f, arg);}
+
+    PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
 
     // ClassInfo2NativeSetMap holds pointers to *some* XPCNativeSets.
     // So we don't want to count those XPCNativeSets, because they are better
     // counted elsewhere (i.e. in XPCJSRuntime::mNativeSetMap, which holds
     // pointers to *all* XPCNativeSets).  Hence the "Shallow".
     size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
     ~ClassInfo2NativeSetMap();
@@ -369,18 +370,19 @@ public:
 
     inline void Remove(nsIClassInfo* info)
     {
         NS_PRECONDITION(info,"bad param");
         PL_DHashTableRemove(mTable, info);
     }
 
     inline uint32_t Count() { return mTable->EntryCount(); }
-    inline uint32_t Enumerate(PLDHashEnumerator f, void* arg)
-        {return PL_DHashTableEnumerate(mTable, f, arg);}
+
+    PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
+    PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
     ~ClassInfo2WrappedNativeProtoMap();
 private:
     ClassInfo2WrappedNativeProtoMap();    // no implementation
     explicit ClassInfo2WrappedNativeProtoMap(int size);
 
@@ -439,18 +441,19 @@ public:
     {
         NS_PRECONDITION(set,"bad param");
 
         XPCNativeSetKey key(set, nullptr, 0);
         PL_DHashTableRemove(mTable, &key);
     }
 
     inline uint32_t Count() { return mTable->EntryCount(); }
-    inline uint32_t Enumerate(PLDHashEnumerator f, void* arg)
-        {return PL_DHashTableEnumerate(mTable, f, arg);}
+
+    PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
+    PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
     ~NativeSetMap();
 private:
     NativeSetMap();    // no implementation
     explicit NativeSetMap(int size);
 
@@ -502,18 +505,16 @@ public:
     }
 
     inline void Remove(REFNSIID iid)
     {
         PL_DHashTableRemove(mTable, &iid);
     }
 
     inline uint32_t Count() { return mTable->EntryCount(); }
-    inline uint32_t Enumerate(PLDHashEnumerator f, void* arg)
-        {return PL_DHashTableEnumerate(mTable, f, arg);}
 
     ~IID2ThisTranslatorMap();
 private:
     IID2ThisTranslatorMap();    // no implementation
     explicit IID2ThisTranslatorMap(int size);
 private:
     PLDHashTable* mTable;
 };
@@ -538,32 +539,34 @@ public:
         static const struct PLDHashTableOps sOps;
     };
 
     static XPCNativeScriptableSharedMap* newMap(int length);
 
     bool GetNewOrUsed(uint32_t flags, char* name, XPCNativeScriptableInfo* si);
 
     inline uint32_t Count() { return mTable->EntryCount(); }
-    inline uint32_t Enumerate(PLDHashEnumerator f, void* arg)
-        {return PL_DHashTableEnumerate(mTable, f, arg);}
+
+    PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
 
     ~XPCNativeScriptableSharedMap();
 private:
     XPCNativeScriptableSharedMap();    // no implementation
     explicit XPCNativeScriptableSharedMap(int size);
 private:
     PLDHashTable* mTable;
 };
 
 /***************************************************************************/
 
 class XPCWrappedNativeProtoMap
 {
 public:
+    typedef PLDHashEntryStub Entry;
+
     static XPCWrappedNativeProtoMap* newMap(int length);
 
     inline XPCWrappedNativeProto* Add(XPCWrappedNativeProto* proto)
     {
         NS_PRECONDITION(proto,"bad param");
         PLDHashEntryStub* entry = static_cast<PLDHashEntryStub*>
             (PL_DHashTableAdd(mTable, proto, mozilla::fallible));
         if (!entry)
@@ -576,18 +579,19 @@ public:
 
     inline void Remove(XPCWrappedNativeProto* proto)
     {
         NS_PRECONDITION(proto,"bad param");
         PL_DHashTableRemove(mTable, proto);
     }
 
     inline uint32_t Count() { return mTable->EntryCount(); }
-    inline uint32_t Enumerate(PLDHashEnumerator f, void* arg)
-        {return PL_DHashTableEnumerate(mTable, f, arg);}
+
+    PLDHashTable::Iterator Iter() const { return PLDHashTable::Iterator(mTable); }
+    PLDHashTable::RemovingIterator RemovingIter() { return PLDHashTable::RemovingIterator(mTable); }
 
     ~XPCWrappedNativeProtoMap();
 private:
     XPCWrappedNativeProtoMap();    // no implementation
     explicit XPCWrappedNativeProtoMap(int size);
 private:
     PLDHashTable* mTable;
 };
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -456,72 +456,58 @@ XPCWrappedNativeScope::~XPCWrappedNative
 
     JSRuntime* rt = XPCJSRuntime::Get()->Runtime();
     mContentXBLScope.finalize(rt);
     for (size_t i = 0; i < mAddonScopes.Length(); i++)
         mAddonScopes[i].finalize(rt);
     mGlobalJSObject.finalize(rt);
 }
 
-static PLDHashOperator
-WrappedNativeJSGCThingTracer(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                             uint32_t number, void* arg)
-{
-    XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
-    if (wrapper->HasExternalReference() && !wrapper->IsWrapperExpired())
-        wrapper->TraceSelf((JSTracer*)arg);
-
-    return PL_DHASH_NEXT;
-}
-
 // static
 void
 XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSRuntime* rt)
 {
     // Do JS_CallTracer for all wrapped natives with external references, as
     // well as any DOM expando objects.
     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
-        cur->mWrappedNativeMap->Enumerate(WrappedNativeJSGCThingTracer, trc);
+        for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
+            auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
+            XPCWrappedNative* wrapper = entry->value;
+            if (wrapper->HasExternalReference() && !wrapper->IsWrapperExpired())
+                wrapper->TraceSelf(trc);
+        }
+
         if (cur->mDOMExpandoSet) {
             for (DOMExpandoSet::Enum e(*cur->mDOMExpandoSet); !e.empty(); e.popFront())
                 JS_CallHashSetObjectTracer(trc, e, e.front(), "DOM expando object");
         }
     }
 }
 
-static PLDHashOperator
-WrappedNativeSuspecter(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                       uint32_t number, void* arg)
-{
-    XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
-
-    if (wrapper->HasExternalReference()) {
-        nsCycleCollectionNoteRootCallback* cb =
-            static_cast<nsCycleCollectionNoteRootCallback*>(arg);
-        XPCJSRuntime::SuspectWrappedNative(wrapper, *cb);
-    }
-
-    return PL_DHASH_NEXT;
-}
-
 static void
 SuspectDOMExpandos(JSObject* obj, nsCycleCollectionNoteRootCallback& cb)
 {
     MOZ_ASSERT(dom::GetDOMClass(obj) && dom::GetDOMClass(obj)->mDOMObjectIsISupports);
     nsISupports* native = dom::UnwrapDOMObject<nsISupports>(obj);
     cb.NoteXPCOMRoot(native);
 }
 
 // static
 void
 XPCWrappedNativeScope::SuspectAllWrappers(XPCJSRuntime* rt,
                                           nsCycleCollectionNoteRootCallback& cb)
 {
     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
-        cur->mWrappedNativeMap->Enumerate(WrappedNativeSuspecter, &cb);
+        for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
+            auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
+            XPCWrappedNative* wrapper = entry->value;
+            if (wrapper->HasExternalReference())
+                XPCJSRuntime::SuspectWrappedNative(wrapper, cb);
+        }
+
         if (cur->mDOMExpandoSet) {
             for (DOMExpandoSet::Range r = cur->mDOMExpandoSet->all(); !r.empty(); r.popFront())
                 SuspectDOMExpandos(r.front(), cb);
         }
     }
 }
 
 // static
@@ -566,86 +552,62 @@ XPCWrappedNativeScope::UpdateWeakPointer
         }
 
         if (cur)
             prev = cur;
         cur = next;
     }
 }
 
-static PLDHashOperator
-WrappedNativeMarker(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                    uint32_t number_t, void* arg)
-{
-    ((Native2WrappedNativeMap::Entry*)hdr)->value->Mark();
-    return PL_DHASH_NEXT;
-}
-
-// We need to explicitly mark all the protos too because some protos may be
-// alive in the hashtable but not currently in use by any wrapper
-static PLDHashOperator
-WrappedNativeProtoMarker(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                         uint32_t number, void* arg)
-{
-    ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->Mark();
-    return PL_DHASH_NEXT;
-}
-
 // static
 void
 XPCWrappedNativeScope::MarkAllWrappedNativesAndProtos()
 {
     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
-        cur->mWrappedNativeMap->Enumerate(WrappedNativeMarker, nullptr);
-        cur->mWrappedNativeProtoMap->Enumerate(WrappedNativeProtoMarker, nullptr);
+        for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
+            auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
+            entry->value->Mark();
+        }
+        // We need to explicitly mark all the protos too because some protos may be
+        // alive in the hashtable but not currently in use by any wrapper
+        for (auto i = cur->mWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
+            auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get());
+            entry->value->Mark();
+        }
     }
 }
 
 #ifdef DEBUG
-static PLDHashOperator
-ASSERT_WrappedNativeSetNotMarked(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                                 uint32_t number, void* arg)
-{
-    ((Native2WrappedNativeMap::Entry*)hdr)->value->ASSERT_SetsNotMarked();
-    return PL_DHASH_NEXT;
-}
-
-static PLDHashOperator
-ASSERT_WrappedNativeProtoSetNotMarked(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                                      uint32_t number, void* arg)
-{
-    ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->ASSERT_SetNotMarked();
-    return PL_DHASH_NEXT;
-}
-
 // static
 void
 XPCWrappedNativeScope::ASSERT_NoInterfaceSetsAreMarked()
 {
     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
-        cur->mWrappedNativeMap->Enumerate(ASSERT_WrappedNativeSetNotMarked, nullptr);
-        cur->mWrappedNativeProtoMap->Enumerate(ASSERT_WrappedNativeProtoSetNotMarked, nullptr);
+        for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
+            auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
+            entry->value->ASSERT_SetsNotMarked();
+        }
+        for (auto i = cur->mWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
+            auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get());
+            entry->value->ASSERT_SetNotMarked();
+        }
     }
 }
 #endif
 
-static PLDHashOperator
-WrappedNativeTearoffSweeper(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                            uint32_t number, void* arg)
-{
-    ((Native2WrappedNativeMap::Entry*)hdr)->value->SweepTearOffs();
-    return PL_DHASH_NEXT;
-}
-
 // static
 void
 XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs()
 {
-    for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
-        cur->mWrappedNativeMap->Enumerate(WrappedNativeTearoffSweeper, nullptr);
+    for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
+        for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
+            auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
+            entry->value->SweepTearOffs();
+        }
+    }
 }
 
 // static
 void
 XPCWrappedNativeScope::KillDyingScopes()
 {
     XPCWrappedNativeScope* cur = gDyingScopes;
     while (cur) {
@@ -662,41 +624,16 @@ struct ShutdownData
 {
     ShutdownData()
         : wrapperCount(0),
           protoCount(0) {}
     int wrapperCount;
     int protoCount;
 };
 
-static PLDHashOperator
-WrappedNativeShutdownEnumerator(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                                uint32_t number, void* arg)
-{
-    ShutdownData* data = (ShutdownData*) arg;
-    XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
-
-    if (wrapper->IsValid()) {
-        wrapper->SystemIsBeingShutDown();
-        data->wrapperCount++;
-    }
-    return PL_DHASH_REMOVE;
-}
-
-static PLDHashOperator
-WrappedNativeProtoShutdownEnumerator(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                                     uint32_t number, void* arg)
-{
-    ShutdownData* data = (ShutdownData*) arg;
-    ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->
-        SystemIsBeingShutDown();
-    data->protoCount++;
-    return PL_DHASH_REMOVE;
-}
-
 //static
 void
 XPCWrappedNativeScope::SystemIsBeingShutDown()
 {
     int liveScopeCount = 0;
 
     ShutdownData data;
 
@@ -720,20 +657,31 @@ XPCWrappedNativeScope::SystemIsBeingShut
 
     for (cur = gDyingScopes; cur; cur = cur->mNext) {
         // Give the Components object a chance to try to clean up.
         if (cur->mComponents)
             cur->mComponents->SystemIsBeingShutDown();
 
         // Walk the protos first. Wrapper shutdown can leave dangling
         // proto pointers in the proto map.
-        cur->mWrappedNativeProtoMap->
-                Enumerate(WrappedNativeProtoShutdownEnumerator,  &data);
-        cur->mWrappedNativeMap->
-                Enumerate(WrappedNativeShutdownEnumerator,  &data);
+        for (auto i = cur->mWrappedNativeProtoMap->RemovingIter(); !i.Done(); i.Next()) {
+            auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get());
+            entry->value->SystemIsBeingShutDown();
+            data.protoCount++;
+            i.Remove();
+        }
+        for (auto i = cur->mWrappedNativeMap->RemovingIter(); !i.Done(); i.Next()) {
+            auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
+            XPCWrappedNative* wrapper = entry->value;
+            if (wrapper->IsValid()) {
+                wrapper->SystemIsBeingShutDown();
+                data.wrapperCount++;
+            }
+            i.Remove();
+        }
     }
 
     // Now it is safe to kill all the scopes.
     KillDyingScopes();
 }
 
 
 /***************************************************************************/
@@ -905,60 +853,49 @@ XPCWrappedNativeScope::DebugDumpAllScope
         XPC_LOG_ALWAYS(("gDyingScopes @ %x", gDyingScopes));
         if (depth)
             for (cur = gScopes; cur; cur = cur->mNext)
                 cur->DebugDump(depth);
     XPC_LOG_OUTDENT();
 #endif
 }
 
-#ifdef DEBUG
-static PLDHashOperator
-WrappedNativeMapDumpEnumerator(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                               uint32_t number, void* arg)
-{
-    ((Native2WrappedNativeMap::Entry*)hdr)->value->DebugDump(*(int16_t*)arg);
-    return PL_DHASH_NEXT;
-}
-static PLDHashOperator
-WrappedNativeProtoMapDumpEnumerator(PLDHashTable* table, PLDHashEntryHdr* hdr,
-                                    uint32_t number, void* arg)
-{
-    ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value->DebugDump(*(int16_t*)arg);
-    return PL_DHASH_NEXT;
-}
-#endif
-
 void
 XPCWrappedNativeScope::DebugDump(int16_t depth)
 {
 #ifdef DEBUG
     depth-- ;
     XPC_LOG_ALWAYS(("XPCWrappedNativeScope @ %x", this));
     XPC_LOG_INDENT();
         XPC_LOG_ALWAYS(("mNext @ %x", mNext));
         XPC_LOG_ALWAYS(("mComponents @ %x", mComponents.get()));
         XPC_LOG_ALWAYS(("mGlobalJSObject @ %x", mGlobalJSObject.get()));
 
         XPC_LOG_ALWAYS(("mWrappedNativeMap @ %x with %d wrappers(s)",
                         mWrappedNativeMap, mWrappedNativeMap->Count()));
         // iterate contexts...
         if (depth && mWrappedNativeMap->Count()) {
             XPC_LOG_INDENT();
-            mWrappedNativeMap->Enumerate(WrappedNativeMapDumpEnumerator, &depth);
+            for (auto i = mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
+                auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
+                entry->value->DebugDump(depth);
+            }
             XPC_LOG_OUTDENT();
         }
 
         XPC_LOG_ALWAYS(("mWrappedNativeProtoMap @ %x with %d protos(s)",
                         mWrappedNativeProtoMap,
                         mWrappedNativeProtoMap->Count()));
         // iterate contexts...
         if (depth && mWrappedNativeProtoMap->Count()) {
             XPC_LOG_INDENT();
-            mWrappedNativeProtoMap->Enumerate(WrappedNativeProtoMapDumpEnumerator, &depth);
+            for (auto i = mWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
+                auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get());
+                entry->value->DebugDump(depth);
+            }
             XPC_LOG_OUTDENT();
         }
     XPC_LOG_OUTDENT();
 #endif
 }
 
 void
 XPCWrappedNativeScope::AddSizeOfAllScopesIncludingThis(ScopeSizeInfo* scopeSizeInfo)