dom/base/nsScriptNameSpaceManager.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     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 "nsIScriptExternalNameSet.h"
    16 #include "nsIScriptNameSpaceManager.h"
    17 #include "nsIScriptContext.h"
    18 #include "nsIInterfaceInfoManager.h"
    19 #include "nsIInterfaceInfo.h"
    20 #include "xptinfo.h"
    21 #include "nsXPIDLString.h"
    22 #include "nsPrintfCString.h"
    23 #include "nsReadableUtils.h"
    24 #include "nsHashKeys.h"
    25 #include "nsDOMClassInfo.h"
    26 #include "nsCRT.h"
    27 #include "nsIObserverService.h"
    28 #include "nsISimpleEnumerator.h"
    30 #include "mozilla/MemoryReporting.h"
    31 #include "mozilla/Preferences.h"
    32 #include "mozilla/Services.h"
    34 #define NS_INTERFACE_PREFIX "nsI"
    35 #define NS_DOM_INTERFACE_PREFIX "nsIDOM"
    37 using namespace mozilla;
    39 // Our extended PLDHashEntryHdr
    40 class GlobalNameMapEntry : public PLDHashEntryHdr
    41 {
    42 public:
    43   // Our hash table ops don't care about the order of these members
    44   nsString mKey;
    45   nsGlobalNameStruct mGlobalName;
    47   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) {
    48     // Measurement of the following members may be added later if DMD finds it
    49     // is worthwhile:
    50     // - mGlobalName
    51     return mKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
    52   }
    53 };
    56 static PLDHashNumber
    57 GlobalNameHashHashKey(PLDHashTable *table, const void *key)
    58 {
    59   const nsAString *str = static_cast<const nsAString *>(key);
    60   return HashString(*str);
    61 }
    63 static bool
    64 GlobalNameHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry,
    65                          const void *key)
    66 {
    67   const GlobalNameMapEntry *e =
    68     static_cast<const GlobalNameMapEntry *>(entry);
    69   const nsAString *str = static_cast<const nsAString *>(key);
    71   return str->Equals(e->mKey);
    72 }
    74 static void
    75 GlobalNameHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
    76 {
    77   GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
    79   // An entry is being cleared, let the key (nsString) do its own
    80   // cleanup.
    81   e->mKey.~nsString();
    82   if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
    83     nsIClassInfo* ci = GET_CLEAN_CI_PTR(e->mGlobalName.mData->mCachedClassInfo);
    85     // If we constructed an internal helper, we'll let the helper delete 
    86     // the nsDOMClassInfoData structure, if not we do it here.
    87     if (!ci || e->mGlobalName.mData->u.mExternalConstructorFptr) {
    88       delete e->mGlobalName.mData;
    89     }
    91     // Release our pointer to the helper.
    92     NS_IF_RELEASE(ci);
    93   }
    94   else if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
    95     delete e->mGlobalName.mAlias;
    96   }
    98   // This will set e->mGlobalName.mType to
    99   // nsGlobalNameStruct::eTypeNotInitialized
   100   memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
   101 }
   103 static bool
   104 GlobalNameHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
   105                         const void *key)
   106 {
   107   GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
   108   const nsAString *keyStr = static_cast<const nsAString *>(key);
   110   // Initialize the key in the entry with placement new
   111   new (&e->mKey) nsString(*keyStr);
   113   // This will set e->mGlobalName.mType to
   114   // nsGlobalNameStruct::eTypeNotInitialized
   115   memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
   116   return true;
   117 }
   119 NS_IMPL_ISUPPORTS(
   120   nsScriptNameSpaceManager,
   121   nsIObserver,
   122   nsISupportsWeakReference,
   123   nsIMemoryReporter)
   125 nsScriptNameSpaceManager::nsScriptNameSpaceManager()
   126   : mIsInitialized(false)
   127 {
   128   MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
   129 }
   131 nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
   132 {
   133   if (mIsInitialized) {
   134     UnregisterWeakMemoryReporter(this);
   135     // Destroy the hash
   136     PL_DHashTableFinish(&mGlobalNames);
   137     PL_DHashTableFinish(&mNavigatorNames);
   138   }
   139   MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
   140 }
   142 nsGlobalNameStruct *
   143 nsScriptNameSpaceManager::AddToHash(PLDHashTable *aTable, const nsAString *aKey,
   144                                     const char16_t **aClassName)
   145 {
   146   GlobalNameMapEntry *entry =
   147     static_cast<GlobalNameMapEntry *>
   148                (PL_DHashTableOperate(aTable, aKey, PL_DHASH_ADD));
   150   if (!entry) {
   151     return nullptr;
   152   }
   154   if (aClassName) {
   155     *aClassName = entry->mKey.get();
   156   }
   158   return &entry->mGlobalName;
   159 }
   161 void
   162 nsScriptNameSpaceManager::RemoveFromHash(PLDHashTable *aTable,
   163                                          const nsAString *aKey)
   164 {
   165   PL_DHashTableOperate(aTable, aKey, PL_DHASH_REMOVE);
   166 }
   168 nsGlobalNameStruct*
   169 nsScriptNameSpaceManager::GetConstructorProto(const nsGlobalNameStruct* aStruct)
   170 {
   171   NS_ASSERTION(aStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias,
   172                "This function only works on constructor aliases!");
   173   if (!aStruct->mAlias->mProto) {
   174     GlobalNameMapEntry *proto =
   175       static_cast<GlobalNameMapEntry *>
   176                  (PL_DHashTableOperate(&mGlobalNames,
   177                                           &aStruct->mAlias->mProtoName,
   178                                           PL_DHASH_LOOKUP));
   180     if (PL_DHASH_ENTRY_IS_BUSY(proto)) {
   181       aStruct->mAlias->mProto = &proto->mGlobalName;
   182     }
   183   }
   184   return aStruct->mAlias->mProto;
   185 }
   187 nsresult
   188 nsScriptNameSpaceManager::FillHash(nsICategoryManager *aCategoryManager,
   189                                    const char *aCategory)
   190 {
   191   nsCOMPtr<nsISimpleEnumerator> e;
   192   nsresult rv = aCategoryManager->EnumerateCategory(aCategory,
   193                                                     getter_AddRefs(e));
   194   NS_ENSURE_SUCCESS(rv, rv);
   196   nsCOMPtr<nsISupports> entry;
   197   while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) {
   198     rv = AddCategoryEntryToHash(aCategoryManager, aCategory, entry);
   199     if (NS_FAILED(rv)) {
   200       return rv;
   201     }
   202   }
   204   return NS_OK;
   205 }
   208 nsresult
   209 nsScriptNameSpaceManager::RegisterExternalInterfaces(bool aAsProto)
   210 {
   211   nsresult rv;
   212   nsCOMPtr<nsICategoryManager> cm =
   213     do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
   214   NS_ENSURE_SUCCESS(rv, rv);
   216   nsCOMPtr<nsIInterfaceInfoManager>
   217     iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
   218   NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
   220   nsCOMPtr<nsISimpleEnumerator> enumerator;
   221   rv = cm->EnumerateCategory(JAVASCRIPT_DOM_INTERFACE,
   222                              getter_AddRefs(enumerator));
   223   NS_ENSURE_SUCCESS(rv, rv);
   225   nsXPIDLCString IID_string;
   226   nsAutoCString category_entry;
   227   const char* if_name;
   228   nsCOMPtr<nsISupports> entry;
   229   nsCOMPtr<nsIInterfaceInfo> if_info;
   230   bool found_old, dom_prefix;
   232   while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) {
   233     nsCOMPtr<nsISupportsCString> category(do_QueryInterface(entry));
   235     if (!category) {
   236       NS_WARNING("Category entry not an nsISupportsCString!");
   238       continue;
   239     }
   241     rv = category->GetData(category_entry);
   242     NS_ENSURE_SUCCESS(rv, rv);
   244     rv = cm->GetCategoryEntry(JAVASCRIPT_DOM_INTERFACE, category_entry.get(),
   245                               getter_Copies(IID_string));
   246     NS_ENSURE_SUCCESS(rv, rv);
   248     nsIID primary_IID;
   249     if (!primary_IID.Parse(IID_string) ||
   250         primary_IID.Equals(NS_GET_IID(nsISupports))) {
   251       NS_ERROR("Invalid IID registered with the script namespace manager!");
   252       continue;
   253     }
   255     iim->GetInfoForIID(&primary_IID, getter_AddRefs(if_info));
   257     while (if_info) {
   258       const nsIID *iid;
   259       if_info->GetIIDShared(&iid);
   260       NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
   262       if (iid->Equals(NS_GET_IID(nsISupports))) {
   263         break;
   264       }
   266       if_info->GetNameShared(&if_name);
   267       dom_prefix = (strncmp(if_name, NS_DOM_INTERFACE_PREFIX,
   268                             sizeof(NS_DOM_INTERFACE_PREFIX) - 1) == 0);
   270       const char* name;
   271       if (dom_prefix) {
   272         name = if_name + sizeof(NS_DOM_INTERFACE_PREFIX) - 1;
   273       } else {
   274         name = if_name + sizeof(NS_INTERFACE_PREFIX) - 1;
   275       }
   277       if (aAsProto) {
   278         RegisterClassProto(name, iid, &found_old);
   279       } else {
   280         RegisterInterface(name, iid, &found_old);
   281       }
   283       if (found_old) {
   284         break;
   285       }
   287       nsCOMPtr<nsIInterfaceInfo> tmp(if_info);
   288       tmp->GetParent(getter_AddRefs(if_info));
   289     }
   290   }
   292   return NS_OK;
   293 }
   295 nsresult
   296 nsScriptNameSpaceManager::RegisterInterface(const char* aIfName,
   297                                             const nsIID *aIfIID,
   298                                             bool* aFoundOld)
   299 {
   300   *aFoundOld = false;
   302   nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aIfName);
   303   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
   305   if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
   306       s->mType != nsGlobalNameStruct::eTypeNewDOMBinding) {
   307     *aFoundOld = true;
   309     return NS_OK;
   310   }
   312   s->mType = nsGlobalNameStruct::eTypeInterface;
   313   s->mIID = *aIfIID;
   315   return NS_OK;
   316 }
   318 #define GLOBALNAME_HASHTABLE_INITIAL_SIZE	1024
   320 nsresult
   321 nsScriptNameSpaceManager::Init()
   322 {
   323   static const PLDHashTableOps hash_table_ops =
   324   {
   325     PL_DHashAllocTable,
   326     PL_DHashFreeTable,
   327     GlobalNameHashHashKey,
   328     GlobalNameHashMatchEntry,
   329     PL_DHashMoveEntryStub,
   330     GlobalNameHashClearEntry,
   331     PL_DHashFinalizeStub,
   332     GlobalNameHashInitEntry
   333   };
   335   mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops,
   336                                      nullptr, sizeof(GlobalNameMapEntry),
   337                                      GLOBALNAME_HASHTABLE_INITIAL_SIZE,
   338                                      fallible_t());
   339   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY);
   341   mIsInitialized = PL_DHashTableInit(&mNavigatorNames, &hash_table_ops,
   342                                      nullptr, sizeof(GlobalNameMapEntry),
   343                                      GLOBALNAME_HASHTABLE_INITIAL_SIZE,
   344                                      fallible_t());
   345   if (!mIsInitialized) {
   346     PL_DHashTableFinish(&mGlobalNames);
   348     return NS_ERROR_OUT_OF_MEMORY;
   349   }
   351   RegisterWeakMemoryReporter(this);
   353   nsresult rv = NS_OK;
   355   rv = RegisterExternalInterfaces(false);
   356   NS_ENSURE_SUCCESS(rv, rv);
   358   nsCOMPtr<nsICategoryManager> cm =
   359     do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
   360   NS_ENSURE_SUCCESS(rv, rv);
   362   rv = FillHash(cm, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY);
   363   NS_ENSURE_SUCCESS(rv, rv);
   365   rv = FillHash(cm, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY);
   366   NS_ENSURE_SUCCESS(rv, rv);
   368   rv = FillHash(cm, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY);
   369   NS_ENSURE_SUCCESS(rv, rv);
   371   rv = FillHash(cm, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY);
   372   NS_ENSURE_SUCCESS(rv, rv);
   374   rv = FillHash(cm, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY);
   375   NS_ENSURE_SUCCESS(rv, rv);
   377   // Initial filling of the has table has been done.
   378   // Now, listen for changes.
   379   nsCOMPtr<nsIObserverService> serv = 
   380     mozilla::services::GetObserverService();
   382   if (serv) {
   383     serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, true);
   384     serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID, true);
   385   }
   387   return NS_OK;
   388 }
   390 struct NameSetClosure {
   391   nsIScriptContext* ctx;
   392   nsresult rv;
   393 };
   395 static PLDHashOperator
   396 NameSetInitCallback(PLDHashTable *table, PLDHashEntryHdr *hdr,
   397                     uint32_t number, void *arg)
   398 {
   399   GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>(hdr);
   401   if (entry->mGlobalName.mType == nsGlobalNameStruct::eTypeStaticNameSet) {
   402     nsresult rv = NS_OK;
   403     nsCOMPtr<nsIScriptExternalNameSet> ns =
   404       do_CreateInstance(entry->mGlobalName.mCID, &rv);
   405     NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
   407     NameSetClosure *closure = static_cast<NameSetClosure *>(arg);
   408     closure->rv = ns->InitializeNameSet(closure->ctx);
   409     if (NS_FAILED(closure->rv)) {
   410       NS_ERROR("Initing external script classes failed!");
   411       return PL_DHASH_STOP;
   412     }
   413   }
   415   return PL_DHASH_NEXT;
   416 }
   418 nsresult
   419 nsScriptNameSpaceManager::InitForContext(nsIScriptContext *aContext)
   420 {
   421   NameSetClosure closure;
   422   closure.ctx = aContext;
   423   closure.rv = NS_OK;
   424   PL_DHashTableEnumerate(&mGlobalNames, NameSetInitCallback, &closure);
   426   return closure.rv;
   427 }
   429 nsGlobalNameStruct*
   430 nsScriptNameSpaceManager::LookupNameInternal(const nsAString& aName,
   431                                              const char16_t **aClassName)
   432 {
   433   GlobalNameMapEntry *entry =
   434     static_cast<GlobalNameMapEntry *>
   435                (PL_DHashTableOperate(&mGlobalNames, &aName,
   436                                         PL_DHASH_LOOKUP));
   438   if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
   439     if (aClassName) {
   440       *aClassName = entry->mKey.get();
   441     }
   442     return &entry->mGlobalName;
   443   }
   445   if (aClassName) {
   446     *aClassName = nullptr;
   447   }
   448   return nullptr;
   449 }
   451 const nsGlobalNameStruct*
   452 nsScriptNameSpaceManager::LookupNavigatorName(const nsAString& aName)
   453 {
   454   GlobalNameMapEntry *entry =
   455     static_cast<GlobalNameMapEntry *>
   456                (PL_DHashTableOperate(&mNavigatorNames, &aName,
   457                                      PL_DHASH_LOOKUP));
   459   if (!PL_DHASH_ENTRY_IS_BUSY(entry)) {
   460     return nullptr;
   461   }
   463   return &entry->mGlobalName;
   464 }
   466 nsresult
   467 nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
   468                                             int32_t aDOMClassInfoID,
   469                                             bool aPrivileged,
   470                                             bool aXBLAllowed,
   471                                             const char16_t **aResult)
   472 {
   473   if (!nsCRT::IsAscii(aClassName)) {
   474     NS_ERROR("Trying to register a non-ASCII class name");
   475     return NS_OK;
   476   }
   477   nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName, aResult);
   478   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
   480   if (s->mType == nsGlobalNameStruct::eTypeClassConstructor) {
   481     return NS_OK;
   482   }
   484   // If a external constructor is already defined with aClassName we
   485   // won't overwrite it.
   487   if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
   488     return NS_OK;
   489   }
   491   NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
   492                s->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
   493                s->mType == nsGlobalNameStruct::eTypeInterface,
   494                "Whaaa, JS environment name clash!");
   496   s->mType = nsGlobalNameStruct::eTypeClassConstructor;
   497   s->mDOMClassInfoID = aDOMClassInfoID;
   498   s->mChromeOnly = aPrivileged;
   499   s->mAllowXBL = aXBLAllowed;
   501   return NS_OK;
   502 }
   504 nsresult
   505 nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName,
   506                                              const nsIID *aConstructorProtoIID,
   507                                              bool *aFoundOld)
   508 {
   509   NS_ENSURE_ARG_POINTER(aConstructorProtoIID);
   511   *aFoundOld = false;
   513   nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName);
   514   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
   516   if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
   517       s->mType != nsGlobalNameStruct::eTypeNewDOMBinding &&
   518       s->mType != nsGlobalNameStruct::eTypeInterface) {
   519     *aFoundOld = true;
   521     return NS_OK;
   522   }
   524   s->mType = nsGlobalNameStruct::eTypeClassProto;
   525   s->mIID = *aConstructorProtoIID;
   527   return NS_OK;
   528 }
   530 nsresult
   531 nsScriptNameSpaceManager::RegisterExternalClassName(const char *aClassName,
   532                                                     nsCID& aCID)
   533 {
   534   nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName);
   535   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
   537   // If an external constructor is already defined with aClassName we
   538   // won't overwrite it.
   540   if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
   541     return NS_OK;
   542   }
   544   NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
   545                s->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
   546                s->mType == nsGlobalNameStruct::eTypeInterface,
   547                "Whaaa, JS environment name clash!");
   549   s->mType = nsGlobalNameStruct::eTypeExternalClassInfoCreator;
   550   s->mCID = aCID;
   552   return NS_OK;
   553 }
   555 nsresult
   556 nsScriptNameSpaceManager::RegisterDOMCIData(const char *aName,
   557                                             nsDOMClassInfoExternalConstructorFnc aConstructorFptr,
   558                                             const nsIID *aProtoChainInterface,
   559                                             const nsIID **aInterfaces,
   560                                             uint32_t aScriptableFlags,
   561                                             bool aHasClassInterface,
   562                                             const nsCID *aConstructorCID)
   563 {
   564   const char16_t* className;
   565   nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aName, &className);
   566   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
   568   // If an external constructor is already defined with aClassName we
   569   // won't overwrite it.
   571   if (s->mType == nsGlobalNameStruct::eTypeClassConstructor ||
   572       s->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
   573     return NS_OK;
   574   }
   576   // XXX Should we bail out here?
   577   NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
   578                s->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
   579                s->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator,
   580                "Someone tries to register classinfo data for a class that isn't new or external!");
   582   s->mData = new nsExternalDOMClassInfoData;
   583   NS_ENSURE_TRUE(s->mData, NS_ERROR_OUT_OF_MEMORY);
   585   s->mType = nsGlobalNameStruct::eTypeExternalClassInfo;
   586   s->mData->mName = aName;
   587   s->mData->mNameUTF16 = className;
   588   if (aConstructorFptr)
   589     s->mData->u.mExternalConstructorFptr = aConstructorFptr;
   590   else
   591     // null constructor will cause us to use nsDOMGenericSH::doCreate
   592     s->mData->u.mExternalConstructorFptr = nullptr;
   593   s->mData->mCachedClassInfo = nullptr;
   594   s->mData->mProtoChainInterface = aProtoChainInterface;
   595   s->mData->mInterfaces = aInterfaces;
   596   s->mData->mScriptableFlags = aScriptableFlags;
   597   s->mData->mHasClassInterface = aHasClassInterface;
   598   s->mData->mConstructorCID = aConstructorCID;
   600   return NS_OK;
   601 }
   603 nsresult
   604 nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategoryManager,
   605                                                    const char* aCategory,
   606                                                    nsISupports* aEntry,
   607                                                    bool aRemove)
   608 {
   609   MOZ_ASSERT(aCategoryManager);
   610   // Get the type from the category name.
   611   // NOTE: we could have passed the type in FillHash() and guessed it in
   612   // Observe() but this way, we have only one place to update and this is
   613   // not performance sensitive.
   614   nsGlobalNameStruct::nametype type;
   615   if (strcmp(aCategory, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY) == 0) {
   616     type = nsGlobalNameStruct::eTypeExternalConstructor;
   617   } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY) == 0 ||
   618              strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0) {
   619     type = nsGlobalNameStruct::eTypeProperty;
   620   } else if (strcmp(aCategory, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY) == 0) {
   621     type = nsGlobalNameStruct::eTypeNavigatorProperty;
   622   } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY) == 0) {
   623     type = nsGlobalNameStruct::eTypeStaticNameSet;
   624   } else {
   625     return NS_OK;
   626   }
   628   nsCOMPtr<nsISupportsCString> strWrapper = do_QueryInterface(aEntry);
   630   if (!strWrapper) {
   631     NS_WARNING("Category entry not an nsISupportsCString!");
   632     return NS_OK;
   633   }
   635   nsAutoCString categoryEntry;
   636   nsresult rv = strWrapper->GetData(categoryEntry);
   637   NS_ENSURE_SUCCESS(rv, rv);
   639   PLDHashTable *table;
   640   if (type == nsGlobalNameStruct::eTypeNavigatorProperty) {
   641     table = &mNavigatorNames;
   642   } else {
   643     table = &mGlobalNames;
   644   }
   646   // We need to handle removal before calling GetCategoryEntry
   647   // because the category entry is already removed before we are
   648   // notified.
   649   if (aRemove) {
   650     NS_ConvertASCIItoUTF16 entry(categoryEntry);
   651     const nsGlobalNameStruct *s =
   652       type == nsGlobalNameStruct::eTypeNavigatorProperty ?
   653       LookupNavigatorName(entry) : LookupNameInternal(entry);
   654     // Verify mType so that this API doesn't remove names
   655     // registered by others.
   656     if (!s || s->mType != type) {
   657       return NS_OK;
   658     }
   660     RemoveFromHash(table, &entry);
   661     return NS_OK;
   662   }
   664   nsXPIDLCString contractId;
   665   rv = aCategoryManager->GetCategoryEntry(aCategory, categoryEntry.get(),
   666                                           getter_Copies(contractId));
   667   NS_ENSURE_SUCCESS(rv, rv);
   669   if (type == nsGlobalNameStruct::eTypeNavigatorProperty ||
   670       type == nsGlobalNameStruct::eTypeExternalConstructor) {
   671     bool isNavProperty = type == nsGlobalNameStruct::eTypeNavigatorProperty;
   672     nsPrintfCString prefName("dom.%s.disable.%s",
   673                              isNavProperty ? "navigator-property" : "global-constructor",
   674                              categoryEntry.get());
   675     if (Preferences::GetType(prefName.get()) == nsIPrefBranch::PREF_BOOL &&
   676         Preferences::GetBool(prefName.get(), false)) {
   677         return NS_OK;
   678     }
   679   }
   681   nsCOMPtr<nsIComponentRegistrar> registrar;
   682   rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
   683   NS_ENSURE_SUCCESS(rv, rv);
   685   nsCID *cidPtr;
   686   rv = registrar->ContractIDToCID(contractId, &cidPtr);
   688   if (NS_FAILED(rv)) {
   689     NS_WARNING("Bad contract id registed with the script namespace manager");
   690     return NS_OK;
   691   }
   693   // Copy CID onto the stack, so we can free it right away and avoid having
   694   // to add cleanup code at every exit point from this function.
   695   nsCID cid = *cidPtr;
   696   nsMemory::Free(cidPtr);
   698   if (type == nsGlobalNameStruct::eTypeExternalConstructor) {
   699     nsXPIDLCString constructorProto;
   700     rv = aCategoryManager->GetCategoryEntry(JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY,
   701                                             categoryEntry.get(),
   702                                             getter_Copies(constructorProto));
   703     if (NS_SUCCEEDED(rv)) {
   704       nsGlobalNameStruct *s = AddToHash(&mGlobalNames, categoryEntry.get());
   705       NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
   707       if (s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
   708           s->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
   709         s->mAlias = new nsGlobalNameStruct::ConstructorAlias;
   710         s->mType = nsGlobalNameStruct::eTypeExternalConstructorAlias;
   711         s->mChromeOnly = false;
   712         s->mAlias->mCID = cid;
   713         AppendASCIItoUTF16(constructorProto, s->mAlias->mProtoName);
   714         s->mAlias->mProto = nullptr;
   715       } else {
   716         NS_WARNING("Global script name not overwritten!");
   717       }
   719       return NS_OK;
   720     }
   721   }
   723   nsGlobalNameStruct *s = AddToHash(table, categoryEntry.get());
   724   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
   726   if (s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
   727       s->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
   728     s->mType = type;
   729     s->mCID = cid;
   730     s->mChromeOnly =
   731       strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0;
   732   } else {
   733     NS_WARNING("Global script name not overwritten!");
   734   }
   736   return NS_OK;
   737 }
   739 nsresult
   740 nsScriptNameSpaceManager::AddCategoryEntryToHash(nsICategoryManager* aCategoryManager,
   741                                                  const char* aCategory,
   742                                                  nsISupports* aEntry)
   743 {
   744   return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry,
   745                                   /* aRemove = */ false);
   746 }
   748 nsresult
   749 nsScriptNameSpaceManager::RemoveCategoryEntryFromHash(nsICategoryManager* aCategoryManager,
   750                                                       const char* aCategory,
   751                                                       nsISupports* aEntry)
   752 {
   753   return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry,
   754                                   /* aRemove = */ true);
   755 }
   757 NS_IMETHODIMP
   758 nsScriptNameSpaceManager::Observe(nsISupports* aSubject, const char* aTopic,
   759                                   const char16_t* aData)
   760 {
   761   if (!aData) {
   762     return NS_OK;
   763   }
   765   if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID)) {
   766     nsCOMPtr<nsICategoryManager> cm =
   767       do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
   768     if (!cm) {
   769       return NS_OK;
   770     }
   772     return AddCategoryEntryToHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
   773                                   aSubject);
   774   } else if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID)) {
   775     nsCOMPtr<nsICategoryManager> cm =
   776       do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
   777     if (!cm) {
   778       return NS_OK;
   779     }
   781     return RemoveCategoryEntryFromHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
   782                                        aSubject);
   783   }
   785   // TODO: we could observe NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID
   786   // but we are safe without it. See bug 600460.
   788   return NS_OK;
   789 }
   791 void
   792 nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
   793     mozilla::dom::DefineInterface aDefineDOMInterface,
   794     mozilla::dom::ConstructorEnabled* aConstructorEnabled)
   795 {
   796   nsGlobalNameStruct *s = AddToHash(&mGlobalNames, &aName);
   797   if (s) {
   798     if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
   799       s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
   800     }
   801     s->mDefineDOMInterface = aDefineDOMInterface;
   802     s->mConstructorEnabled = aConstructorEnabled;
   803   }
   804 }
   806 void
   807 nsScriptNameSpaceManager::RegisterNavigatorDOMConstructor(
   808     const nsAFlatString& aName,
   809     mozilla::dom::ConstructNavigatorProperty aNavConstructor,
   810     mozilla::dom::ConstructorEnabled* aConstructorEnabled)
   811 {
   812   nsGlobalNameStruct *s = AddToHash(&mNavigatorNames, &aName);
   813   if (s) {
   814     if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
   815       s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
   816     }
   817     s->mConstructNavigatorProperty = aNavConstructor;
   818     s->mConstructorEnabled = aConstructorEnabled;
   819   }
   820 }
   822 struct NameClosure
   823 {
   824   nsScriptNameSpaceManager::NameEnumerator enumerator;
   825   void* closure;
   826 };
   828 static PLDHashOperator
   829 EnumerateName(PLDHashTable*, PLDHashEntryHdr *hdr, uint32_t, void* aClosure)
   830 {
   831   GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>(hdr);
   832   NameClosure* closure = static_cast<NameClosure*>(aClosure);
   833   return closure->enumerator(entry->mKey, entry->mGlobalName, closure->closure);
   834 }
   836 void
   837 nsScriptNameSpaceManager::EnumerateGlobalNames(NameEnumerator aEnumerator,
   838                                                void* aClosure)
   839 {
   840   NameClosure closure = { aEnumerator, aClosure };
   841   PL_DHashTableEnumerate(&mGlobalNames, EnumerateName, &closure);
   842 }
   844 void
   845 nsScriptNameSpaceManager::EnumerateNavigatorNames(NameEnumerator aEnumerator,
   846                                                   void* aClosure)
   847 {
   848   NameClosure closure = { aEnumerator, aClosure };
   849   PL_DHashTableEnumerate(&mNavigatorNames, EnumerateName, &closure);
   850 }
   852 static size_t
   853 SizeOfEntryExcludingThis(PLDHashEntryHdr *aHdr, MallocSizeOf aMallocSizeOf,
   854                          void *aArg)
   855 {
   856   GlobalNameMapEntry* entry = static_cast<GlobalNameMapEntry*>(aHdr);
   857   return entry->SizeOfExcludingThis(aMallocSizeOf);
   858 }
   860 MOZ_DEFINE_MALLOC_SIZE_OF(ScriptNameSpaceManagerMallocSizeOf)
   862 NS_IMETHODIMP
   863 nsScriptNameSpaceManager::CollectReports(
   864   nsIHandleReportCallback* aHandleReport, nsISupports* aData)
   865 {
   866   return MOZ_COLLECT_REPORT(
   867     "explicit/script-namespace-manager", KIND_HEAP, UNITS_BYTES,
   868     SizeOfIncludingThis(ScriptNameSpaceManagerMallocSizeOf),
   869     "Memory used for the script namespace manager.");
   870 }
   872 size_t
   873 nsScriptNameSpaceManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
   874 {
   875   size_t n = 0;
   876   n += PL_DHashTableSizeOfExcludingThis(&mGlobalNames,
   877          SizeOfEntryExcludingThis, aMallocSizeOf);
   878   n += PL_DHashTableSizeOfExcludingThis(&mNavigatorNames,
   879          SizeOfEntryExcludingThis, aMallocSizeOf);
   880   return n;
   881 }

mercurial