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
--- 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