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 /***************************************************************************/
20 // Note this is returning the bit pattern of the first part of the nsID, not
21 // the pointer to the nsID.
24 HashIIDPtrKey(PLDHashTable
* table
, const void* key
)
26 return *((js::HashNumber
*)key
);
30 MatchIIDPtrKey(PLDHashTable
* table
,
31 const PLDHashEntryHdr
* entry
,
34 return ((const nsID
*)key
)->
35 Equals(*((const nsID
*)((PLDHashEntryStub
*)entry
)->key
));
39 HashNativeKey(PLDHashTable
* table
, const void* key
)
41 XPCNativeSetKey
* Key
= (XPCNativeSetKey
*) key
;
46 XPCNativeInterface
* Addition
;
50 Set
= Key
->GetBaseSet();
51 Addition
= Key
->GetAddition();
52 Position
= Key
->GetPosition();
54 Set
= (XPCNativeSet
*) Key
;
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;
65 XPCNativeInterface
** Current
= Set
->GetInterfaceArray();
66 uint16_t count
= Set
->GetInterfaceCount();
69 for (uint16_t i
= 0; i
< count
; i
++) {
71 h
^= (js::HashNumber
) NS_PTR_TO_INT32(Addition
) >> 2;
73 h
^= (js::HashNumber
) NS_PTR_TO_INT32(*(Current
++)) >> 2;
76 for (uint16_t i
= 0; i
< count
; i
++)
77 h
^= (js::HashNumber
) NS_PTR_TO_INT32(*(Current
++)) >> 2;
84 /***************************************************************************/
85 // implement JSObject2WrappedJSMap...
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
96 if (wrapper
->IsSubjectToFinalization() && wrapper
->IsObjectAboutToBeFinalized())
97 dying
->AppendElement(wrapper
);
98 wrapper
= wrapper
->GetNextWrapper();
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();
115 JSObject2WrappedJSMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const
117 size_t n
= mallocSizeOf(this);
118 n
+= mTable
.sizeOfExcludingThis(mallocSizeOf
);
123 JSObject2WrappedJSMap::SizeOfWrappedJS(mozilla::MallocSizeOf mallocSizeOf
) const
126 for (Map::Range r
= mTable
.all(); !r
.empty(); r
.popFront())
127 n
+= r
.front().value()->SizeOfIncludingThis(mallocSizeOf
);
131 /***************************************************************************/
132 // implement Native2WrappedNativeMap...
135 Native2WrappedNativeMap
*
136 Native2WrappedNativeMap::newMap(int length
)
138 Native2WrappedNativeMap
* map
= new Native2WrappedNativeMap(length
);
139 if (map
&& map
->mTable
)
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.");
149 Native2WrappedNativeMap::Native2WrappedNativeMap(int length
)
151 mTable
= PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
152 sizeof(Entry
), length
);
155 Native2WrappedNativeMap::~Native2WrappedNativeMap()
158 PL_DHashTableDestroy(mTable
);
162 Native2WrappedNativeMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
)
165 n
+= mallocSizeOf(this);
166 n
+= mTable
? PL_DHashTableSizeOfIncludingThis(mTable
, SizeOfEntryExcludingThis
, mallocSizeOf
) : 0;
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
=
186 PL_DHashMoveEntryStub
,
187 PL_DHashClearEntryStub
,
192 IID2WrappedJSClassMap
*
193 IID2WrappedJSClassMap::newMap(int length
)
195 IID2WrappedJSClassMap
* map
= new IID2WrappedJSClassMap(length
);
196 if (map
&& map
->mTable
)
202 IID2WrappedJSClassMap::IID2WrappedJSClassMap(int length
)
204 mTable
= PL_NewDHashTable(&Entry::sOps
, nullptr, sizeof(Entry
), length
);
207 IID2WrappedJSClassMap::~IID2WrappedJSClassMap()
210 PL_DHashTableDestroy(mTable
);
214 /***************************************************************************/
215 // implement IID2NativeInterfaceMap...
217 const struct PLDHashTableOps
IID2NativeInterfaceMap::Entry::sOps
=
223 PL_DHashMoveEntryStub
,
224 PL_DHashClearEntryStub
,
229 IID2NativeInterfaceMap
*
230 IID2NativeInterfaceMap::newMap(int length
)
232 IID2NativeInterfaceMap
* map
= new IID2NativeInterfaceMap(length
);
233 if (map
&& map
->mTable
)
239 IID2NativeInterfaceMap::IID2NativeInterfaceMap(int length
)
241 mTable
= PL_NewDHashTable(&Entry::sOps
, nullptr, sizeof(Entry
), length
);
244 IID2NativeInterfaceMap::~IID2NativeInterfaceMap()
247 PL_DHashTableDestroy(mTable
);
251 IID2NativeInterfaceMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
)
254 n
+= mallocSizeOf(this);
255 n
+= mTable
? PL_DHashTableSizeOfIncludingThis(mTable
, SizeOfEntryExcludingThis
, mallocSizeOf
) : 0;
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...
271 ClassInfo2NativeSetMap
*
272 ClassInfo2NativeSetMap::newMap(int length
)
274 ClassInfo2NativeSetMap
* map
= new ClassInfo2NativeSetMap(length
);
275 if (map
&& map
->mTable
)
281 ClassInfo2NativeSetMap::ClassInfo2NativeSetMap(int length
)
283 mTable
= PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
284 sizeof(Entry
), length
);
287 ClassInfo2NativeSetMap::~ClassInfo2NativeSetMap()
290 PL_DHashTableDestroy(mTable
);
294 ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
)
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;
303 /***************************************************************************/
304 // implement ClassInfo2WrappedNativeProtoMap...
307 ClassInfo2WrappedNativeProtoMap
*
308 ClassInfo2WrappedNativeProtoMap::newMap(int length
)
310 ClassInfo2WrappedNativeProtoMap
* map
= new ClassInfo2WrappedNativeProtoMap(length
);
311 if (map
&& map
->mTable
)
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.");
321 ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap(int length
)
323 mTable
= PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
324 sizeof(Entry
), length
);
327 ClassInfo2WrappedNativeProtoMap::~ClassInfo2WrappedNativeProtoMap()
330 PL_DHashTableDestroy(mTable
);
334 ClassInfo2WrappedNativeProtoMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
)
337 n
+= mallocSizeOf(this);
338 n
+= mTable
? PL_DHashTableSizeOfIncludingThis(mTable
, SizeOfEntryExcludingThis
, mallocSizeOf
) : 0;
343 ClassInfo2WrappedNativeProtoMap::SizeOfEntryExcludingThis(PLDHashEntryHdr
* hdr
,
344 mozilla::MallocSizeOf mallocSizeOf
, void*)
346 return mallocSizeOf(((ClassInfo2WrappedNativeProtoMap::Entry
*)hdr
)->value
);
349 /***************************************************************************/
350 // implement NativeSetMap...
353 NativeSetMap::Entry::Match(PLDHashTable
* table
,
354 const PLDHashEntryHdr
* entry
,
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
;
367 uint16_t count
= Set1
->GetInterfaceCount();
368 if (count
!= Set2
->GetInterfaceCount())
371 XPCNativeInterface
** Current1
= Set1
->GetInterfaceArray();
372 XPCNativeInterface
** Current2
= Set2
->GetInterfaceArray();
373 for (uint16_t i
= 0; i
< count
; i
++) {
374 if (*(Current1
++) != *(Current2
++))
381 XPCNativeSet
* SetInTable
= ((Entry
*)entry
)->key_value
;
382 XPCNativeSet
* Set
= Key
->GetBaseSet();
383 XPCNativeInterface
* Addition
= Key
->GetAddition();
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
)
404 uint16_t count
= Set
->GetInterfaceCount() + (Addition
? 1 : 0);
405 if (count
!= SetInTable
->GetInterfaceCount())
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
++))
416 if (*(Current
++) != *(CurrentInTable
++))
424 const struct PLDHashTableOps
NativeSetMap::Entry::sOps
=
430 PL_DHashMoveEntryStub
,
431 PL_DHashClearEntryStub
,
437 NativeSetMap::newMap(int length
)
439 NativeSetMap
* map
= new NativeSetMap(length
);
440 if (map
&& map
->mTable
)
446 NativeSetMap::NativeSetMap(int length
)
448 mTable
= PL_NewDHashTable(&Entry::sOps
, nullptr, sizeof(Entry
), length
);
451 NativeSetMap::~NativeSetMap()
454 PL_DHashTableDestroy(mTable
);
458 NativeSetMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
)
461 n
+= mallocSizeOf(this);
462 n
+= mTable
? PL_DHashTableSizeOfIncludingThis(mTable
, SizeOfEntryExcludingThis
, mallocSizeOf
) : 0;
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...
477 IID2ThisTranslatorMap::Entry::Match(PLDHashTable
* table
,
478 const PLDHashEntryHdr
* entry
,
481 return ((const nsID
*)key
)->Equals(((Entry
*)entry
)->key
);
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
=
497 PL_DHashMoveEntryStub
,
503 IID2ThisTranslatorMap
*
504 IID2ThisTranslatorMap::newMap(int length
)
506 IID2ThisTranslatorMap
* map
= new IID2ThisTranslatorMap(length
);
507 if (map
&& map
->mTable
)
513 IID2ThisTranslatorMap::IID2ThisTranslatorMap(int length
)
515 mTable
= PL_NewDHashTable(&Entry::sOps
, nullptr, sizeof(Entry
), length
);
518 IID2ThisTranslatorMap::~IID2ThisTranslatorMap()
521 PL_DHashTableDestroy(mTable
);
524 /***************************************************************************/
527 XPCNativeScriptableSharedMap::Entry::Hash(PLDHashTable
* table
, const void* key
)
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
539 h
= (PLDHashNumber
) obj
->GetFlags();
540 for (s
= (const unsigned char*) obj
->GetJSClass()->name
; *s
!= '\0'; s
++)
541 h
= RotateLeft(h
, 4) ^ *s
;
546 XPCNativeScriptableSharedMap::Entry::Match(PLDHashTable
* table
,
547 const PLDHashEntryHdr
* entry
,
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())
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
=
577 PL_DHashMoveEntryStub
,
578 PL_DHashClearEntryStub
,
583 XPCNativeScriptableSharedMap
*
584 XPCNativeScriptableSharedMap::newMap(int length
)
586 XPCNativeScriptableSharedMap
* map
=
587 new XPCNativeScriptableSharedMap(length
);
588 if (map
&& map
->mTable
)
594 XPCNativeScriptableSharedMap::XPCNativeScriptableSharedMap(int length
)
596 mTable
= PL_NewDHashTable(&Entry::sOps
, nullptr, sizeof(Entry
), length
);
599 XPCNativeScriptableSharedMap::~XPCNativeScriptableSharedMap()
602 PL_DHashTableDestroy(mTable
);
606 XPCNativeScriptableSharedMap::GetNewOrUsed(uint32_t flags
,
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
);
620 XPCNativeScriptableShared
* shared
= entry
->key
;
623 entry
->key
= shared
=
624 new XPCNativeScriptableShared(flags
, key
.TransferNameOwnership(),
628 shared
->PopulateJSClass();
630 si
->SetScriptableShared(shared
);
634 /***************************************************************************/
635 // implement XPCWrappedNativeProtoMap...
638 XPCWrappedNativeProtoMap
*
639 XPCWrappedNativeProtoMap::newMap(int length
)
641 XPCWrappedNativeProtoMap
* map
= new XPCWrappedNativeProtoMap(length
);
642 if (map
&& map
->mTable
)
648 XPCWrappedNativeProtoMap::XPCWrappedNativeProtoMap(int length
)
650 mTable
= PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
651 sizeof(PLDHashEntryStub
), length
);
654 XPCWrappedNativeProtoMap::~XPCWrappedNativeProtoMap()
657 PL_DHashTableDestroy(mTable
);
660 /***************************************************************************/