1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/base/nsScriptNameSpaceManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,881 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsScriptNameSpaceManager.h" 1.11 +#include "nsCOMPtr.h" 1.12 +#include "nsIComponentManager.h" 1.13 +#include "nsIComponentRegistrar.h" 1.14 +#include "nsICategoryManager.h" 1.15 +#include "nsIServiceManager.h" 1.16 +#include "nsXPCOM.h" 1.17 +#include "nsISupportsPrimitives.h" 1.18 +#include "nsIScriptExternalNameSet.h" 1.19 +#include "nsIScriptNameSpaceManager.h" 1.20 +#include "nsIScriptContext.h" 1.21 +#include "nsIInterfaceInfoManager.h" 1.22 +#include "nsIInterfaceInfo.h" 1.23 +#include "xptinfo.h" 1.24 +#include "nsXPIDLString.h" 1.25 +#include "nsPrintfCString.h" 1.26 +#include "nsReadableUtils.h" 1.27 +#include "nsHashKeys.h" 1.28 +#include "nsDOMClassInfo.h" 1.29 +#include "nsCRT.h" 1.30 +#include "nsIObserverService.h" 1.31 +#include "nsISimpleEnumerator.h" 1.32 + 1.33 +#include "mozilla/MemoryReporting.h" 1.34 +#include "mozilla/Preferences.h" 1.35 +#include "mozilla/Services.h" 1.36 + 1.37 +#define NS_INTERFACE_PREFIX "nsI" 1.38 +#define NS_DOM_INTERFACE_PREFIX "nsIDOM" 1.39 + 1.40 +using namespace mozilla; 1.41 + 1.42 +// Our extended PLDHashEntryHdr 1.43 +class GlobalNameMapEntry : public PLDHashEntryHdr 1.44 +{ 1.45 +public: 1.46 + // Our hash table ops don't care about the order of these members 1.47 + nsString mKey; 1.48 + nsGlobalNameStruct mGlobalName; 1.49 + 1.50 + size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) { 1.51 + // Measurement of the following members may be added later if DMD finds it 1.52 + // is worthwhile: 1.53 + // - mGlobalName 1.54 + return mKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf); 1.55 + } 1.56 +}; 1.57 + 1.58 + 1.59 +static PLDHashNumber 1.60 +GlobalNameHashHashKey(PLDHashTable *table, const void *key) 1.61 +{ 1.62 + const nsAString *str = static_cast<const nsAString *>(key); 1.63 + return HashString(*str); 1.64 +} 1.65 + 1.66 +static bool 1.67 +GlobalNameHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry, 1.68 + const void *key) 1.69 +{ 1.70 + const GlobalNameMapEntry *e = 1.71 + static_cast<const GlobalNameMapEntry *>(entry); 1.72 + const nsAString *str = static_cast<const nsAString *>(key); 1.73 + 1.74 + return str->Equals(e->mKey); 1.75 +} 1.76 + 1.77 +static void 1.78 +GlobalNameHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) 1.79 +{ 1.80 + GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry); 1.81 + 1.82 + // An entry is being cleared, let the key (nsString) do its own 1.83 + // cleanup. 1.84 + e->mKey.~nsString(); 1.85 + if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalClassInfo) { 1.86 + nsIClassInfo* ci = GET_CLEAN_CI_PTR(e->mGlobalName.mData->mCachedClassInfo); 1.87 + 1.88 + // If we constructed an internal helper, we'll let the helper delete 1.89 + // the nsDOMClassInfoData structure, if not we do it here. 1.90 + if (!ci || e->mGlobalName.mData->u.mExternalConstructorFptr) { 1.91 + delete e->mGlobalName.mData; 1.92 + } 1.93 + 1.94 + // Release our pointer to the helper. 1.95 + NS_IF_RELEASE(ci); 1.96 + } 1.97 + else if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) { 1.98 + delete e->mGlobalName.mAlias; 1.99 + } 1.100 + 1.101 + // This will set e->mGlobalName.mType to 1.102 + // nsGlobalNameStruct::eTypeNotInitialized 1.103 + memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct)); 1.104 +} 1.105 + 1.106 +static bool 1.107 +GlobalNameHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, 1.108 + const void *key) 1.109 +{ 1.110 + GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry); 1.111 + const nsAString *keyStr = static_cast<const nsAString *>(key); 1.112 + 1.113 + // Initialize the key in the entry with placement new 1.114 + new (&e->mKey) nsString(*keyStr); 1.115 + 1.116 + // This will set e->mGlobalName.mType to 1.117 + // nsGlobalNameStruct::eTypeNotInitialized 1.118 + memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct)); 1.119 + return true; 1.120 +} 1.121 + 1.122 +NS_IMPL_ISUPPORTS( 1.123 + nsScriptNameSpaceManager, 1.124 + nsIObserver, 1.125 + nsISupportsWeakReference, 1.126 + nsIMemoryReporter) 1.127 + 1.128 +nsScriptNameSpaceManager::nsScriptNameSpaceManager() 1.129 + : mIsInitialized(false) 1.130 +{ 1.131 + MOZ_COUNT_CTOR(nsScriptNameSpaceManager); 1.132 +} 1.133 + 1.134 +nsScriptNameSpaceManager::~nsScriptNameSpaceManager() 1.135 +{ 1.136 + if (mIsInitialized) { 1.137 + UnregisterWeakMemoryReporter(this); 1.138 + // Destroy the hash 1.139 + PL_DHashTableFinish(&mGlobalNames); 1.140 + PL_DHashTableFinish(&mNavigatorNames); 1.141 + } 1.142 + MOZ_COUNT_DTOR(nsScriptNameSpaceManager); 1.143 +} 1.144 + 1.145 +nsGlobalNameStruct * 1.146 +nsScriptNameSpaceManager::AddToHash(PLDHashTable *aTable, const nsAString *aKey, 1.147 + const char16_t **aClassName) 1.148 +{ 1.149 + GlobalNameMapEntry *entry = 1.150 + static_cast<GlobalNameMapEntry *> 1.151 + (PL_DHashTableOperate(aTable, aKey, PL_DHASH_ADD)); 1.152 + 1.153 + if (!entry) { 1.154 + return nullptr; 1.155 + } 1.156 + 1.157 + if (aClassName) { 1.158 + *aClassName = entry->mKey.get(); 1.159 + } 1.160 + 1.161 + return &entry->mGlobalName; 1.162 +} 1.163 + 1.164 +void 1.165 +nsScriptNameSpaceManager::RemoveFromHash(PLDHashTable *aTable, 1.166 + const nsAString *aKey) 1.167 +{ 1.168 + PL_DHashTableOperate(aTable, aKey, PL_DHASH_REMOVE); 1.169 +} 1.170 + 1.171 +nsGlobalNameStruct* 1.172 +nsScriptNameSpaceManager::GetConstructorProto(const nsGlobalNameStruct* aStruct) 1.173 +{ 1.174 + NS_ASSERTION(aStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias, 1.175 + "This function only works on constructor aliases!"); 1.176 + if (!aStruct->mAlias->mProto) { 1.177 + GlobalNameMapEntry *proto = 1.178 + static_cast<GlobalNameMapEntry *> 1.179 + (PL_DHashTableOperate(&mGlobalNames, 1.180 + &aStruct->mAlias->mProtoName, 1.181 + PL_DHASH_LOOKUP)); 1.182 + 1.183 + if (PL_DHASH_ENTRY_IS_BUSY(proto)) { 1.184 + aStruct->mAlias->mProto = &proto->mGlobalName; 1.185 + } 1.186 + } 1.187 + return aStruct->mAlias->mProto; 1.188 +} 1.189 + 1.190 +nsresult 1.191 +nsScriptNameSpaceManager::FillHash(nsICategoryManager *aCategoryManager, 1.192 + const char *aCategory) 1.193 +{ 1.194 + nsCOMPtr<nsISimpleEnumerator> e; 1.195 + nsresult rv = aCategoryManager->EnumerateCategory(aCategory, 1.196 + getter_AddRefs(e)); 1.197 + NS_ENSURE_SUCCESS(rv, rv); 1.198 + 1.199 + nsCOMPtr<nsISupports> entry; 1.200 + while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) { 1.201 + rv = AddCategoryEntryToHash(aCategoryManager, aCategory, entry); 1.202 + if (NS_FAILED(rv)) { 1.203 + return rv; 1.204 + } 1.205 + } 1.206 + 1.207 + return NS_OK; 1.208 +} 1.209 + 1.210 + 1.211 +nsresult 1.212 +nsScriptNameSpaceManager::RegisterExternalInterfaces(bool aAsProto) 1.213 +{ 1.214 + nsresult rv; 1.215 + nsCOMPtr<nsICategoryManager> cm = 1.216 + do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv); 1.217 + NS_ENSURE_SUCCESS(rv, rv); 1.218 + 1.219 + nsCOMPtr<nsIInterfaceInfoManager> 1.220 + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); 1.221 + NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE); 1.222 + 1.223 + nsCOMPtr<nsISimpleEnumerator> enumerator; 1.224 + rv = cm->EnumerateCategory(JAVASCRIPT_DOM_INTERFACE, 1.225 + getter_AddRefs(enumerator)); 1.226 + NS_ENSURE_SUCCESS(rv, rv); 1.227 + 1.228 + nsXPIDLCString IID_string; 1.229 + nsAutoCString category_entry; 1.230 + const char* if_name; 1.231 + nsCOMPtr<nsISupports> entry; 1.232 + nsCOMPtr<nsIInterfaceInfo> if_info; 1.233 + bool found_old, dom_prefix; 1.234 + 1.235 + while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) { 1.236 + nsCOMPtr<nsISupportsCString> category(do_QueryInterface(entry)); 1.237 + 1.238 + if (!category) { 1.239 + NS_WARNING("Category entry not an nsISupportsCString!"); 1.240 + 1.241 + continue; 1.242 + } 1.243 + 1.244 + rv = category->GetData(category_entry); 1.245 + NS_ENSURE_SUCCESS(rv, rv); 1.246 + 1.247 + rv = cm->GetCategoryEntry(JAVASCRIPT_DOM_INTERFACE, category_entry.get(), 1.248 + getter_Copies(IID_string)); 1.249 + NS_ENSURE_SUCCESS(rv, rv); 1.250 + 1.251 + nsIID primary_IID; 1.252 + if (!primary_IID.Parse(IID_string) || 1.253 + primary_IID.Equals(NS_GET_IID(nsISupports))) { 1.254 + NS_ERROR("Invalid IID registered with the script namespace manager!"); 1.255 + continue; 1.256 + } 1.257 + 1.258 + iim->GetInfoForIID(&primary_IID, getter_AddRefs(if_info)); 1.259 + 1.260 + while (if_info) { 1.261 + const nsIID *iid; 1.262 + if_info->GetIIDShared(&iid); 1.263 + NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED); 1.264 + 1.265 + if (iid->Equals(NS_GET_IID(nsISupports))) { 1.266 + break; 1.267 + } 1.268 + 1.269 + if_info->GetNameShared(&if_name); 1.270 + dom_prefix = (strncmp(if_name, NS_DOM_INTERFACE_PREFIX, 1.271 + sizeof(NS_DOM_INTERFACE_PREFIX) - 1) == 0); 1.272 + 1.273 + const char* name; 1.274 + if (dom_prefix) { 1.275 + name = if_name + sizeof(NS_DOM_INTERFACE_PREFIX) - 1; 1.276 + } else { 1.277 + name = if_name + sizeof(NS_INTERFACE_PREFIX) - 1; 1.278 + } 1.279 + 1.280 + if (aAsProto) { 1.281 + RegisterClassProto(name, iid, &found_old); 1.282 + } else { 1.283 + RegisterInterface(name, iid, &found_old); 1.284 + } 1.285 + 1.286 + if (found_old) { 1.287 + break; 1.288 + } 1.289 + 1.290 + nsCOMPtr<nsIInterfaceInfo> tmp(if_info); 1.291 + tmp->GetParent(getter_AddRefs(if_info)); 1.292 + } 1.293 + } 1.294 + 1.295 + return NS_OK; 1.296 +} 1.297 + 1.298 +nsresult 1.299 +nsScriptNameSpaceManager::RegisterInterface(const char* aIfName, 1.300 + const nsIID *aIfIID, 1.301 + bool* aFoundOld) 1.302 +{ 1.303 + *aFoundOld = false; 1.304 + 1.305 + nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aIfName); 1.306 + NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY); 1.307 + 1.308 + if (s->mType != nsGlobalNameStruct::eTypeNotInitialized && 1.309 + s->mType != nsGlobalNameStruct::eTypeNewDOMBinding) { 1.310 + *aFoundOld = true; 1.311 + 1.312 + return NS_OK; 1.313 + } 1.314 + 1.315 + s->mType = nsGlobalNameStruct::eTypeInterface; 1.316 + s->mIID = *aIfIID; 1.317 + 1.318 + return NS_OK; 1.319 +} 1.320 + 1.321 +#define GLOBALNAME_HASHTABLE_INITIAL_SIZE 1024 1.322 + 1.323 +nsresult 1.324 +nsScriptNameSpaceManager::Init() 1.325 +{ 1.326 + static const PLDHashTableOps hash_table_ops = 1.327 + { 1.328 + PL_DHashAllocTable, 1.329 + PL_DHashFreeTable, 1.330 + GlobalNameHashHashKey, 1.331 + GlobalNameHashMatchEntry, 1.332 + PL_DHashMoveEntryStub, 1.333 + GlobalNameHashClearEntry, 1.334 + PL_DHashFinalizeStub, 1.335 + GlobalNameHashInitEntry 1.336 + }; 1.337 + 1.338 + mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops, 1.339 + nullptr, sizeof(GlobalNameMapEntry), 1.340 + GLOBALNAME_HASHTABLE_INITIAL_SIZE, 1.341 + fallible_t()); 1.342 + NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY); 1.343 + 1.344 + mIsInitialized = PL_DHashTableInit(&mNavigatorNames, &hash_table_ops, 1.345 + nullptr, sizeof(GlobalNameMapEntry), 1.346 + GLOBALNAME_HASHTABLE_INITIAL_SIZE, 1.347 + fallible_t()); 1.348 + if (!mIsInitialized) { 1.349 + PL_DHashTableFinish(&mGlobalNames); 1.350 + 1.351 + return NS_ERROR_OUT_OF_MEMORY; 1.352 + } 1.353 + 1.354 + RegisterWeakMemoryReporter(this); 1.355 + 1.356 + nsresult rv = NS_OK; 1.357 + 1.358 + rv = RegisterExternalInterfaces(false); 1.359 + NS_ENSURE_SUCCESS(rv, rv); 1.360 + 1.361 + nsCOMPtr<nsICategoryManager> cm = 1.362 + do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv); 1.363 + NS_ENSURE_SUCCESS(rv, rv); 1.364 + 1.365 + rv = FillHash(cm, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY); 1.366 + NS_ENSURE_SUCCESS(rv, rv); 1.367 + 1.368 + rv = FillHash(cm, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY); 1.369 + NS_ENSURE_SUCCESS(rv, rv); 1.370 + 1.371 + rv = FillHash(cm, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY); 1.372 + NS_ENSURE_SUCCESS(rv, rv); 1.373 + 1.374 + rv = FillHash(cm, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY); 1.375 + NS_ENSURE_SUCCESS(rv, rv); 1.376 + 1.377 + rv = FillHash(cm, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY); 1.378 + NS_ENSURE_SUCCESS(rv, rv); 1.379 + 1.380 + // Initial filling of the has table has been done. 1.381 + // Now, listen for changes. 1.382 + nsCOMPtr<nsIObserverService> serv = 1.383 + mozilla::services::GetObserverService(); 1.384 + 1.385 + if (serv) { 1.386 + serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, true); 1.387 + serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID, true); 1.388 + } 1.389 + 1.390 + return NS_OK; 1.391 +} 1.392 + 1.393 +struct NameSetClosure { 1.394 + nsIScriptContext* ctx; 1.395 + nsresult rv; 1.396 +}; 1.397 + 1.398 +static PLDHashOperator 1.399 +NameSetInitCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, 1.400 + uint32_t number, void *arg) 1.401 +{ 1.402 + GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>(hdr); 1.403 + 1.404 + if (entry->mGlobalName.mType == nsGlobalNameStruct::eTypeStaticNameSet) { 1.405 + nsresult rv = NS_OK; 1.406 + nsCOMPtr<nsIScriptExternalNameSet> ns = 1.407 + do_CreateInstance(entry->mGlobalName.mCID, &rv); 1.408 + NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT); 1.409 + 1.410 + NameSetClosure *closure = static_cast<NameSetClosure *>(arg); 1.411 + closure->rv = ns->InitializeNameSet(closure->ctx); 1.412 + if (NS_FAILED(closure->rv)) { 1.413 + NS_ERROR("Initing external script classes failed!"); 1.414 + return PL_DHASH_STOP; 1.415 + } 1.416 + } 1.417 + 1.418 + return PL_DHASH_NEXT; 1.419 +} 1.420 + 1.421 +nsresult 1.422 +nsScriptNameSpaceManager::InitForContext(nsIScriptContext *aContext) 1.423 +{ 1.424 + NameSetClosure closure; 1.425 + closure.ctx = aContext; 1.426 + closure.rv = NS_OK; 1.427 + PL_DHashTableEnumerate(&mGlobalNames, NameSetInitCallback, &closure); 1.428 + 1.429 + return closure.rv; 1.430 +} 1.431 + 1.432 +nsGlobalNameStruct* 1.433 +nsScriptNameSpaceManager::LookupNameInternal(const nsAString& aName, 1.434 + const char16_t **aClassName) 1.435 +{ 1.436 + GlobalNameMapEntry *entry = 1.437 + static_cast<GlobalNameMapEntry *> 1.438 + (PL_DHashTableOperate(&mGlobalNames, &aName, 1.439 + PL_DHASH_LOOKUP)); 1.440 + 1.441 + if (PL_DHASH_ENTRY_IS_BUSY(entry)) { 1.442 + if (aClassName) { 1.443 + *aClassName = entry->mKey.get(); 1.444 + } 1.445 + return &entry->mGlobalName; 1.446 + } 1.447 + 1.448 + if (aClassName) { 1.449 + *aClassName = nullptr; 1.450 + } 1.451 + return nullptr; 1.452 +} 1.453 + 1.454 +const nsGlobalNameStruct* 1.455 +nsScriptNameSpaceManager::LookupNavigatorName(const nsAString& aName) 1.456 +{ 1.457 + GlobalNameMapEntry *entry = 1.458 + static_cast<GlobalNameMapEntry *> 1.459 + (PL_DHashTableOperate(&mNavigatorNames, &aName, 1.460 + PL_DHASH_LOOKUP)); 1.461 + 1.462 + if (!PL_DHASH_ENTRY_IS_BUSY(entry)) { 1.463 + return nullptr; 1.464 + } 1.465 + 1.466 + return &entry->mGlobalName; 1.467 +} 1.468 + 1.469 +nsresult 1.470 +nsScriptNameSpaceManager::RegisterClassName(const char *aClassName, 1.471 + int32_t aDOMClassInfoID, 1.472 + bool aPrivileged, 1.473 + bool aXBLAllowed, 1.474 + const char16_t **aResult) 1.475 +{ 1.476 + if (!nsCRT::IsAscii(aClassName)) { 1.477 + NS_ERROR("Trying to register a non-ASCII class name"); 1.478 + return NS_OK; 1.479 + } 1.480 + nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName, aResult); 1.481 + NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY); 1.482 + 1.483 + if (s->mType == nsGlobalNameStruct::eTypeClassConstructor) { 1.484 + return NS_OK; 1.485 + } 1.486 + 1.487 + // If a external constructor is already defined with aClassName we 1.488 + // won't overwrite it. 1.489 + 1.490 + if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) { 1.491 + return NS_OK; 1.492 + } 1.493 + 1.494 + NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized || 1.495 + s->mType == nsGlobalNameStruct::eTypeNewDOMBinding || 1.496 + s->mType == nsGlobalNameStruct::eTypeInterface, 1.497 + "Whaaa, JS environment name clash!"); 1.498 + 1.499 + s->mType = nsGlobalNameStruct::eTypeClassConstructor; 1.500 + s->mDOMClassInfoID = aDOMClassInfoID; 1.501 + s->mChromeOnly = aPrivileged; 1.502 + s->mAllowXBL = aXBLAllowed; 1.503 + 1.504 + return NS_OK; 1.505 +} 1.506 + 1.507 +nsresult 1.508 +nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName, 1.509 + const nsIID *aConstructorProtoIID, 1.510 + bool *aFoundOld) 1.511 +{ 1.512 + NS_ENSURE_ARG_POINTER(aConstructorProtoIID); 1.513 + 1.514 + *aFoundOld = false; 1.515 + 1.516 + nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName); 1.517 + NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY); 1.518 + 1.519 + if (s->mType != nsGlobalNameStruct::eTypeNotInitialized && 1.520 + s->mType != nsGlobalNameStruct::eTypeNewDOMBinding && 1.521 + s->mType != nsGlobalNameStruct::eTypeInterface) { 1.522 + *aFoundOld = true; 1.523 + 1.524 + return NS_OK; 1.525 + } 1.526 + 1.527 + s->mType = nsGlobalNameStruct::eTypeClassProto; 1.528 + s->mIID = *aConstructorProtoIID; 1.529 + 1.530 + return NS_OK; 1.531 +} 1.532 + 1.533 +nsresult 1.534 +nsScriptNameSpaceManager::RegisterExternalClassName(const char *aClassName, 1.535 + nsCID& aCID) 1.536 +{ 1.537 + nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName); 1.538 + NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY); 1.539 + 1.540 + // If an external constructor is already defined with aClassName we 1.541 + // won't overwrite it. 1.542 + 1.543 + if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) { 1.544 + return NS_OK; 1.545 + } 1.546 + 1.547 + NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized || 1.548 + s->mType == nsGlobalNameStruct::eTypeNewDOMBinding || 1.549 + s->mType == nsGlobalNameStruct::eTypeInterface, 1.550 + "Whaaa, JS environment name clash!"); 1.551 + 1.552 + s->mType = nsGlobalNameStruct::eTypeExternalClassInfoCreator; 1.553 + s->mCID = aCID; 1.554 + 1.555 + return NS_OK; 1.556 +} 1.557 + 1.558 +nsresult 1.559 +nsScriptNameSpaceManager::RegisterDOMCIData(const char *aName, 1.560 + nsDOMClassInfoExternalConstructorFnc aConstructorFptr, 1.561 + const nsIID *aProtoChainInterface, 1.562 + const nsIID **aInterfaces, 1.563 + uint32_t aScriptableFlags, 1.564 + bool aHasClassInterface, 1.565 + const nsCID *aConstructorCID) 1.566 +{ 1.567 + const char16_t* className; 1.568 + nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aName, &className); 1.569 + NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY); 1.570 + 1.571 + // If an external constructor is already defined with aClassName we 1.572 + // won't overwrite it. 1.573 + 1.574 + if (s->mType == nsGlobalNameStruct::eTypeClassConstructor || 1.575 + s->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { 1.576 + return NS_OK; 1.577 + } 1.578 + 1.579 + // XXX Should we bail out here? 1.580 + NS_ASSERTION(s->mType == nsGlobalNameStruct::eTypeNotInitialized || 1.581 + s->mType == nsGlobalNameStruct::eTypeNewDOMBinding || 1.582 + s->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator, 1.583 + "Someone tries to register classinfo data for a class that isn't new or external!"); 1.584 + 1.585 + s->mData = new nsExternalDOMClassInfoData; 1.586 + NS_ENSURE_TRUE(s->mData, NS_ERROR_OUT_OF_MEMORY); 1.587 + 1.588 + s->mType = nsGlobalNameStruct::eTypeExternalClassInfo; 1.589 + s->mData->mName = aName; 1.590 + s->mData->mNameUTF16 = className; 1.591 + if (aConstructorFptr) 1.592 + s->mData->u.mExternalConstructorFptr = aConstructorFptr; 1.593 + else 1.594 + // null constructor will cause us to use nsDOMGenericSH::doCreate 1.595 + s->mData->u.mExternalConstructorFptr = nullptr; 1.596 + s->mData->mCachedClassInfo = nullptr; 1.597 + s->mData->mProtoChainInterface = aProtoChainInterface; 1.598 + s->mData->mInterfaces = aInterfaces; 1.599 + s->mData->mScriptableFlags = aScriptableFlags; 1.600 + s->mData->mHasClassInterface = aHasClassInterface; 1.601 + s->mData->mConstructorCID = aConstructorCID; 1.602 + 1.603 + return NS_OK; 1.604 +} 1.605 + 1.606 +nsresult 1.607 +nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategoryManager, 1.608 + const char* aCategory, 1.609 + nsISupports* aEntry, 1.610 + bool aRemove) 1.611 +{ 1.612 + MOZ_ASSERT(aCategoryManager); 1.613 + // Get the type from the category name. 1.614 + // NOTE: we could have passed the type in FillHash() and guessed it in 1.615 + // Observe() but this way, we have only one place to update and this is 1.616 + // not performance sensitive. 1.617 + nsGlobalNameStruct::nametype type; 1.618 + if (strcmp(aCategory, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY) == 0) { 1.619 + type = nsGlobalNameStruct::eTypeExternalConstructor; 1.620 + } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY) == 0 || 1.621 + strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0) { 1.622 + type = nsGlobalNameStruct::eTypeProperty; 1.623 + } else if (strcmp(aCategory, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY) == 0) { 1.624 + type = nsGlobalNameStruct::eTypeNavigatorProperty; 1.625 + } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY) == 0) { 1.626 + type = nsGlobalNameStruct::eTypeStaticNameSet; 1.627 + } else { 1.628 + return NS_OK; 1.629 + } 1.630 + 1.631 + nsCOMPtr<nsISupportsCString> strWrapper = do_QueryInterface(aEntry); 1.632 + 1.633 + if (!strWrapper) { 1.634 + NS_WARNING("Category entry not an nsISupportsCString!"); 1.635 + return NS_OK; 1.636 + } 1.637 + 1.638 + nsAutoCString categoryEntry; 1.639 + nsresult rv = strWrapper->GetData(categoryEntry); 1.640 + NS_ENSURE_SUCCESS(rv, rv); 1.641 + 1.642 + PLDHashTable *table; 1.643 + if (type == nsGlobalNameStruct::eTypeNavigatorProperty) { 1.644 + table = &mNavigatorNames; 1.645 + } else { 1.646 + table = &mGlobalNames; 1.647 + } 1.648 + 1.649 + // We need to handle removal before calling GetCategoryEntry 1.650 + // because the category entry is already removed before we are 1.651 + // notified. 1.652 + if (aRemove) { 1.653 + NS_ConvertASCIItoUTF16 entry(categoryEntry); 1.654 + const nsGlobalNameStruct *s = 1.655 + type == nsGlobalNameStruct::eTypeNavigatorProperty ? 1.656 + LookupNavigatorName(entry) : LookupNameInternal(entry); 1.657 + // Verify mType so that this API doesn't remove names 1.658 + // registered by others. 1.659 + if (!s || s->mType != type) { 1.660 + return NS_OK; 1.661 + } 1.662 + 1.663 + RemoveFromHash(table, &entry); 1.664 + return NS_OK; 1.665 + } 1.666 + 1.667 + nsXPIDLCString contractId; 1.668 + rv = aCategoryManager->GetCategoryEntry(aCategory, categoryEntry.get(), 1.669 + getter_Copies(contractId)); 1.670 + NS_ENSURE_SUCCESS(rv, rv); 1.671 + 1.672 + if (type == nsGlobalNameStruct::eTypeNavigatorProperty || 1.673 + type == nsGlobalNameStruct::eTypeExternalConstructor) { 1.674 + bool isNavProperty = type == nsGlobalNameStruct::eTypeNavigatorProperty; 1.675 + nsPrintfCString prefName("dom.%s.disable.%s", 1.676 + isNavProperty ? "navigator-property" : "global-constructor", 1.677 + categoryEntry.get()); 1.678 + if (Preferences::GetType(prefName.get()) == nsIPrefBranch::PREF_BOOL && 1.679 + Preferences::GetBool(prefName.get(), false)) { 1.680 + return NS_OK; 1.681 + } 1.682 + } 1.683 + 1.684 + nsCOMPtr<nsIComponentRegistrar> registrar; 1.685 + rv = NS_GetComponentRegistrar(getter_AddRefs(registrar)); 1.686 + NS_ENSURE_SUCCESS(rv, rv); 1.687 + 1.688 + nsCID *cidPtr; 1.689 + rv = registrar->ContractIDToCID(contractId, &cidPtr); 1.690 + 1.691 + if (NS_FAILED(rv)) { 1.692 + NS_WARNING("Bad contract id registed with the script namespace manager"); 1.693 + return NS_OK; 1.694 + } 1.695 + 1.696 + // Copy CID onto the stack, so we can free it right away and avoid having 1.697 + // to add cleanup code at every exit point from this function. 1.698 + nsCID cid = *cidPtr; 1.699 + nsMemory::Free(cidPtr); 1.700 + 1.701 + if (type == nsGlobalNameStruct::eTypeExternalConstructor) { 1.702 + nsXPIDLCString constructorProto; 1.703 + rv = aCategoryManager->GetCategoryEntry(JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY, 1.704 + categoryEntry.get(), 1.705 + getter_Copies(constructorProto)); 1.706 + if (NS_SUCCEEDED(rv)) { 1.707 + nsGlobalNameStruct *s = AddToHash(&mGlobalNames, categoryEntry.get()); 1.708 + NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY); 1.709 + 1.710 + if (s->mType == nsGlobalNameStruct::eTypeNotInitialized || 1.711 + s->mType == nsGlobalNameStruct::eTypeNewDOMBinding) { 1.712 + s->mAlias = new nsGlobalNameStruct::ConstructorAlias; 1.713 + s->mType = nsGlobalNameStruct::eTypeExternalConstructorAlias; 1.714 + s->mChromeOnly = false; 1.715 + s->mAlias->mCID = cid; 1.716 + AppendASCIItoUTF16(constructorProto, s->mAlias->mProtoName); 1.717 + s->mAlias->mProto = nullptr; 1.718 + } else { 1.719 + NS_WARNING("Global script name not overwritten!"); 1.720 + } 1.721 + 1.722 + return NS_OK; 1.723 + } 1.724 + } 1.725 + 1.726 + nsGlobalNameStruct *s = AddToHash(table, categoryEntry.get()); 1.727 + NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY); 1.728 + 1.729 + if (s->mType == nsGlobalNameStruct::eTypeNotInitialized || 1.730 + s->mType == nsGlobalNameStruct::eTypeNewDOMBinding) { 1.731 + s->mType = type; 1.732 + s->mCID = cid; 1.733 + s->mChromeOnly = 1.734 + strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0; 1.735 + } else { 1.736 + NS_WARNING("Global script name not overwritten!"); 1.737 + } 1.738 + 1.739 + return NS_OK; 1.740 +} 1.741 + 1.742 +nsresult 1.743 +nsScriptNameSpaceManager::AddCategoryEntryToHash(nsICategoryManager* aCategoryManager, 1.744 + const char* aCategory, 1.745 + nsISupports* aEntry) 1.746 +{ 1.747 + return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry, 1.748 + /* aRemove = */ false); 1.749 +} 1.750 + 1.751 +nsresult 1.752 +nsScriptNameSpaceManager::RemoveCategoryEntryFromHash(nsICategoryManager* aCategoryManager, 1.753 + const char* aCategory, 1.754 + nsISupports* aEntry) 1.755 +{ 1.756 + return OperateCategoryEntryHash(aCategoryManager, aCategory, aEntry, 1.757 + /* aRemove = */ true); 1.758 +} 1.759 + 1.760 +NS_IMETHODIMP 1.761 +nsScriptNameSpaceManager::Observe(nsISupports* aSubject, const char* aTopic, 1.762 + const char16_t* aData) 1.763 +{ 1.764 + if (!aData) { 1.765 + return NS_OK; 1.766 + } 1.767 + 1.768 + if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID)) { 1.769 + nsCOMPtr<nsICategoryManager> cm = 1.770 + do_GetService(NS_CATEGORYMANAGER_CONTRACTID); 1.771 + if (!cm) { 1.772 + return NS_OK; 1.773 + } 1.774 + 1.775 + return AddCategoryEntryToHash(cm, NS_ConvertUTF16toUTF8(aData).get(), 1.776 + aSubject); 1.777 + } else if (!strcmp(aTopic, NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID)) { 1.778 + nsCOMPtr<nsICategoryManager> cm = 1.779 + do_GetService(NS_CATEGORYMANAGER_CONTRACTID); 1.780 + if (!cm) { 1.781 + return NS_OK; 1.782 + } 1.783 + 1.784 + return RemoveCategoryEntryFromHash(cm, NS_ConvertUTF16toUTF8(aData).get(), 1.785 + aSubject); 1.786 + } 1.787 + 1.788 + // TODO: we could observe NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID 1.789 + // but we are safe without it. See bug 600460. 1.790 + 1.791 + return NS_OK; 1.792 +} 1.793 + 1.794 +void 1.795 +nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName, 1.796 + mozilla::dom::DefineInterface aDefineDOMInterface, 1.797 + mozilla::dom::ConstructorEnabled* aConstructorEnabled) 1.798 +{ 1.799 + nsGlobalNameStruct *s = AddToHash(&mGlobalNames, &aName); 1.800 + if (s) { 1.801 + if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) { 1.802 + s->mType = nsGlobalNameStruct::eTypeNewDOMBinding; 1.803 + } 1.804 + s->mDefineDOMInterface = aDefineDOMInterface; 1.805 + s->mConstructorEnabled = aConstructorEnabled; 1.806 + } 1.807 +} 1.808 + 1.809 +void 1.810 +nsScriptNameSpaceManager::RegisterNavigatorDOMConstructor( 1.811 + const nsAFlatString& aName, 1.812 + mozilla::dom::ConstructNavigatorProperty aNavConstructor, 1.813 + mozilla::dom::ConstructorEnabled* aConstructorEnabled) 1.814 +{ 1.815 + nsGlobalNameStruct *s = AddToHash(&mNavigatorNames, &aName); 1.816 + if (s) { 1.817 + if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) { 1.818 + s->mType = nsGlobalNameStruct::eTypeNewDOMBinding; 1.819 + } 1.820 + s->mConstructNavigatorProperty = aNavConstructor; 1.821 + s->mConstructorEnabled = aConstructorEnabled; 1.822 + } 1.823 +} 1.824 + 1.825 +struct NameClosure 1.826 +{ 1.827 + nsScriptNameSpaceManager::NameEnumerator enumerator; 1.828 + void* closure; 1.829 +}; 1.830 + 1.831 +static PLDHashOperator 1.832 +EnumerateName(PLDHashTable*, PLDHashEntryHdr *hdr, uint32_t, void* aClosure) 1.833 +{ 1.834 + GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>(hdr); 1.835 + NameClosure* closure = static_cast<NameClosure*>(aClosure); 1.836 + return closure->enumerator(entry->mKey, entry->mGlobalName, closure->closure); 1.837 +} 1.838 + 1.839 +void 1.840 +nsScriptNameSpaceManager::EnumerateGlobalNames(NameEnumerator aEnumerator, 1.841 + void* aClosure) 1.842 +{ 1.843 + NameClosure closure = { aEnumerator, aClosure }; 1.844 + PL_DHashTableEnumerate(&mGlobalNames, EnumerateName, &closure); 1.845 +} 1.846 + 1.847 +void 1.848 +nsScriptNameSpaceManager::EnumerateNavigatorNames(NameEnumerator aEnumerator, 1.849 + void* aClosure) 1.850 +{ 1.851 + NameClosure closure = { aEnumerator, aClosure }; 1.852 + PL_DHashTableEnumerate(&mNavigatorNames, EnumerateName, &closure); 1.853 +} 1.854 + 1.855 +static size_t 1.856 +SizeOfEntryExcludingThis(PLDHashEntryHdr *aHdr, MallocSizeOf aMallocSizeOf, 1.857 + void *aArg) 1.858 +{ 1.859 + GlobalNameMapEntry* entry = static_cast<GlobalNameMapEntry*>(aHdr); 1.860 + return entry->SizeOfExcludingThis(aMallocSizeOf); 1.861 +} 1.862 + 1.863 +MOZ_DEFINE_MALLOC_SIZE_OF(ScriptNameSpaceManagerMallocSizeOf) 1.864 + 1.865 +NS_IMETHODIMP 1.866 +nsScriptNameSpaceManager::CollectReports( 1.867 + nsIHandleReportCallback* aHandleReport, nsISupports* aData) 1.868 +{ 1.869 + return MOZ_COLLECT_REPORT( 1.870 + "explicit/script-namespace-manager", KIND_HEAP, UNITS_BYTES, 1.871 + SizeOfIncludingThis(ScriptNameSpaceManagerMallocSizeOf), 1.872 + "Memory used for the script namespace manager."); 1.873 +} 1.874 + 1.875 +size_t 1.876 +nsScriptNameSpaceManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) 1.877 +{ 1.878 + size_t n = 0; 1.879 + n += PL_DHashTableSizeOfExcludingThis(&mGlobalNames, 1.880 + SizeOfEntryExcludingThis, aMallocSizeOf); 1.881 + n += PL_DHashTableSizeOfExcludingThis(&mNavigatorNames, 1.882 + SizeOfEntryExcludingThis, aMallocSizeOf); 1.883 + return n; 1.884 +}