Bumping manifests a=b2g-bump
[gecko.git] / dom / base / nsScriptNameSpaceManager.cpp
blob1b6e962cac7fbdfc664cb122b0030890f9c16fc1
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 "nsIScriptNameSpaceManager.h"
16 #include "nsIScriptContext.h"
17 #include "nsIInterfaceInfoManager.h"
18 #include "nsIInterfaceInfo.h"
19 #include "xptinfo.h"
20 #include "nsXPIDLString.h"
21 #include "nsPrintfCString.h"
22 #include "nsReadableUtils.h"
23 #include "nsHashKeys.h"
24 #include "nsDOMClassInfo.h"
25 #include "nsCRT.h"
26 #include "nsIObserverService.h"
27 #include "nsISimpleEnumerator.h"
29 #include "mozilla/MemoryReporting.h"
30 #include "mozilla/Preferences.h"
31 #include "mozilla/Services.h"
33 #define NS_INTERFACE_PREFIX "nsI"
34 #define NS_DOM_INTERFACE_PREFIX "nsIDOM"
36 using namespace mozilla;
38 // Our extended PLDHashEntryHdr
39 class GlobalNameMapEntry : public PLDHashEntryHdr
41 public:
42 // Our hash table ops don't care about the order of these members
43 nsString mKey;
44 nsGlobalNameStruct mGlobalName;
46 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) {
47 // Measurement of the following members may be added later if DMD finds it
48 // is worthwhile:
49 // - mGlobalName
50 return mKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
55 static PLDHashNumber
56 GlobalNameHashHashKey(PLDHashTable *table, const void *key)
58 const nsAString *str = static_cast<const nsAString *>(key);
59 return HashString(*str);
62 static bool
63 GlobalNameHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry,
64 const void *key)
66 const GlobalNameMapEntry *e =
67 static_cast<const GlobalNameMapEntry *>(entry);
68 const nsAString *str = static_cast<const nsAString *>(key);
70 return str->Equals(e->mKey);
73 static void
74 GlobalNameHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
76 GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
78 // An entry is being cleared, let the key (nsString) do its own
79 // cleanup.
80 e->mKey.~nsString();
81 if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
82 nsIClassInfo* ci = GET_CLEAN_CI_PTR(e->mGlobalName.mData->mCachedClassInfo);
84 // If we constructed an internal helper, we'll let the helper delete
85 // the nsDOMClassInfoData structure, if not we do it here.
86 if (!ci || e->mGlobalName.mData->u.mExternalConstructorFptr) {
87 delete e->mGlobalName.mData;
90 // Release our pointer to the helper.
91 NS_IF_RELEASE(ci);
93 else if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
94 delete e->mGlobalName.mAlias;
97 // This will set e->mGlobalName.mType to
98 // nsGlobalNameStruct::eTypeNotInitialized
99 memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
102 static bool
103 GlobalNameHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
104 const void *key)
106 GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
107 const nsAString *keyStr = static_cast<const nsAString *>(key);
109 // Initialize the key in the entry with placement new
110 new (&e->mKey) nsString(*keyStr);
112 // This will set e->mGlobalName.mType to
113 // nsGlobalNameStruct::eTypeNotInitialized
114 memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
115 return true;
118 NS_IMPL_ISUPPORTS(
119 nsScriptNameSpaceManager,
120 nsIObserver,
121 nsISupportsWeakReference,
122 nsIMemoryReporter)
124 nsScriptNameSpaceManager::nsScriptNameSpaceManager()
125 : mIsInitialized(false)
127 MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
130 nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
132 if (mIsInitialized) {
133 UnregisterWeakMemoryReporter(this);
134 // Destroy the hash
135 PL_DHashTableFinish(&mGlobalNames);
136 PL_DHashTableFinish(&mNavigatorNames);
138 MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
141 nsGlobalNameStruct *
142 nsScriptNameSpaceManager::AddToHash(PLDHashTable *aTable, const nsAString *aKey,
143 const char16_t **aClassName)
145 GlobalNameMapEntry *entry =
146 static_cast<GlobalNameMapEntry *>
147 (PL_DHashTableOperate(aTable, aKey, PL_DHASH_ADD));
149 if (!entry) {
150 return nullptr;
153 if (aClassName) {
154 *aClassName = entry->mKey.get();
157 return &entry->mGlobalName;
160 void
161 nsScriptNameSpaceManager::RemoveFromHash(PLDHashTable *aTable,
162 const nsAString *aKey)
164 PL_DHashTableOperate(aTable, aKey, PL_DHASH_REMOVE);
167 nsGlobalNameStruct*
168 nsScriptNameSpaceManager::GetConstructorProto(const nsGlobalNameStruct* aStruct)
170 NS_ASSERTION(aStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias,
171 "This function only works on constructor aliases!");
172 if (!aStruct->mAlias->mProto) {
173 GlobalNameMapEntry *proto =
174 static_cast<GlobalNameMapEntry *>
175 (PL_DHashTableOperate(&mGlobalNames,
176 &aStruct->mAlias->mProtoName,
177 PL_DHASH_LOOKUP));
179 if (PL_DHASH_ENTRY_IS_BUSY(proto)) {
180 aStruct->mAlias->mProto = &proto->mGlobalName;
183 return aStruct->mAlias->mProto;
186 nsresult
187 nsScriptNameSpaceManager::FillHash(nsICategoryManager *aCategoryManager,
188 const char *aCategory)
190 nsCOMPtr<nsISimpleEnumerator> e;
191 nsresult rv = aCategoryManager->EnumerateCategory(aCategory,
192 getter_AddRefs(e));
193 NS_ENSURE_SUCCESS(rv, rv);
195 nsCOMPtr<nsISupports> entry;
196 while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) {
197 rv = AddCategoryEntryToHash(aCategoryManager, aCategory, entry);
198 if (NS_FAILED(rv)) {
199 return rv;
203 return NS_OK;
207 nsresult
208 nsScriptNameSpaceManager::RegisterExternalInterfaces(bool aAsProto)
210 nsresult rv;
211 nsCOMPtr<nsICategoryManager> cm =
212 do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
213 NS_ENSURE_SUCCESS(rv, rv);
215 nsCOMPtr<nsIInterfaceInfoManager>
216 iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
217 NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE);
219 nsCOMPtr<nsISimpleEnumerator> enumerator;
220 rv = cm->EnumerateCategory(JAVASCRIPT_DOM_INTERFACE,
221 getter_AddRefs(enumerator));
222 NS_ENSURE_SUCCESS(rv, rv);
224 nsXPIDLCString IID_string;
225 nsAutoCString category_entry;
226 const char* if_name;
227 nsCOMPtr<nsISupports> entry;
228 nsCOMPtr<nsIInterfaceInfo> if_info;
229 bool found_old, dom_prefix;
231 while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) {
232 nsCOMPtr<nsISupportsCString> category(do_QueryInterface(entry));
234 if (!category) {
235 NS_WARNING("Category entry not an nsISupportsCString!");
237 continue;
240 rv = category->GetData(category_entry);
241 NS_ENSURE_SUCCESS(rv, rv);
243 rv = cm->GetCategoryEntry(JAVASCRIPT_DOM_INTERFACE, category_entry.get(),
244 getter_Copies(IID_string));
245 NS_ENSURE_SUCCESS(rv, rv);
247 nsIID primary_IID;
248 if (!primary_IID.Parse(IID_string) ||
249 primary_IID.Equals(NS_GET_IID(nsISupports))) {
250 NS_ERROR("Invalid IID registered with the script namespace manager!");
251 continue;
254 iim->GetInfoForIID(&primary_IID, getter_AddRefs(if_info));
256 while (if_info) {
257 const nsIID *iid;
258 if_info->GetIIDShared(&iid);
259 NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
261 if (iid->Equals(NS_GET_IID(nsISupports))) {
262 break;
265 if_info->GetNameShared(&if_name);
266 dom_prefix = (strncmp(if_name, NS_DOM_INTERFACE_PREFIX,
267 sizeof(NS_DOM_INTERFACE_PREFIX) - 1) == 0);
269 const char* name;
270 if (dom_prefix) {
271 name = if_name + sizeof(NS_DOM_INTERFACE_PREFIX) - 1;
272 } else {
273 name = if_name + sizeof(NS_INTERFACE_PREFIX) - 1;
276 if (aAsProto) {
277 RegisterClassProto(name, iid, &found_old);
278 } else {
279 RegisterInterface(name, iid, &found_old);
282 if (found_old) {
283 break;
286 nsCOMPtr<nsIInterfaceInfo> tmp(if_info);
287 tmp->GetParent(getter_AddRefs(if_info));
291 return NS_OK;
294 nsresult
295 nsScriptNameSpaceManager::RegisterInterface(const char* aIfName,
296 const nsIID *aIfIID,
297 bool* aFoundOld)
299 *aFoundOld = false;
301 nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aIfName);
302 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
304 if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
305 s->mType != nsGlobalNameStruct::eTypeNewDOMBinding) {
306 *aFoundOld = true;
308 return NS_OK;
311 s->mType = nsGlobalNameStruct::eTypeInterface;
312 s->mIID = *aIfIID;
314 return NS_OK;
317 #define GLOBALNAME_HASHTABLE_INITIAL_LENGTH 512
319 nsresult
320 nsScriptNameSpaceManager::Init()
322 static const PLDHashTableOps hash_table_ops =
324 PL_DHashAllocTable,
325 PL_DHashFreeTable,
326 GlobalNameHashHashKey,
327 GlobalNameHashMatchEntry,
328 PL_DHashMoveEntryStub,
329 GlobalNameHashClearEntry,
330 PL_DHashFinalizeStub,
331 GlobalNameHashInitEntry
334 mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops,
335 nullptr, sizeof(GlobalNameMapEntry),
336 fallible_t(),
337 GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
338 NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY);
340 mIsInitialized = PL_DHashTableInit(&mNavigatorNames, &hash_table_ops,
341 nullptr, sizeof(GlobalNameMapEntry),
342 fallible_t(),
343 GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
344 if (!mIsInitialized) {
345 PL_DHashTableFinish(&mGlobalNames);
347 return NS_ERROR_OUT_OF_MEMORY;
350 RegisterWeakMemoryReporter(this);
352 nsresult rv = NS_OK;
354 rv = RegisterExternalInterfaces(false);
355 NS_ENSURE_SUCCESS(rv, rv);
357 nsCOMPtr<nsICategoryManager> cm =
358 do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
359 NS_ENSURE_SUCCESS(rv, rv);
361 rv = FillHash(cm, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY);
362 NS_ENSURE_SUCCESS(rv, rv);
364 rv = FillHash(cm, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY);
365 NS_ENSURE_SUCCESS(rv, rv);
367 rv = FillHash(cm, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY);
368 NS_ENSURE_SUCCESS(rv, rv);
370 rv = FillHash(cm, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY);
371 NS_ENSURE_SUCCESS(rv, rv);
373 // Initial filling of the has table has been done.
374 // Now, listen for changes.
375 nsCOMPtr<nsIObserverService> serv =
376 mozilla::services::GetObserverService();
378 if (serv) {
379 serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, true);
380 serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID, true);
383 return NS_OK;
386 nsGlobalNameStruct*
387 nsScriptNameSpaceManager::LookupNameInternal(const nsAString& aName,
388 const char16_t **aClassName)
390 GlobalNameMapEntry *entry =
391 static_cast<GlobalNameMapEntry *>
392 (PL_DHashTableOperate(&mGlobalNames, &aName,
393 PL_DHASH_LOOKUP));
395 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
396 if (aClassName) {
397 *aClassName = entry->mKey.get();
399 return &entry->mGlobalName;
402 if (aClassName) {
403 *aClassName = nullptr;
405 return nullptr;
408 const nsGlobalNameStruct*
409 nsScriptNameSpaceManager::LookupNavigatorName(const nsAString& aName)
411 GlobalNameMapEntry *entry =
412 static_cast<GlobalNameMapEntry *>
413 (PL_DHashTableOperate(&mNavigatorNames, &aName,
414 PL_DHASH_LOOKUP));
416 if (!PL_DHASH_ENTRY_IS_BUSY(entry)) {
417 return nullptr;
420 return &entry->mGlobalName;
423 nsresult
424 nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
425 int32_t aDOMClassInfoID,
426 bool aPrivileged,
427 bool aXBLAllowed,
428 const char16_t **aResult)
430 if (!nsCRT::IsAscii(aClassName)) {
431 NS_ERROR("Trying to register a non-ASCII class name");
432 return NS_OK;
434 nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName, aResult);
435 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
437 if (s->mType == nsGlobalNameStruct::eTypeClassConstructor) {
438 return NS_OK;
441 // If a external constructor is already defined with aClassName we
442 // won't overwrite it.
444 if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
445 return NS_OK;
448 NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
449 s->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
450 s->mType == nsGlobalNameStruct::eTypeInterface,
451 "Whaaa, JS environment name clash!");
453 s->mType = nsGlobalNameStruct::eTypeClassConstructor;
454 s->mDOMClassInfoID = aDOMClassInfoID;
455 s->mChromeOnly = aPrivileged;
456 s->mAllowXBL = aXBLAllowed;
458 return NS_OK;
461 nsresult
462 nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName,
463 const nsIID *aConstructorProtoIID,
464 bool *aFoundOld)
466 NS_ENSURE_ARG_POINTER(aConstructorProtoIID);
468 *aFoundOld = false;
470 nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName);
471 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
473 if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
474 s->mType != nsGlobalNameStruct::eTypeNewDOMBinding &&
475 s->mType != nsGlobalNameStruct::eTypeInterface) {
476 *aFoundOld = true;
478 return NS_OK;
481 s->mType = nsGlobalNameStruct::eTypeClassProto;
482 s->mIID = *aConstructorProtoIID;
484 return NS_OK;
487 nsresult
488 nsScriptNameSpaceManager::RegisterExternalClassName(const char *aClassName,
489 nsCID& aCID)
491 nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName);
492 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
494 // If an external constructor is already defined with aClassName we
495 // won't overwrite it.
497 if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
498 return NS_OK;
501 NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
502 s->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
503 s->mType == nsGlobalNameStruct::eTypeInterface,
504 "Whaaa, JS environment name clash!");
506 s->mType = nsGlobalNameStruct::eTypeExternalClassInfoCreator;
507 s->mCID = aCID;
509 return NS_OK;
512 nsresult
513 nsScriptNameSpaceManager::RegisterDOMCIData(const char *aName,
514 nsDOMClassInfoExternalConstructorFnc aConstructorFptr,
515 const nsIID *aProtoChainInterface,
516 const nsIID **aInterfaces,
517 uint32_t aScriptableFlags,
518 bool aHasClassInterface,
519 const nsCID *aConstructorCID)
521 const char16_t* className;
522 nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aName, &className);
523 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
525 // If an external constructor is already defined with aClassName we
526 // won't overwrite it.
528 if (s->mType == nsGlobalNameStruct::eTypeClassConstructor ||
529 s->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
530 return NS_OK;
533 // XXX Should we bail out here?
534 NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
535 s->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
536 s->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator,
537 "Someone tries to register classinfo data for a class that isn't new or external!");
539 s->mData = new nsExternalDOMClassInfoData;
540 NS_ENSURE_TRUE(s->mData, NS_ERROR_OUT_OF_MEMORY);
542 s->mType = nsGlobalNameStruct::eTypeExternalClassInfo;
543 s->mData->mName = aName;
544 s->mData->mNameUTF16 = className;
545 if (aConstructorFptr)
546 s->mData->u.mExternalConstructorFptr = aConstructorFptr;
547 else
548 // null constructor will cause us to use nsDOMGenericSH::doCreate
549 s->mData->u.mExternalConstructorFptr = nullptr;
550 s->mData->mCachedClassInfo = nullptr;
551 s->mData->mProtoChainInterface = aProtoChainInterface;
552 s->mData->mInterfaces = aInterfaces;
553 s->mData->mScriptableFlags = aScriptableFlags;
554 s->mData->mHasClassInterface = aHasClassInterface;
555 s->mData->mConstructorCID = aConstructorCID;
557 return NS_OK;
560 nsresult
561 nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategoryManager,
562 const char* aCategory,
563 nsISupports* aEntry,
564 bool aRemove)
566 MOZ_ASSERT(aCategoryManager);
567 // Get the type from the category name.
568 // NOTE: we could have passed the type in FillHash() and guessed it in
569 // Observe() but this way, we have only one place to update and this is
570 // not performance sensitive.
571 nsGlobalNameStruct::nametype type;
572 if (strcmp(aCategory, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY) == 0) {
573 type = nsGlobalNameStruct::eTypeExternalConstructor;
574 } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY) == 0 ||
575 strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0) {
576 type = nsGlobalNameStruct::eTypeProperty;
577 } else if (strcmp(aCategory, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY) == 0) {
578 type = nsGlobalNameStruct::eTypeNavigatorProperty;
579 } else {
580 return NS_OK;
583 nsCOMPtr<nsISupportsCString> strWrapper = do_QueryInterface(aEntry);
585 if (!strWrapper) {
586 NS_WARNING("Category entry not an nsISupportsCString!");
587 return NS_OK;
590 nsAutoCString categoryEntry;
591 nsresult rv = strWrapper->GetData(categoryEntry);
592 NS_ENSURE_SUCCESS(rv, rv);
594 PLDHashTable *table;
595 if (type == nsGlobalNameStruct::eTypeNavigatorProperty) {
596 table = &mNavigatorNames;
597 } else {
598 table = &mGlobalNames;
601 // We need to handle removal before calling GetCategoryEntry
602 // because the category entry is already removed before we are
603 // notified.
604 if (aRemove) {
605 NS_ConvertASCIItoUTF16 entry(categoryEntry);
606 const nsGlobalNameStruct *s =
607 type == nsGlobalNameStruct::eTypeNavigatorProperty ?
608 LookupNavigatorName(entry) : LookupNameInternal(entry);
609 // Verify mType so that this API doesn't remove names
610 // registered by others.
611 if (!s || s->mType != type) {
612 return NS_OK;
615 RemoveFromHash(table, &entry);
616 return NS_OK;
619 nsXPIDLCString contractId;
620 rv = aCategoryManager->GetCategoryEntry(aCategory, categoryEntry.get(),
621 getter_Copies(contractId));
622 NS_ENSURE_SUCCESS(rv, rv);
624 if (type == nsGlobalNameStruct::eTypeNavigatorProperty ||
625 type == nsGlobalNameStruct::eTypeExternalConstructor) {
626 bool isNavProperty = type == nsGlobalNameStruct::eTypeNavigatorProperty;
627 nsPrintfCString prefName("dom.%s.disable.%s",
628 isNavProperty ? "navigator-property" : "global-constructor",
629 categoryEntry.get());
630 if (Preferences::GetType(prefName.get()) == nsIPrefBranch::PREF_BOOL &&
631 Preferences::GetBool(prefName.get(), false)) {
632 return NS_OK;
636 nsCOMPtr<nsIComponentRegistrar> registrar;
637 rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
638 NS_ENSURE_SUCCESS(rv, rv);
640 nsCID *cidPtr;
641 rv = registrar->ContractIDToCID(contractId, &cidPtr);
643 if (NS_FAILED(rv)) {
644 NS_WARNING("Bad contract id registed with the script namespace manager");
645 return NS_OK;
648 // Copy CID onto the stack, so we can free it right away and avoid having
649 // to add cleanup code at every exit point from this function.
650 nsCID cid = *cidPtr;
651 nsMemory::Free(cidPtr);
653 if (type == nsGlobalNameStruct::eTypeExternalConstructor) {
654 nsXPIDLCString constructorProto;
655 rv = aCategoryManager->GetCategoryEntry(JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY,
656 categoryEntry.get(),
657 getter_Copies(constructorProto));
658 if (NS_SUCCEEDED(rv)) {
659 nsGlobalNameStruct *s = AddToHash(&mGlobalNames, categoryEntry.get());
660 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
662 if (s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
663 s->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
664 s->mAlias = new nsGlobalNameStruct::ConstructorAlias;
665 s->mType = nsGlobalNameStruct::eTypeExternalConstructorAlias;
666 s->mChromeOnly = false;
667 s->mAlias->mCID = cid;
668 AppendASCIItoUTF16(constructorProto, s->mAlias->mProtoName);
669 s->mAlias->mProto = nullptr;
670 } else {
671 NS_WARNING("Global script name not overwritten!");
674 return NS_OK;
678 nsGlobalNameStruct *s = AddToHash(table, categoryEntry.get());
679 NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
681 if (s->mType == nsGlobalNameStruct::eTypeNotInitialized ||
682 s->mType == nsGlobalNameStruct::eTypeNewDOMBinding) {
683 s->mType = type;
684 s->mCID = cid;
685 s->mChromeOnly =
686 strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0;
687 } else {
688 NS_WARNING("Global script name not overwritten!");
691 return NS_OK;
694 nsresult
695 nsScriptNameSpaceManager::AddCategoryEntryToHash(nsICategoryManager* aCategoryManager,
696 const char* aCategory,
697 nsISupports* aEntry)
699 return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry,
700 /* aRemove = */ false);
703 nsresult
704 nsScriptNameSpaceManager::RemoveCategoryEntryFromHash(nsICategoryManager* aCategoryManager,
705 const char* aCategory,
706 nsISupports* aEntry)
708 return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry,
709 /* aRemove = */ true);
712 NS_IMETHODIMP
713 nsScriptNameSpaceManager::Observe(nsISupports* aSubject, const char* aTopic,
714 const char16_t* aData)
716 if (!aData) {
717 return NS_OK;
720 if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID)) {
721 nsCOMPtr<nsICategoryManager> cm =
722 do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
723 if (!cm) {
724 return NS_OK;
727 return AddCategoryEntryToHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
728 aSubject);
729 } else if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID)) {
730 nsCOMPtr<nsICategoryManager> cm =
731 do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
732 if (!cm) {
733 return NS_OK;
736 return RemoveCategoryEntryFromHash(cm, NS_ConvertUTF16toUTF8(aData).get(),
737 aSubject);
740 // TODO: we could observe NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID
741 // but we are safe without it. See bug 600460.
743 return NS_OK;
746 void
747 nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
748 mozilla::dom::DefineInterface aDefineDOMInterface,
749 mozilla::dom::ConstructorEnabled* aConstructorEnabled)
751 nsGlobalNameStruct *s = AddToHash(&mGlobalNames, &aName);
752 if (s) {
753 if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
754 s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
756 s->mDefineDOMInterface = aDefineDOMInterface;
757 s->mConstructorEnabled = aConstructorEnabled;
761 void
762 nsScriptNameSpaceManager::RegisterNavigatorDOMConstructor(
763 const nsAFlatString& aName,
764 mozilla::dom::ConstructNavigatorProperty aNavConstructor,
765 mozilla::dom::ConstructorEnabled* aConstructorEnabled)
767 nsGlobalNameStruct *s = AddToHash(&mNavigatorNames, &aName);
768 if (s) {
769 if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
770 s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
772 s->mConstructNavigatorProperty = aNavConstructor;
773 s->mConstructorEnabled = aConstructorEnabled;
777 struct NameClosure
779 nsScriptNameSpaceManager::NameEnumerator enumerator;
780 void* closure;
783 static PLDHashOperator
784 EnumerateName(PLDHashTable*, PLDHashEntryHdr *hdr, uint32_t, void* aClosure)
786 GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>(hdr);
787 NameClosure* closure = static_cast<NameClosure*>(aClosure);
788 return closure->enumerator(entry->mKey, entry->mGlobalName, closure->closure);
791 void
792 nsScriptNameSpaceManager::EnumerateGlobalNames(NameEnumerator aEnumerator,
793 void* aClosure)
795 NameClosure closure = { aEnumerator, aClosure };
796 PL_DHashTableEnumerate(&mGlobalNames, EnumerateName, &closure);
799 void
800 nsScriptNameSpaceManager::EnumerateNavigatorNames(NameEnumerator aEnumerator,
801 void* aClosure)
803 NameClosure closure = { aEnumerator, aClosure };
804 PL_DHashTableEnumerate(&mNavigatorNames, EnumerateName, &closure);
807 static size_t
808 SizeOfEntryExcludingThis(PLDHashEntryHdr *aHdr, MallocSizeOf aMallocSizeOf,
809 void *aArg)
811 GlobalNameMapEntry* entry = static_cast<GlobalNameMapEntry*>(aHdr);
812 return entry->SizeOfExcludingThis(aMallocSizeOf);
815 MOZ_DEFINE_MALLOC_SIZE_OF(ScriptNameSpaceManagerMallocSizeOf)
817 NS_IMETHODIMP
818 nsScriptNameSpaceManager::CollectReports(
819 nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
821 return MOZ_COLLECT_REPORT(
822 "explicit/script-namespace-manager", KIND_HEAP, UNITS_BYTES,
823 SizeOfIncludingThis(ScriptNameSpaceManagerMallocSizeOf),
824 "Memory used for the script namespace manager.");
827 size_t
828 nsScriptNameSpaceManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
830 size_t n = 0;
831 n += PL_DHashTableSizeOfExcludingThis(&mGlobalNames,
832 SizeOfEntryExcludingThis, aMallocSizeOf);
833 n += PL_DHashTableSizeOfExcludingThis(&mNavigatorNames,
834 SizeOfEntryExcludingThis, aMallocSizeOf);
835 return n;