forked from mirrors/gecko-dev
		
	 c2306345d5
			
		
	
	
		c2306345d5
		
	
	
	
	
		
			
			This patch removes checking of all the callback calls in memory reporter CollectReport() functions, because it's not useful. The patch also does some associated clean-up. - Replaces some uses of nsIMemoryReporterCallback with the preferred nsIHandleReportCallback typedef. - Replaces aCallback/aCb/aClosure with aHandleRepor/aData for CollectReports() parameter names, for consistency. - Adds MOZ_MUST_USE/[must_use] in a few places in nsIMemoryReporter.idl. - Uses the MOZ_COLLECT_REPORT macro in all suitable places. Overall the patch reduces code size by ~300 lines and reduces the size of libxul by about 37 KiB on my Linux64 builds. --HG-- extra : rebase_source : e94323614bd10463a0c5134a7276238a7ca1cf23
		
			
				
	
	
		
			436 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			436 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* 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 "nsScriptNameSpaceManager.h"
 | |
| #include "nsCOMPtr.h"
 | |
| #include "nsIComponentManager.h"
 | |
| #include "nsIComponentRegistrar.h"
 | |
| #include "nsICategoryManager.h"
 | |
| #include "nsIServiceManager.h"
 | |
| #include "nsXPCOM.h"
 | |
| #include "nsISupportsPrimitives.h"
 | |
| #include "nsIScriptNameSpaceManager.h"
 | |
| #include "nsIScriptContext.h"
 | |
| #include "nsIInterfaceInfoManager.h"
 | |
| #include "nsIInterfaceInfo.h"
 | |
| #include "xptinfo.h"
 | |
| #include "nsXPIDLString.h"
 | |
| #include "nsReadableUtils.h"
 | |
| #include "nsHashKeys.h"
 | |
| #include "nsDOMClassInfo.h"
 | |
| #include "nsCRT.h"
 | |
| #include "nsIObserverService.h"
 | |
| #include "nsISimpleEnumerator.h"
 | |
| #include "mozilla/dom/BindingUtils.h"
 | |
| #include "mozilla/dom/WebIDLGlobalNameHash.h"
 | |
| #include "mozilla/MemoryReporting.h"
 | |
| #include "mozilla/Preferences.h"
 | |
| #include "mozilla/Services.h"
 | |
| 
 | |
| #define NS_INTERFACE_PREFIX "nsI"
 | |
| #define NS_DOM_INTERFACE_PREFIX "nsIDOM"
 | |
| 
 | |
| using namespace mozilla;
 | |
| using namespace mozilla::dom;
 | |
| 
 | |
| static PLDHashNumber
 | |
| GlobalNameHashHashKey(const void *key)
 | |
| {
 | |
|   const nsAString *str = static_cast<const nsAString *>(key);
 | |
|   return HashString(*str);
 | |
| }
 | |
| 
 | |
| static bool
 | |
| GlobalNameHashMatchEntry(const PLDHashEntryHdr *entry, const void *key)
 | |
| {
 | |
|   const GlobalNameMapEntry *e =
 | |
|     static_cast<const GlobalNameMapEntry *>(entry);
 | |
|   const nsAString *str = static_cast<const nsAString *>(key);
 | |
| 
 | |
|   return str->Equals(e->mKey);
 | |
| }
 | |
| 
 | |
| static void
 | |
| GlobalNameHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
 | |
| {
 | |
|   GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
 | |
| 
 | |
|   // An entry is being cleared, let the key (nsString) do its own
 | |
|   // cleanup.
 | |
|   e->mKey.~nsString();
 | |
| 
 | |
|   // This will set e->mGlobalName.mType to
 | |
|   // nsGlobalNameStruct::eTypeNotInitialized
 | |
|   memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
 | |
| }
 | |
| 
 | |
| static void
 | |
| GlobalNameHashInitEntry(PLDHashEntryHdr *entry, const void *key)
 | |
| {
 | |
|   GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
 | |
|   const nsAString *keyStr = static_cast<const nsAString *>(key);
 | |
| 
 | |
|   // Initialize the key in the entry with placement new
 | |
|   new (&e->mKey) nsString(*keyStr);
 | |
| 
 | |
|   // This will set e->mGlobalName.mType to
 | |
|   // nsGlobalNameStruct::eTypeNotInitialized
 | |
|   memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
 | |
| }
 | |
| 
 | |
| NS_IMPL_ISUPPORTS(
 | |
|   nsScriptNameSpaceManager,
 | |
|   nsIObserver,
 | |
|   nsISupportsWeakReference,
 | |
|   nsIMemoryReporter)
 | |
| 
 | |
| static const PLDHashTableOps hash_table_ops =
 | |
| {
 | |
|   GlobalNameHashHashKey,
 | |
|   GlobalNameHashMatchEntry,
 | |
|   PLDHashTable::MoveEntryStub,
 | |
|   GlobalNameHashClearEntry,
 | |
|   GlobalNameHashInitEntry
 | |
| };
 | |
| 
 | |
| #define GLOBALNAME_HASHTABLE_INITIAL_LENGTH          32
 | |
| 
 | |
| nsScriptNameSpaceManager::nsScriptNameSpaceManager()
 | |
|   : mGlobalNames(&hash_table_ops, sizeof(GlobalNameMapEntry),
 | |
|                  GLOBALNAME_HASHTABLE_INITIAL_LENGTH)
 | |
| {
 | |
|   MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
 | |
| }
 | |
| 
 | |
| nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
 | |
| {
 | |
|   UnregisterWeakMemoryReporter(this);
 | |
|   MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
 | |
| }
 | |
| 
 | |
| nsGlobalNameStruct *
 | |
| nsScriptNameSpaceManager::AddToHash(const char *aKey,
 | |
|                                     const char16_t **aClassName)
 | |
| {
 | |
|   NS_ConvertASCIItoUTF16 key(aKey);
 | |
|   auto entry = static_cast<GlobalNameMapEntry*>(mGlobalNames.Add(&key, fallible));
 | |
|   if (!entry) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   WebIDLGlobalNameHash::Remove(aKey, key.Length());
 | |
| 
 | |
|   if (aClassName) {
 | |
|     *aClassName = entry->mKey.get();
 | |
|   }
 | |
| 
 | |
|   return &entry->mGlobalName;
 | |
| }
 | |
| 
 | |
| void
 | |
| nsScriptNameSpaceManager::RemoveFromHash(const nsAString *aKey)
 | |
| {
 | |
|   mGlobalNames.Remove(aKey);
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsScriptNameSpaceManager::FillHash(nsICategoryManager *aCategoryManager,
 | |
|                                    const char *aCategory)
 | |
| {
 | |
|   nsCOMPtr<nsISimpleEnumerator> e;
 | |
|   nsresult rv = aCategoryManager->EnumerateCategory(aCategory,
 | |
|                                                     getter_AddRefs(e));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   nsCOMPtr<nsISupports> entry;
 | |
|   while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) {
 | |
|     rv = AddCategoryEntryToHash(aCategoryManager, aCategory, entry);
 | |
|     if (NS_FAILED(rv)) {
 | |
|       return rv;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| nsresult
 | |
| nsScriptNameSpaceManager::Init()
 | |
| {
 | |
|   RegisterWeakMemoryReporter(this);
 | |
| 
 | |
|   nsresult rv = NS_OK;
 | |
| 
 | |
|   nsCOMPtr<nsICategoryManager> cm =
 | |
|     do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   rv = FillHash(cm, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   rv = FillHash(cm, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   rv = FillHash(cm, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   // Initial filling of the has table has been done.
 | |
|   // Now, listen for changes.
 | |
|   nsCOMPtr<nsIObserverService> serv = 
 | |
|     mozilla::services::GetObserverService();
 | |
| 
 | |
|   if (serv) {
 | |
|     serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, true);
 | |
|     serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID, true);
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| const nsGlobalNameStruct*
 | |
| nsScriptNameSpaceManager::LookupName(const nsAString& aName,
 | |
|                                      const char16_t **aClassName)
 | |
| {
 | |
|   auto entry = static_cast<GlobalNameMapEntry*>(mGlobalNames.Search(&aName));
 | |
| 
 | |
|   if (entry) {
 | |
|     if (aClassName) {
 | |
|       *aClassName = entry->mKey.get();
 | |
|     }
 | |
|     return &entry->mGlobalName;
 | |
|   }
 | |
| 
 | |
|   if (aClassName) {
 | |
|     *aClassName = nullptr;
 | |
|   }
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
 | |
|                                             int32_t aDOMClassInfoID,
 | |
|                                             bool aPrivileged,
 | |
|                                             bool aXBLAllowed,
 | |
|                                             const char16_t **aResult)
 | |
| {
 | |
|   if (!nsCRT::IsAscii(aClassName)) {
 | |
|     NS_ERROR("Trying to register a non-ASCII class name");
 | |
|     return NS_OK;
 | |
|   }
 | |
|   nsGlobalNameStruct *s = AddToHash(aClassName, aResult);
 | |
|   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|   if (s->mType == nsGlobalNameStruct::eTypeClassConstructor) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // If a external constructor is already defined with aClassName we
 | |
|   // won't overwrite it.
 | |
| 
 | |
|   if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized,
 | |
|                "Whaaa, JS environment name clash!");
 | |
| 
 | |
|   s->mType = nsGlobalNameStruct::eTypeClassConstructor;
 | |
|   s->mDOMClassInfoID = aDOMClassInfoID;
 | |
|   s->mChromeOnly = aPrivileged;
 | |
|   s->mAllowXBL = aXBLAllowed;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName,
 | |
|                                              const nsIID *aConstructorProtoIID,
 | |
|                                              bool *aFoundOld)
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aConstructorProtoIID);
 | |
| 
 | |
|   *aFoundOld = false;
 | |
| 
 | |
|   nsGlobalNameStruct *s = AddToHash(aClassName);
 | |
|   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|   if (s->mType != nsGlobalNameStruct::eTypeNotInitialized) {
 | |
|     *aFoundOld = true;
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   s->mType = nsGlobalNameStruct::eTypeClassProto;
 | |
|   s->mIID = *aConstructorProtoIID;
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategoryManager,
 | |
|                                                    const char* aCategory,
 | |
|                                                    nsISupports* aEntry,
 | |
|                                                    bool aRemove)
 | |
| {
 | |
|   MOZ_ASSERT(aCategoryManager);
 | |
|   // Get the type from the category name.
 | |
|   // NOTE: we could have passed the type in FillHash() and guessed it in
 | |
|   // Observe() but this way, we have only one place to update and this is
 | |
|   // not performance sensitive.
 | |
|   nsGlobalNameStruct::nametype type;
 | |
|   if (strcmp(aCategory, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY) == 0) {
 | |
|     type = nsGlobalNameStruct::eTypeExternalConstructor;
 | |
|   } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY) == 0 ||
 | |
|              strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0) {
 | |
|     type = nsGlobalNameStruct::eTypeProperty;
 | |
|   } else {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsISupportsCString> strWrapper = do_QueryInterface(aEntry);
 | |
| 
 | |
|   if (!strWrapper) {
 | |
|     NS_WARNING("Category entry not an nsISupportsCString!");
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsAutoCString categoryEntry;
 | |
|   nsresult rv = strWrapper->GetData(categoryEntry);
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   // We need to handle removal before calling GetCategoryEntry
 | |
|   // because the category entry is already removed before we are
 | |
|   // notified.
 | |
|   if (aRemove) {
 | |
|     NS_ConvertASCIItoUTF16 entry(categoryEntry);
 | |
|     const nsGlobalNameStruct *s = LookupName(entry);
 | |
|     // Verify mType so that this API doesn't remove names
 | |
|     // registered by others.
 | |
|     if (!s || s->mType != type) {
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     RemoveFromHash(&entry);
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   nsXPIDLCString contractId;
 | |
|   rv = aCategoryManager->GetCategoryEntry(aCategory, categoryEntry.get(),
 | |
|                                           getter_Copies(contractId));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   nsCOMPtr<nsIComponentRegistrar> registrar;
 | |
|   rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
 | |
|   NS_ENSURE_SUCCESS(rv, rv);
 | |
| 
 | |
|   nsCID *cidPtr;
 | |
|   rv = registrar->ContractIDToCID(contractId, &cidPtr);
 | |
| 
 | |
|   if (NS_FAILED(rv)) {
 | |
|     NS_WARNING("Bad contract id registed with the script namespace manager");
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // Copy CID onto the stack, so we can free it right away and avoid having
 | |
|   // to add cleanup code at every exit point from this function.
 | |
|   nsCID cid = *cidPtr;
 | |
|   free(cidPtr);
 | |
| 
 | |
|   nsGlobalNameStruct *s = AddToHash(categoryEntry.get());
 | |
|   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 | |
| 
 | |
|   if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
 | |
|     s->mType = type;
 | |
|     s->mCID = cid;
 | |
|     s->mChromeOnly =
 | |
|       strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0;
 | |
|   } else {
 | |
|     NS_WARNING("Global script name not overwritten!");
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsScriptNameSpaceManager::AddCategoryEntryToHash(nsICategoryManager* aCategoryManager,
 | |
|                                                  const char* aCategory,
 | |
|                                                  nsISupports* aEntry)
 | |
| {
 | |
|   return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry,
 | |
|                                   /* aRemove = */ false);
 | |
| }
 | |
| 
 | |
| nsresult
 | |
| nsScriptNameSpaceManager::RemoveCategoryEntryFromHash(nsICategoryManager* aCategoryManager,
 | |
|                                                       const char* aCategory,
 | |
|                                                       nsISupports* aEntry)
 | |
| {
 | |
|   return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry,
 | |
|                                   /* aRemove = */ true);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsScriptNameSpaceManager::Observe(nsISupports* aSubject, const char* aTopic,
 | |
|                                   const char16_t* aData)
 | |
| {
 | |
|   if (!aData) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID)) {
 | |
|     nsCOMPtr<nsICategoryManager> cm =
 | |
|       do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
 | |
|     if (!cm) {
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     return AddCategoryEntryToHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
 | |
|                                   aSubject);
 | |
|   } else if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID)) {
 | |
|     nsCOMPtr<nsICategoryManager> cm =
 | |
|       do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
 | |
|     if (!cm) {
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     return RemoveCategoryEntryFromHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
 | |
|                                        aSubject);
 | |
|   }
 | |
| 
 | |
|   // TODO: we could observe NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID
 | |
|   // but we are safe without it. See bug 600460.
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| MOZ_DEFINE_MALLOC_SIZE_OF(ScriptNameSpaceManagerMallocSizeOf)
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| nsScriptNameSpaceManager::CollectReports(
 | |
|   nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
 | |
| {
 | |
|   MOZ_COLLECT_REPORT(
 | |
|     "explicit/script-namespace-manager", KIND_HEAP, UNITS_BYTES,
 | |
|     SizeOfIncludingThis(ScriptNameSpaceManagerMallocSizeOf),
 | |
|     "Memory used for the script namespace manager.");
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| nsScriptNameSpaceManager::SizeOfIncludingThis(
 | |
|     mozilla::MallocSizeOf aMallocSizeOf) const
 | |
| {
 | |
|   size_t n = 0;
 | |
| 
 | |
|   n += mGlobalNames.ShallowSizeOfExcludingThis(aMallocSizeOf);
 | |
|   for (auto iter = mGlobalNames.ConstIter(); !iter.Done(); iter.Next()) {
 | |
|     auto entry = static_cast<GlobalNameMapEntry*>(iter.Get());
 | |
|     n += entry->SizeOfExcludingThis(aMallocSizeOf);
 | |
|   }
 | |
| 
 | |
|   return n;
 | |
| }
 |