Bug 1477579: Part 2 - Use nsID* rather than nsID for mFactories hash keys. r?froydnj draft
authorKris Maglione <maglione.k@gmail.com>
Sat, 21 Jul 2018 19:09:25 -0700
changeset 821292 055b89d30b88312c0f50e771b46b35c1774ccc8f
parent 821291 0e901ce6af2a825f56ff714bc3340b15ac612fff
child 821293 c7af0b00fe92fadfb47d161588fd7f307db74140
push id117051
push usermaglione.k@gmail.com
push dateSun, 22 Jul 2018 18:01:56 +0000
reviewersfroydnj
bugs1477579
milestone63.0a1
Bug 1477579: Part 2 - Use nsID* rather than nsID for mFactories hash keys. r?froydnj Our factory registrations already require that we store nsID pointers, which we generally handle by using pointers to static data, or arena allocating a copy of a dynamic ID. Since we already have viable pointers to these IDs, there's no reason to store an entire second copy for our hash key. We can use the pointer, instead, which saves 16 bytes per entry. MozReview-Commit-ID: 6MgKrXRSHv4
xpcom/components/nsComponentManager.cpp
xpcom/components/nsComponentManager.h
xpcom/ds/nsHashKeys.h
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -567,17 +567,17 @@ nsComponentManagerImpl::RegisterCIDEntry
     KnownModule* aModule)
 {
   mLock.AssertCurrentThreadOwns();
 
   if (!ProcessSelectorMatches(aEntry->processSelector)) {
     return;
   }
 
-  if (auto entry = mFactories.LookupForAdd(*aEntry->cid)) {
+  if (auto entry = mFactories.LookupForAdd(aEntry->cid)) {
     nsFactoryEntry* f = entry.Data();
     NS_WARNING("Re-registering a CID?");
 
     char idstr[NSID_LENGTH];
     aEntry->cid->ToProvidedString(idstr);
 
     nsCString existing;
     if (f->mModule) {
@@ -600,17 +600,17 @@ nsComponentManagerImpl::RegisterContract
     const mozilla::Module::ContractIDEntry* aEntry)
 {
   mLock.AssertCurrentThreadOwns();
 
   if (!ProcessSelectorMatches(aEntry->processSelector)) {
     return;
   }
 
-  nsFactoryEntry* f = mFactories.Get(*aEntry->cid);
+  nsFactoryEntry* f = mFactories.Get(aEntry->cid);
   if (!f) {
     NS_WARNING("No CID found when attempting to map contract ID");
 
     char idstr[NSID_LENGTH];
     aEntry->cid->ToProvidedString(idstr);
 
     SafeMutexAutoUnlock unlock(mLock);
     LogMessage("Could not map contract ID '%s' to CID %s because no implementation of the CID is registered.",
@@ -694,19 +694,18 @@ nsComponentManagerImpl::ManifestComponen
   }
 
   // Precompute the hash/file data outside of the lock
   FileLocation fl(aCx.mFile, file);
   nsCString hash;
   fl.GetURIString(hash);
 
   MutexLock lock(mLock);
-  auto entry = mFactories.LookupForAdd(cid);
-  if (entry) {
-    nsFactoryEntry* f = entry.Data();
+  nsFactoryEntry* f = mFactories.Get(&cid);
+  if (f) {
     char idstr[NSID_LENGTH];
     cid.ToProvidedString(idstr);
 
     nsCString existing;
     if (f->mModule) {
       existing = f->mModule->Description();
     } else {
       existing = "<unknown module>";
@@ -732,17 +731,17 @@ nsComponentManagerImpl::ManifestComponen
   void* place = mArena.Allocate(sizeof(nsCID));
   nsID* permanentCID = static_cast<nsID*>(place);
   *permanentCID = cid;
 
   place = mArena.Allocate(sizeof(mozilla::Module::CIDEntry));
   auto* e = new (KnownNotNull, place) mozilla::Module::CIDEntry();
   e->cid = permanentCID;
 
-  entry.OrInsert([e, km] () { return new nsFactoryEntry(e, km); });
+  mFactories.Put(permanentCID, new nsFactoryEntry(e, km));
 }
 
 void
 nsComponentManagerImpl::ManifestContract(ManifestProcessingContext& aCx,
                                          int aLineNo, char* const* aArgv)
 {
   mLock.AssertNotCurrentThreadOwns();
 
@@ -752,17 +751,17 @@ nsComponentManagerImpl::ManifestContract
   nsID cid;
   if (!cid.Parse(id)) {
     LogMessageWithContext(aCx.mFile, aLineNo,
                           "Malformed CID: '%s'.", id);
     return;
   }
 
   MutexLock lock(mLock);
-  nsFactoryEntry* f = mFactories.Get(cid);
+  nsFactoryEntry* f = mFactories.Get(&cid);
   if (!f) {
     lock.Unlock();
     LogMessageWithContext(aCx.mFile, aLineNo,
                           "Could not map contract ID '%s' to CID %s because no implementation of the CID is registered.",
                           contract, id);
     return;
   }
 
@@ -919,17 +918,17 @@ nsComponentManagerImpl::GetFactoryEntry(
   return mContractIDs.Get(nsDependentCString(aContractID, aContractIDLen));
 }
 
 
 nsFactoryEntry*
 nsComponentManagerImpl::GetFactoryEntry(const nsCID& aClass)
 {
   SafeMutexAutoLock lock(mLock);
-  return mFactories.Get(aClass);
+  return mFactories.Get(&aClass);
 }
 
 already_AddRefed<nsIFactory>
 nsComponentManagerImpl::FindFactory(const nsCID& aClass)
 {
   nsFactoryEntry* e = GetFactoryEntry(aClass);
   if (!e) {
     return nullptr;
@@ -1248,17 +1247,17 @@ nsComponentManagerImpl::GetService(const
     return NS_ERROR_UNEXPECTED;
   }
 
   // `service` must be released after the lock is released, so it must be
   // declared before the lock in this C++ block.
   nsCOMPtr<nsISupports> service;
   MutexLock lock(mLock);
 
-  nsFactoryEntry* entry = mFactories.Get(aClass);
+  nsFactoryEntry* entry = mFactories.Get(&aClass);
   if (!entry) {
     return NS_ERROR_FACTORY_NOT_REGISTERED;
   }
 
   if (entry->mServiceObject) {
     lock.Unlock();
     return entry->mServiceObject->QueryInterface(aIID, aResult);
   }
@@ -1364,17 +1363,17 @@ nsComponentManagerImpl::IsServiceInstant
     return NS_ERROR_UNEXPECTED;
   }
 
   nsresult rv = NS_OK;
   nsFactoryEntry* entry;
 
   {
     SafeMutexAutoLock lock(mLock);
-    entry = mFactories.Get(aClass);
+    entry = mFactories.Get(&aClass);
   }
 
   if (entry && entry->mServiceObject) {
     nsCOMPtr<nsISupports> service;
     rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
     *aResult = (service != nullptr);
   } else {
     *aResult = false;
@@ -1569,29 +1568,29 @@ nsComponentManagerImpl::RegisterFactory(
   if (!aFactory) {
     // If a null factory is passed in, this call just wants to reset
     // the contract ID to point to an existing CID entry.
     if (!aContractID) {
       return NS_ERROR_INVALID_ARG;
     }
 
     SafeMutexAutoLock lock(mLock);
-    nsFactoryEntry* oldf = mFactories.Get(aClass);
+    nsFactoryEntry* oldf = mFactories.Get(&aClass);
     if (!oldf) {
       return NS_ERROR_FACTORY_NOT_REGISTERED;
     }
 
     mContractIDs.Put(nsDependentCString(aContractID), oldf);
     return NS_OK;
   }
 
   nsAutoPtr<nsFactoryEntry> f(new nsFactoryEntry(aClass, aFactory));
 
   SafeMutexAutoLock lock(mLock);
-  if (auto entry = mFactories.LookupForAdd(aClass)) {
+  if (auto entry = mFactories.LookupForAdd(f->mCIDEntry->cid)) {
     return NS_ERROR_FACTORY_EXISTS;
   } else {
     if (aContractID) {
       mContractIDs.Put(nsDependentCString(aContractID), f);
     }
     entry.OrInsert([&f] () { return f.forget(); });
   }
 
@@ -1604,17 +1603,17 @@ nsComponentManagerImpl::UnregisterFactor
 {
   // Don't release the dying factory or service object until releasing
   // the component manager monitor.
   nsCOMPtr<nsIFactory> dyingFactory;
   nsCOMPtr<nsISupports> dyingServiceObject;
 
   {
     SafeMutexAutoLock lock(mLock);
-    auto entry = mFactories.Lookup(aClass);
+    auto entry = mFactories.Lookup(&aClass);
     nsFactoryEntry* f = entry ? entry.Data() : nullptr;
     if (!f || f->mFactory != aFactory) {
       return NS_ERROR_FACTORY_NOT_REGISTERED;
     }
 
     entry.Remove();
 
     // This might leave a stale contractid -> factory mapping in
@@ -1692,19 +1691,19 @@ nsComponentManagerImpl::IsContractIDRegi
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator** aEnumerator)
 {
   nsCOMArray<nsISupports> array;
   for (auto iter = mFactories.Iter(); !iter.Done(); iter.Next()) {
-    const nsID& id = iter.Key();
+    const nsID* id = iter.Key();
     nsCOMPtr<nsISupportsID> wrapper = new nsSupportsID();
-    wrapper->SetData(&id);
+    wrapper->SetData(id);
     array.AppendObject(wrapper);
   }
   return NS_NewArrayEnumerator(aEnumerator, array);
 }
 
 NS_IMETHODIMP
 nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator** aEnumerator)
 {
--- a/xpcom/components/nsComponentManager.h
+++ b/xpcom/components/nsComponentManager.h
@@ -162,17 +162,17 @@ public:
                                            uint32_t aContractIDLen);
 
   already_AddRefed<nsIFactory> LoadFactory(nsFactoryEntry* aEntry);
 
   nsFactoryEntry* GetFactoryEntry(const char* aContractID,
                                   uint32_t aContractIDLen);
   nsFactoryEntry* GetFactoryEntry(const nsCID& aClass);
 
-  nsDataHashtable<nsIDHashKey, nsFactoryEntry*> mFactories;
+  nsDataHashtable<nsIDPointerHashKey, nsFactoryEntry*> mFactories;
   nsDataHashtable<nsCStringHashKey, nsFactoryEntry*> mContractIDs;
 
   SafeMutex mLock;
 
   static void InitializeStaticModules();
   static void InitializeModuleLocations();
 
   struct ComponentLocation
--- a/xpcom/ds/nsHashKeys.h
+++ b/xpcom/ds/nsHashKeys.h
@@ -469,16 +469,47 @@ public:
 
   enum { ALLOW_MEMMOVE = true };
 
 private:
   const nsID mID;
 };
 
 /**
+ * hashkey wrapper using nsID* KeyType
+ *
+ * @see nsTHashtable::EntryType for specification
+ */
+class nsIDPointerHashKey : public PLDHashEntryHdr
+{
+public:
+  typedef const nsID* KeyType;
+  typedef const nsID* KeyTypePointer;
+
+  explicit nsIDPointerHashKey(const nsID* aInID) : mID(aInID) {}
+  nsIDPointerHashKey(const nsIDPointerHashKey& aToCopy) : mID(aToCopy.mID) {}
+  ~nsIDPointerHashKey() {}
+
+  KeyType GetKey() const { return mID; }
+  bool KeyEquals(KeyTypePointer aKey) const { return aKey->Equals(*mID); }
+
+  static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
+  static PLDHashNumber HashKey(KeyTypePointer aKey)
+  {
+    // Hash the nsID object's raw bytes.
+    return mozilla::HashBytes(aKey, sizeof(*aKey));
+  }
+
+  enum { ALLOW_MEMMOVE = true };
+
+private:
+  const nsID* mID;
+};
+
+/**
  * hashkey wrapper for "dependent" const char*; this class does not "own"
  * its string pointer.
  *
  * This class must only be used if the strings have a lifetime longer than
  * the hashtable they occupy. This normally occurs only for static
  * strings or strings that have been arena-allocated.
  *
  * @see nsTHashtable::EntryType for specification