dom/base/nsScriptNameSpaceManager.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial