LCOV - code coverage report
Current view: top level - dom/base - nsScriptNameSpaceManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 120 176 68.2 %
Date: 2017-07-14 16:53:18 Functions: 16 24 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsScriptNameSpaceManager.h"
       8             : #include "nsCOMPtr.h"
       9             : #include "nsIComponentManager.h"
      10             : #include "nsIComponentRegistrar.h"
      11             : #include "nsICategoryManager.h"
      12             : #include "nsIServiceManager.h"
      13             : #include "nsXPCOM.h"
      14             : #include "nsISupportsPrimitives.h"
      15             : #include "nsIScriptNameSpaceManager.h"
      16             : #include "nsIScriptContext.h"
      17             : #include "nsIInterfaceInfoManager.h"
      18             : #include "nsIInterfaceInfo.h"
      19             : #include "xptinfo.h"
      20             : #include "nsXPIDLString.h"
      21             : #include "nsReadableUtils.h"
      22             : #include "nsHashKeys.h"
      23             : #include "nsDOMClassInfo.h"
      24             : #include "nsCRT.h"
      25             : #include "nsIObserverService.h"
      26             : #include "nsISimpleEnumerator.h"
      27             : #include "mozilla/dom/BindingUtils.h"
      28             : #include "mozilla/dom/WebIDLGlobalNameHash.h"
      29             : #include "mozilla/MemoryReporting.h"
      30             : #include "mozilla/Preferences.h"
      31             : #include "mozilla/Services.h"
      32             : 
      33             : #define NS_INTERFACE_PREFIX "nsI"
      34             : #define NS_DOM_INTERFACE_PREFIX "nsIDOM"
      35             : 
      36             : using namespace mozilla;
      37             : using namespace mozilla::dom;
      38             : 
      39             : static PLDHashNumber
      40        3195 : GlobalNameHashHashKey(const void *key)
      41             : {
      42        3195 :   const nsAString *str = static_cast<const nsAString *>(key);
      43        3195 :   return HashString(*str);
      44             : }
      45             : 
      46             : static bool
      47          32 : GlobalNameHashMatchEntry(const PLDHashEntryHdr *entry, const void *key)
      48             : {
      49             :   const GlobalNameMapEntry *e =
      50          32 :     static_cast<const GlobalNameMapEntry *>(entry);
      51          32 :   const nsAString *str = static_cast<const nsAString *>(key);
      52             : 
      53          32 :   return str->Equals(e->mKey);
      54             : }
      55             : 
      56             : static void
      57           0 : GlobalNameHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
      58             : {
      59           0 :   GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
      60             : 
      61             :   // An entry is being cleared, let the key (nsString) do its own
      62             :   // cleanup.
      63           0 :   e->mKey.~nsString();
      64             : 
      65             :   // This will set e->mGlobalName.mType to
      66             :   // nsGlobalNameStruct::eTypeNotInitialized
      67           0 :   memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
      68           0 : }
      69             : 
      70             : static void
      71          33 : GlobalNameHashInitEntry(PLDHashEntryHdr *entry, const void *key)
      72             : {
      73          33 :   GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
      74          33 :   const nsAString *keyStr = static_cast<const nsAString *>(key);
      75             : 
      76             :   // Initialize the key in the entry with placement new
      77          33 :   new (&e->mKey) nsString(*keyStr);
      78             : 
      79             :   // This will set e->mGlobalName.mType to
      80             :   // nsGlobalNameStruct::eTypeNotInitialized
      81          33 :   memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
      82          33 : }
      83             : 
      84          62 : NS_IMPL_ISUPPORTS(
      85             :   nsScriptNameSpaceManager,
      86             :   nsIObserver,
      87             :   nsISupportsWeakReference,
      88             :   nsIMemoryReporter)
      89             : 
      90             : static const PLDHashTableOps hash_table_ops =
      91             : {
      92             :   GlobalNameHashHashKey,
      93             :   GlobalNameHashMatchEntry,
      94             :   PLDHashTable::MoveEntryStub,
      95             :   GlobalNameHashClearEntry,
      96             :   GlobalNameHashInitEntry
      97             : };
      98             : 
      99             : #define GLOBALNAME_HASHTABLE_INITIAL_LENGTH          32
     100             : 
     101           3 : nsScriptNameSpaceManager::nsScriptNameSpaceManager()
     102             :   : mGlobalNames(&hash_table_ops, sizeof(GlobalNameMapEntry),
     103           3 :                  GLOBALNAME_HASHTABLE_INITIAL_LENGTH)
     104             : {
     105           3 : }
     106             : 
     107           0 : nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
     108             : {
     109           0 :   UnregisterWeakMemoryReporter(this);
     110           0 : }
     111             : 
     112             : nsGlobalNameStruct *
     113          63 : nsScriptNameSpaceManager::AddToHash(const char *aKey,
     114             :                                     const char16_t **aClassName)
     115             : {
     116         126 :   NS_ConvertASCIItoUTF16 key(aKey);
     117          63 :   auto entry = static_cast<GlobalNameMapEntry*>(mGlobalNames.Add(&key, fallible));
     118          63 :   if (!entry) {
     119           0 :     return nullptr;
     120             :   }
     121             : 
     122          63 :   WebIDLGlobalNameHash::Remove(aKey, key.Length());
     123             : 
     124          63 :   if (aClassName) {
     125          30 :     *aClassName = entry->mKey.get();
     126             :   }
     127             : 
     128          63 :   return &entry->mGlobalName;
     129             : }
     130             : 
     131             : void
     132           0 : nsScriptNameSpaceManager::RemoveFromHash(const nsAString *aKey)
     133             : {
     134           0 :   mGlobalNames.Remove(aKey);
     135           0 : }
     136             : 
     137             : nsresult
     138           9 : nsScriptNameSpaceManager::FillHash(nsICategoryManager *aCategoryManager,
     139             :                                    const char *aCategory)
     140             : {
     141          18 :   nsCOMPtr<nsISimpleEnumerator> e;
     142           9 :   nsresult rv = aCategoryManager->EnumerateCategory(aCategory,
     143          18 :                                                     getter_AddRefs(e));
     144           9 :   NS_ENSURE_SUCCESS(rv, rv);
     145             : 
     146          18 :   nsCOMPtr<nsISupports> entry;
     147          15 :   while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) {
     148           3 :     rv = AddCategoryEntryToHash(aCategoryManager, aCategory, entry);
     149           3 :     if (NS_FAILED(rv)) {
     150           0 :       return rv;
     151             :     }
     152             :   }
     153             : 
     154           9 :   return NS_OK;
     155             : }
     156             : 
     157             : 
     158             : nsresult
     159           3 : nsScriptNameSpaceManager::Init()
     160             : {
     161           3 :   RegisterWeakMemoryReporter(this);
     162             : 
     163           3 :   nsresult rv = NS_OK;
     164             : 
     165             :   nsCOMPtr<nsICategoryManager> cm =
     166           6 :     do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
     167           3 :   NS_ENSURE_SUCCESS(rv, rv);
     168             : 
     169           3 :   rv = FillHash(cm, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY);
     170           3 :   NS_ENSURE_SUCCESS(rv, rv);
     171             : 
     172           3 :   rv = FillHash(cm, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY);
     173           3 :   NS_ENSURE_SUCCESS(rv, rv);
     174             : 
     175           3 :   rv = FillHash(cm, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY);
     176           3 :   NS_ENSURE_SUCCESS(rv, rv);
     177             : 
     178             :   // Initial filling of the has table has been done.
     179             :   // Now, listen for changes.
     180             :   nsCOMPtr<nsIObserverService> serv =
     181           6 :     mozilla::services::GetObserverService();
     182             : 
     183           3 :   if (serv) {
     184           3 :     serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, true);
     185           3 :     serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID, true);
     186             :   }
     187             : 
     188           3 :   return NS_OK;
     189             : }
     190             : 
     191             : const nsGlobalNameStruct*
     192        3132 : nsScriptNameSpaceManager::LookupName(const nsAString& aName,
     193             :                                      const char16_t **aClassName)
     194             : {
     195        3132 :   auto entry = static_cast<GlobalNameMapEntry*>(mGlobalNames.Search(&aName));
     196             : 
     197        3132 :   if (entry) {
     198           2 :     if (aClassName) {
     199           0 :       *aClassName = entry->mKey.get();
     200             :     }
     201           2 :     return &entry->mGlobalName;
     202             :   }
     203             : 
     204        3130 :   if (aClassName) {
     205        3130 :     *aClassName = nullptr;
     206             :   }
     207        3130 :   return nullptr;
     208             : }
     209             : 
     210             : nsresult
     211          30 : nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
     212             :                                             int32_t aDOMClassInfoID,
     213             :                                             bool aPrivileged,
     214             :                                             bool aXBLAllowed,
     215             :                                             const char16_t **aResult)
     216             : {
     217          30 :   if (!nsCRT::IsAscii(aClassName)) {
     218           0 :     NS_ERROR("Trying to register a non-ASCII class name");
     219           0 :     return NS_OK;
     220             :   }
     221          30 :   nsGlobalNameStruct *s = AddToHash(aClassName, aResult);
     222          30 :   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
     223             : 
     224          30 :   if (s->mType == nsGlobalNameStruct::eTypeClassConstructor) {
     225           0 :     return NS_OK;
     226             :   }
     227             : 
     228             :   // If a external constructor is already defined with aClassName we
     229             :   // won't overwrite it.
     230             : 
     231          30 :   if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
     232           0 :     return NS_OK;
     233             :   }
     234             : 
     235          30 :   NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized,
     236             :                "Whaaa, JS environment name clash!");
     237             : 
     238          30 :   s->mType = nsGlobalNameStruct::eTypeClassConstructor;
     239          30 :   s->mDOMClassInfoID = aDOMClassInfoID;
     240          30 :   s->mChromeOnly = aPrivileged;
     241          30 :   s->mAllowXBL = aXBLAllowed;
     242             : 
     243          30 :   return NS_OK;
     244             : }
     245             : 
     246             : nsresult
     247          30 : nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName,
     248             :                                              const nsIID *aConstructorProtoIID,
     249             :                                              bool *aFoundOld)
     250             : {
     251          30 :   NS_ENSURE_ARG_POINTER(aConstructorProtoIID);
     252             : 
     253          30 :   *aFoundOld = false;
     254             : 
     255          30 :   nsGlobalNameStruct *s = AddToHash(aClassName);
     256          30 :   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
     257             : 
     258          30 :   if (s->mType != nsGlobalNameStruct::eTypeNotInitialized) {
     259          30 :     *aFoundOld = true;
     260             : 
     261          30 :     return NS_OK;
     262             :   }
     263             : 
     264           0 :   s->mType = nsGlobalNameStruct::eTypeClassProto;
     265           0 :   s->mIID = *aConstructorProtoIID;
     266             : 
     267           0 :   return NS_OK;
     268             : }
     269             : 
     270             : nsresult
     271           7 : nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategoryManager,
     272             :                                                    const char* aCategory,
     273             :                                                    nsISupports* aEntry,
     274             :                                                    bool aRemove)
     275             : {
     276           7 :   MOZ_ASSERT(aCategoryManager);
     277             :   // Get the type from the category name.
     278             :   // NOTE: we could have passed the type in FillHash() and guessed it in
     279             :   // Observe() but this way, we have only one place to update and this is
     280             :   // not performance sensitive.
     281             :   nsGlobalNameStruct::nametype type;
     282           7 :   if (strcmp(aCategory, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY) == 0) {
     283           0 :     type = nsGlobalNameStruct::eTypeExternalConstructor;
     284          11 :   } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY) == 0 ||
     285           4 :              strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0) {
     286           3 :     type = nsGlobalNameStruct::eTypeProperty;
     287             :   } else {
     288           4 :     return NS_OK;
     289             :   }
     290             : 
     291           6 :   nsCOMPtr<nsISupportsCString> strWrapper = do_QueryInterface(aEntry);
     292             : 
     293           3 :   if (!strWrapper) {
     294           0 :     NS_WARNING("Category entry not an nsISupportsCString!");
     295           0 :     return NS_OK;
     296             :   }
     297             : 
     298           6 :   nsAutoCString categoryEntry;
     299           3 :   nsresult rv = strWrapper->GetData(categoryEntry);
     300           3 :   NS_ENSURE_SUCCESS(rv, rv);
     301             : 
     302             :   // We need to handle removal before calling GetCategoryEntry
     303             :   // because the category entry is already removed before we are
     304             :   // notified.
     305           3 :   if (aRemove) {
     306           0 :     NS_ConvertASCIItoUTF16 entry(categoryEntry);
     307           0 :     const nsGlobalNameStruct *s = LookupName(entry);
     308             :     // Verify mType so that this API doesn't remove names
     309             :     // registered by others.
     310           0 :     if (!s || s->mType != type) {
     311           0 :       return NS_OK;
     312             :     }
     313             : 
     314           0 :     RemoveFromHash(&entry);
     315           0 :     return NS_OK;
     316             :   }
     317             : 
     318           6 :   nsXPIDLCString contractId;
     319           3 :   rv = aCategoryManager->GetCategoryEntry(aCategory, categoryEntry.get(),
     320           6 :                                           getter_Copies(contractId));
     321           3 :   NS_ENSURE_SUCCESS(rv, rv);
     322             : 
     323           6 :   nsCOMPtr<nsIComponentRegistrar> registrar;
     324           3 :   rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
     325           3 :   NS_ENSURE_SUCCESS(rv, rv);
     326             : 
     327             :   nsCID *cidPtr;
     328           3 :   rv = registrar->ContractIDToCID(contractId, &cidPtr);
     329             : 
     330           3 :   if (NS_FAILED(rv)) {
     331           0 :     NS_WARNING("Bad contract id registed with the script namespace manager");
     332           0 :     return NS_OK;
     333             :   }
     334             : 
     335             :   // Copy CID onto the stack, so we can free it right away and avoid having
     336             :   // to add cleanup code at every exit point from this function.
     337           3 :   nsCID cid = *cidPtr;
     338           3 :   free(cidPtr);
     339             : 
     340           3 :   nsGlobalNameStruct *s = AddToHash(categoryEntry.get());
     341           3 :   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
     342             : 
     343           3 :   if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
     344           3 :     s->mType = type;
     345           3 :     s->mCID = cid;
     346           3 :     s->mChromeOnly =
     347           3 :       strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0;
     348             :   } else {
     349           0 :     NS_WARNING("Global script name not overwritten!");
     350             :   }
     351             : 
     352           3 :   return NS_OK;
     353             : }
     354             : 
     355             : nsresult
     356           7 : nsScriptNameSpaceManager::AddCategoryEntryToHash(nsICategoryManager* aCategoryManager,
     357             :                                                  const char* aCategory,
     358             :                                                  nsISupports* aEntry)
     359             : {
     360             :   return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry,
     361           7 :                                   /* aRemove = */ false);
     362             : }
     363             : 
     364             : nsresult
     365           0 : nsScriptNameSpaceManager::RemoveCategoryEntryFromHash(nsICategoryManager* aCategoryManager,
     366             :                                                       const char* aCategory,
     367             :                                                       nsISupports* aEntry)
     368             : {
     369             :   return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry,
     370           0 :                                   /* aRemove = */ true);
     371             : }
     372             : 
     373             : NS_IMETHODIMP
     374           4 : nsScriptNameSpaceManager::Observe(nsISupports* aSubject, const char* aTopic,
     375             :                                   const char16_t* aData)
     376             : {
     377           4 :   if (!aData) {
     378           0 :     return NS_OK;
     379             :   }
     380             : 
     381           4 :   if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID)) {
     382             :     nsCOMPtr<nsICategoryManager> cm =
     383           8 :       do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
     384           4 :     if (!cm) {
     385           0 :       return NS_OK;
     386             :     }
     387             : 
     388           8 :     return AddCategoryEntryToHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
     389           4 :                                   aSubject);
     390           0 :   } else if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID)) {
     391             :     nsCOMPtr<nsICategoryManager> cm =
     392           0 :       do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
     393           0 :     if (!cm) {
     394           0 :       return NS_OK;
     395             :     }
     396             : 
     397           0 :     return RemoveCategoryEntryFromHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
     398           0 :                                        aSubject);
     399             :   }
     400             : 
     401             :   // TODO: we could observe NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID
     402             :   // but we are safe without it. See bug 600460.
     403             : 
     404           0 :   return NS_OK;
     405             : }
     406             : 
     407           0 : MOZ_DEFINE_MALLOC_SIZE_OF(ScriptNameSpaceManagerMallocSizeOf)
     408             : 
     409             : NS_IMETHODIMP
     410           0 : nsScriptNameSpaceManager::CollectReports(
     411             :   nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
     412             : {
     413           0 :   MOZ_COLLECT_REPORT(
     414             :     "explicit/script-namespace-manager", KIND_HEAP, UNITS_BYTES,
     415             :     SizeOfIncludingThis(ScriptNameSpaceManagerMallocSizeOf),
     416           0 :     "Memory used for the script namespace manager.");
     417             : 
     418           0 :   return NS_OK;
     419             : }
     420             : 
     421             : size_t
     422           0 : nsScriptNameSpaceManager::SizeOfIncludingThis(
     423             :     mozilla::MallocSizeOf aMallocSizeOf) const
     424             : {
     425           0 :   size_t n = 0;
     426             : 
     427           0 :   n += mGlobalNames.ShallowSizeOfExcludingThis(aMallocSizeOf);
     428           0 :   for (auto iter = mGlobalNames.ConstIter(); !iter.Done(); iter.Next()) {
     429           0 :     auto entry = static_cast<GlobalNameMapEntry*>(iter.Get());
     430           0 :     n += entry->SizeOfExcludingThis(aMallocSizeOf);
     431             :   }
     432             : 
     433           0 :   return n;
     434             : }

Generated by: LCOV version 1.13