Bumping manifests a=b2g-bump
[gecko.git] / js / xpconnect / src / XPCMaps.cpp
blob10e63d40f505bd9130bbd0f0aea9ea14b830c39e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
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 /* Private maps (hashtables). */
9 #include "mozilla/MathAlgorithms.h"
10 #include "mozilla/MemoryReporting.h"
11 #include "xpcprivate.h"
13 #include "js/HashTable.h"
15 using namespace mozilla;
17 /***************************************************************************/
18 // static shared...
20 // Note this is returning the bit pattern of the first part of the nsID, not
21 // the pointer to the nsID.
23 static PLDHashNumber
24 HashIIDPtrKey(PLDHashTable* table, const void* key)
26 return *((js::HashNumber*)key);
29 static bool
30 MatchIIDPtrKey(PLDHashTable* table,
31 const PLDHashEntryHdr* entry,
32 const void* key)
34 return ((const nsID*)key)->
35 Equals(*((const nsID*)((PLDHashEntryStub*)entry)->key));
38 static PLDHashNumber
39 HashNativeKey(PLDHashTable* table, const void* key)
41 XPCNativeSetKey* Key = (XPCNativeSetKey*) key;
43 PLDHashNumber h = 0;
45 XPCNativeSet* Set;
46 XPCNativeInterface* Addition;
47 uint16_t Position;
49 if (Key->IsAKey()) {
50 Set = Key->GetBaseSet();
51 Addition = Key->GetAddition();
52 Position = Key->GetPosition();
53 } else {
54 Set = (XPCNativeSet*) Key;
55 Addition = nullptr;
56 Position = 0;
59 if (!Set) {
60 MOZ_ASSERT(Addition, "bad key");
61 // This would be an XOR like below.
62 // But "0 ^ x == x". So it does not matter.
63 h = (js::HashNumber) NS_PTR_TO_INT32(Addition) >> 2;
64 } else {
65 XPCNativeInterface** Current = Set->GetInterfaceArray();
66 uint16_t count = Set->GetInterfaceCount();
67 if (Addition) {
68 count++;
69 for (uint16_t i = 0; i < count; i++) {
70 if (i == Position)
71 h ^= (js::HashNumber) NS_PTR_TO_INT32(Addition) >> 2;
72 else
73 h ^= (js::HashNumber) NS_PTR_TO_INT32(*(Current++)) >> 2;
75 } else {
76 for (uint16_t i = 0; i < count; i++)
77 h ^= (js::HashNumber) NS_PTR_TO_INT32(*(Current++)) >> 2;
81 return h;
84 /***************************************************************************/
85 // implement JSObject2WrappedJSMap...
87 void
88 JSObject2WrappedJSMap::FindDyingJSObjects(nsTArray<nsXPCWrappedJS*>* dying)
90 for (Map::Range r = mTable.all(); !r.empty(); r.popFront()) {
91 nsXPCWrappedJS* wrapper = r.front().value();
92 MOZ_ASSERT(wrapper, "found a null JS wrapper!");
94 // walk the wrapper chain and find any whose JSObject is to be finalized
95 while (wrapper) {
96 if (wrapper->IsSubjectToFinalization() && wrapper->IsObjectAboutToBeFinalized())
97 dying->AppendElement(wrapper);
98 wrapper = wrapper->GetNextWrapper();
103 void
104 JSObject2WrappedJSMap::ShutdownMarker()
106 for (Map::Range r = mTable.all(); !r.empty(); r.popFront()) {
107 nsXPCWrappedJS* wrapper = r.front().value();
108 MOZ_ASSERT(wrapper, "found a null JS wrapper!");
109 MOZ_ASSERT(wrapper->IsValid(), "found an invalid JS wrapper!");
110 wrapper->SystemIsBeingShutDown();
114 size_t
115 JSObject2WrappedJSMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
117 size_t n = mallocSizeOf(this);
118 n += mTable.sizeOfExcludingThis(mallocSizeOf);
119 return n;
122 size_t
123 JSObject2WrappedJSMap::SizeOfWrappedJS(mozilla::MallocSizeOf mallocSizeOf) const
125 size_t n = 0;
126 for (Map::Range r = mTable.all(); !r.empty(); r.popFront())
127 n += r.front().value()->SizeOfIncludingThis(mallocSizeOf);
128 return n;
131 /***************************************************************************/
132 // implement Native2WrappedNativeMap...
134 // static
135 Native2WrappedNativeMap*
136 Native2WrappedNativeMap::newMap(int length)
138 Native2WrappedNativeMap* map = new Native2WrappedNativeMap(length);
139 if (map && map->mTable)
140 return map;
141 // Allocation of the map or the creation of its hash table has
142 // failed. This will cause a nullptr deref later when we attempt
143 // to use the map, so we abort immediately to provide a more
144 // useful crash stack.
145 NS_RUNTIMEABORT("Ran out of memory.");
146 return nullptr;
149 Native2WrappedNativeMap::Native2WrappedNativeMap(int length)
151 mTable = PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
152 sizeof(Entry), length);
155 Native2WrappedNativeMap::~Native2WrappedNativeMap()
157 if (mTable)
158 PL_DHashTableDestroy(mTable);
161 size_t
162 Native2WrappedNativeMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
164 size_t n = 0;
165 n += mallocSizeOf(this);
166 n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
167 return n;
170 /* static */ size_t
171 Native2WrappedNativeMap::SizeOfEntryExcludingThis(PLDHashEntryHdr* hdr,
172 mozilla::MallocSizeOf mallocSizeOf, void*)
174 return mallocSizeOf(((Native2WrappedNativeMap::Entry*)hdr)->value);
177 /***************************************************************************/
178 // implement IID2WrappedJSClassMap...
180 const struct PLDHashTableOps IID2WrappedJSClassMap::Entry::sOps =
182 PL_DHashAllocTable,
183 PL_DHashFreeTable,
184 HashIIDPtrKey,
185 MatchIIDPtrKey,
186 PL_DHashMoveEntryStub,
187 PL_DHashClearEntryStub,
188 PL_DHashFinalizeStub
191 // static
192 IID2WrappedJSClassMap*
193 IID2WrappedJSClassMap::newMap(int length)
195 IID2WrappedJSClassMap* map = new IID2WrappedJSClassMap(length);
196 if (map && map->mTable)
197 return map;
198 delete map;
199 return nullptr;
202 IID2WrappedJSClassMap::IID2WrappedJSClassMap(int length)
204 mTable = PL_NewDHashTable(&Entry::sOps, nullptr, sizeof(Entry), length);
207 IID2WrappedJSClassMap::~IID2WrappedJSClassMap()
209 if (mTable)
210 PL_DHashTableDestroy(mTable);
214 /***************************************************************************/
215 // implement IID2NativeInterfaceMap...
217 const struct PLDHashTableOps IID2NativeInterfaceMap::Entry::sOps =
219 PL_DHashAllocTable,
220 PL_DHashFreeTable,
221 HashIIDPtrKey,
222 MatchIIDPtrKey,
223 PL_DHashMoveEntryStub,
224 PL_DHashClearEntryStub,
225 PL_DHashFinalizeStub
228 // static
229 IID2NativeInterfaceMap*
230 IID2NativeInterfaceMap::newMap(int length)
232 IID2NativeInterfaceMap* map = new IID2NativeInterfaceMap(length);
233 if (map && map->mTable)
234 return map;
235 delete map;
236 return nullptr;
239 IID2NativeInterfaceMap::IID2NativeInterfaceMap(int length)
241 mTable = PL_NewDHashTable(&Entry::sOps, nullptr, sizeof(Entry), length);
244 IID2NativeInterfaceMap::~IID2NativeInterfaceMap()
246 if (mTable)
247 PL_DHashTableDestroy(mTable);
250 size_t
251 IID2NativeInterfaceMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
253 size_t n = 0;
254 n += mallocSizeOf(this);
255 n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
256 return n;
259 /* static */ size_t
260 IID2NativeInterfaceMap::SizeOfEntryExcludingThis(PLDHashEntryHdr* hdr,
261 mozilla::MallocSizeOf mallocSizeOf, void*)
263 XPCNativeInterface* iface = ((IID2NativeInterfaceMap::Entry*)hdr)->value;
264 return iface->SizeOfIncludingThis(mallocSizeOf);
267 /***************************************************************************/
268 // implement ClassInfo2NativeSetMap...
270 // static
271 ClassInfo2NativeSetMap*
272 ClassInfo2NativeSetMap::newMap(int length)
274 ClassInfo2NativeSetMap* map = new ClassInfo2NativeSetMap(length);
275 if (map && map->mTable)
276 return map;
277 delete map;
278 return nullptr;
281 ClassInfo2NativeSetMap::ClassInfo2NativeSetMap(int length)
283 mTable = PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
284 sizeof(Entry), length);
287 ClassInfo2NativeSetMap::~ClassInfo2NativeSetMap()
289 if (mTable)
290 PL_DHashTableDestroy(mTable);
293 size_t
294 ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
296 size_t n = 0;
297 n += mallocSizeOf(this);
298 // The second arg is nullptr because this is a "shallow" measurement of the map.
299 n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, nullptr, mallocSizeOf) : 0;
300 return n;
303 /***************************************************************************/
304 // implement ClassInfo2WrappedNativeProtoMap...
306 // static
307 ClassInfo2WrappedNativeProtoMap*
308 ClassInfo2WrappedNativeProtoMap::newMap(int length)
310 ClassInfo2WrappedNativeProtoMap* map = new ClassInfo2WrappedNativeProtoMap(length);
311 if (map && map->mTable)
312 return map;
313 // Allocation of the map or the creation of its hash table has
314 // failed. This will cause a nullptr deref later when we attempt
315 // to use the map, so we abort immediately to provide a more
316 // useful crash stack.
317 NS_RUNTIMEABORT("Ran out of memory.");
318 return nullptr;
321 ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap(int length)
323 mTable = PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
324 sizeof(Entry), length);
327 ClassInfo2WrappedNativeProtoMap::~ClassInfo2WrappedNativeProtoMap()
329 if (mTable)
330 PL_DHashTableDestroy(mTable);
333 size_t
334 ClassInfo2WrappedNativeProtoMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
336 size_t n = 0;
337 n += mallocSizeOf(this);
338 n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
339 return n;
342 /* static */ size_t
343 ClassInfo2WrappedNativeProtoMap::SizeOfEntryExcludingThis(PLDHashEntryHdr* hdr,
344 mozilla::MallocSizeOf mallocSizeOf, void*)
346 return mallocSizeOf(((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value);
349 /***************************************************************************/
350 // implement NativeSetMap...
352 bool
353 NativeSetMap::Entry::Match(PLDHashTable* table,
354 const PLDHashEntryHdr* entry,
355 const void* key)
357 XPCNativeSetKey* Key = (XPCNativeSetKey*) key;
359 // See the comment in the XPCNativeSetKey declaration in xpcprivate.h.
360 if (!Key->IsAKey()) {
361 XPCNativeSet* Set1 = (XPCNativeSet*) key;
362 XPCNativeSet* Set2 = ((Entry*)entry)->key_value;
364 if (Set1 == Set2)
365 return true;
367 uint16_t count = Set1->GetInterfaceCount();
368 if (count != Set2->GetInterfaceCount())
369 return false;
371 XPCNativeInterface** Current1 = Set1->GetInterfaceArray();
372 XPCNativeInterface** Current2 = Set2->GetInterfaceArray();
373 for (uint16_t i = 0; i < count; i++) {
374 if (*(Current1++) != *(Current2++))
375 return false;
378 return true;
381 XPCNativeSet* SetInTable = ((Entry*)entry)->key_value;
382 XPCNativeSet* Set = Key->GetBaseSet();
383 XPCNativeInterface* Addition = Key->GetAddition();
385 if (!Set) {
386 // This is a special case to deal with the invariant that says:
387 // "All sets have exactly one nsISupports interface and it comes first."
388 // See XPCNativeSet::NewInstance for details.
390 // Though we might have a key that represents only one interface, we
391 // know that if that one interface were contructed into a set then
392 // it would end up really being a set with two interfaces (except for
393 // the case where the one interface happened to be nsISupports).
395 return (SetInTable->GetInterfaceCount() == 1 &&
396 SetInTable->GetInterfaceAt(0) == Addition) ||
397 (SetInTable->GetInterfaceCount() == 2 &&
398 SetInTable->GetInterfaceAt(1) == Addition);
401 if (!Addition && Set == SetInTable)
402 return true;
404 uint16_t count = Set->GetInterfaceCount() + (Addition ? 1 : 0);
405 if (count != SetInTable->GetInterfaceCount())
406 return false;
408 uint16_t Position = Key->GetPosition();
409 XPCNativeInterface** CurrentInTable = SetInTable->GetInterfaceArray();
410 XPCNativeInterface** Current = Set->GetInterfaceArray();
411 for (uint16_t i = 0; i < count; i++) {
412 if (Addition && i == Position) {
413 if (Addition != *(CurrentInTable++))
414 return false;
415 } else {
416 if (*(Current++) != *(CurrentInTable++))
417 return false;
421 return true;
424 const struct PLDHashTableOps NativeSetMap::Entry::sOps =
426 PL_DHashAllocTable,
427 PL_DHashFreeTable,
428 HashNativeKey,
429 Match,
430 PL_DHashMoveEntryStub,
431 PL_DHashClearEntryStub,
432 PL_DHashFinalizeStub
435 // static
436 NativeSetMap*
437 NativeSetMap::newMap(int length)
439 NativeSetMap* map = new NativeSetMap(length);
440 if (map && map->mTable)
441 return map;
442 delete map;
443 return nullptr;
446 NativeSetMap::NativeSetMap(int length)
448 mTable = PL_NewDHashTable(&Entry::sOps, nullptr, sizeof(Entry), length);
451 NativeSetMap::~NativeSetMap()
453 if (mTable)
454 PL_DHashTableDestroy(mTable);
457 size_t
458 NativeSetMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
460 size_t n = 0;
461 n += mallocSizeOf(this);
462 n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
463 return n;
466 /* static */ size_t
467 NativeSetMap::SizeOfEntryExcludingThis(PLDHashEntryHdr* hdr, mozilla::MallocSizeOf mallocSizeOf, void*)
469 XPCNativeSet* set = ((NativeSetMap::Entry*)hdr)->key_value;
470 return set->SizeOfIncludingThis(mallocSizeOf);
473 /***************************************************************************/
474 // implement IID2ThisTranslatorMap...
476 bool
477 IID2ThisTranslatorMap::Entry::Match(PLDHashTable* table,
478 const PLDHashEntryHdr* entry,
479 const void* key)
481 return ((const nsID*)key)->Equals(((Entry*)entry)->key);
484 void
485 IID2ThisTranslatorMap::Entry::Clear(PLDHashTable* table, PLDHashEntryHdr* entry)
487 static_cast<Entry*>(entry)->value = nullptr;
488 memset(entry, 0, table->EntrySize());
491 const struct PLDHashTableOps IID2ThisTranslatorMap::Entry::sOps =
493 PL_DHashAllocTable,
494 PL_DHashFreeTable,
495 HashIIDPtrKey,
496 Match,
497 PL_DHashMoveEntryStub,
498 Clear,
499 PL_DHashFinalizeStub
502 // static
503 IID2ThisTranslatorMap*
504 IID2ThisTranslatorMap::newMap(int length)
506 IID2ThisTranslatorMap* map = new IID2ThisTranslatorMap(length);
507 if (map && map->mTable)
508 return map;
509 delete map;
510 return nullptr;
513 IID2ThisTranslatorMap::IID2ThisTranslatorMap(int length)
515 mTable = PL_NewDHashTable(&Entry::sOps, nullptr, sizeof(Entry), length);
518 IID2ThisTranslatorMap::~IID2ThisTranslatorMap()
520 if (mTable)
521 PL_DHashTableDestroy(mTable);
524 /***************************************************************************/
526 PLDHashNumber
527 XPCNativeScriptableSharedMap::Entry::Hash(PLDHashTable* table, const void* key)
529 PLDHashNumber h;
530 const unsigned char* s;
532 XPCNativeScriptableShared* obj =
533 (XPCNativeScriptableShared*) key;
535 // hash together the flags and the classname string, ignore the interfaces
536 // bitmap since it's very rare that it's different when flags and classname
537 // are the same.
539 h = (PLDHashNumber) obj->GetFlags();
540 for (s = (const unsigned char*) obj->GetJSClass()->name; *s != '\0'; s++)
541 h = RotateLeft(h, 4) ^ *s;
542 return h;
545 bool
546 XPCNativeScriptableSharedMap::Entry::Match(PLDHashTable* table,
547 const PLDHashEntryHdr* entry,
548 const void* key)
550 XPCNativeScriptableShared* obj1 =
551 ((XPCNativeScriptableSharedMap::Entry*) entry)->key;
553 XPCNativeScriptableShared* obj2 =
554 (XPCNativeScriptableShared*) key;
556 // match the flags, the classname string and the interfaces bitmap
558 if (obj1->GetFlags() != obj2->GetFlags() ||
559 obj1->GetInterfacesBitmap() != obj2->GetInterfacesBitmap())
560 return false;
562 const char* name1 = obj1->GetJSClass()->name;
563 const char* name2 = obj2->GetJSClass()->name;
565 if (!name1 || !name2)
566 return name1 == name2;
568 return 0 == strcmp(name1, name2);
571 const struct PLDHashTableOps XPCNativeScriptableSharedMap::Entry::sOps =
573 PL_DHashAllocTable,
574 PL_DHashFreeTable,
575 Hash,
576 Match,
577 PL_DHashMoveEntryStub,
578 PL_DHashClearEntryStub,
579 PL_DHashFinalizeStub
582 // static
583 XPCNativeScriptableSharedMap*
584 XPCNativeScriptableSharedMap::newMap(int length)
586 XPCNativeScriptableSharedMap* map =
587 new XPCNativeScriptableSharedMap(length);
588 if (map && map->mTable)
589 return map;
590 delete map;
591 return nullptr;
594 XPCNativeScriptableSharedMap::XPCNativeScriptableSharedMap(int length)
596 mTable = PL_NewDHashTable(&Entry::sOps, nullptr, sizeof(Entry), length);
599 XPCNativeScriptableSharedMap::~XPCNativeScriptableSharedMap()
601 if (mTable)
602 PL_DHashTableDestroy(mTable);
605 bool
606 XPCNativeScriptableSharedMap::GetNewOrUsed(uint32_t flags,
607 char* name,
608 uint32_t interfacesBitmap,
609 XPCNativeScriptableInfo* si)
611 NS_PRECONDITION(name,"bad param");
612 NS_PRECONDITION(si,"bad param");
614 XPCNativeScriptableShared key(flags, name, interfacesBitmap);
615 Entry* entry = (Entry*)
616 PL_DHashTableOperate(mTable, &key, PL_DHASH_ADD);
617 if (!entry)
618 return false;
620 XPCNativeScriptableShared* shared = entry->key;
622 if (!shared) {
623 entry->key = shared =
624 new XPCNativeScriptableShared(flags, key.TransferNameOwnership(),
625 interfacesBitmap);
626 if (!shared)
627 return false;
628 shared->PopulateJSClass();
630 si->SetScriptableShared(shared);
631 return true;
634 /***************************************************************************/
635 // implement XPCWrappedNativeProtoMap...
637 // static
638 XPCWrappedNativeProtoMap*
639 XPCWrappedNativeProtoMap::newMap(int length)
641 XPCWrappedNativeProtoMap* map = new XPCWrappedNativeProtoMap(length);
642 if (map && map->mTable)
643 return map;
644 delete map;
645 return nullptr;
648 XPCWrappedNativeProtoMap::XPCWrappedNativeProtoMap(int length)
650 mTable = PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
651 sizeof(PLDHashEntryStub), length);
654 XPCWrappedNativeProtoMap::~XPCWrappedNativeProtoMap()
656 if (mTable)
657 PL_DHashTableDestroy(mTable);
660 /***************************************************************************/