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). */
12 #include "mozilla/MemoryReporting.h"
17 // Note that most of the declarations for hash table entries begin with
18 // a pointer to something or another. This makes them look enough like
19 // the PLDHashEntryStub struct that the default OPs (PL_DHashGetStubOps())
20 // just do the right thing for most of our needs.
22 // no virtuals in the maps - all the common stuff inlined
23 // templates could be used to good effect here.
25 /*************************/
27 class JSObject2WrappedJSMap
29 typedef js::HashMap
<JSObject
*, nsXPCWrappedJS
*, js::PointerHasher
<JSObject
*, 3>,
30 js::SystemAllocPolicy
> Map
;
33 static JSObject2WrappedJSMap
* newMap(int length
) {
34 JSObject2WrappedJSMap
* map
= new JSObject2WrappedJSMap();
35 if (map
&& map
->mTable
.init(length
))
41 inline nsXPCWrappedJS
* Find(JSObject
* Obj
) {
42 NS_PRECONDITION(Obj
,"bad param");
43 Map::Ptr p
= mTable
.lookup(Obj
);
44 return p
? p
->value() : nullptr;
47 inline nsXPCWrappedJS
* Add(JSContext
* cx
, nsXPCWrappedJS
* wrapper
) {
48 NS_PRECONDITION(wrapper
,"bad param");
49 JSObject
* obj
= wrapper
->GetJSObjectPreserveColor();
50 Map::AddPtr p
= mTable
.lookupForAdd(obj
);
53 if (!mTable
.add(p
, obj
, wrapper
))
55 JS_StoreObjectPostBarrierCallback(cx
, KeyMarkCallback
, obj
, this);
59 inline void Remove(nsXPCWrappedJS
* wrapper
) {
60 NS_PRECONDITION(wrapper
,"bad param");
61 mTable
.remove(wrapper
->GetJSObjectPreserveColor());
64 inline uint32_t Count() {return mTable
.count();}
66 inline void Dump(int16_t depth
) {
67 for (Map::Range r
= mTable
.all(); !r
.empty(); r
.popFront())
68 r
.front().value()->DebugDump(depth
);
71 void FindDyingJSObjects(nsTArray
<nsXPCWrappedJS
*>* dying
);
73 void ShutdownMarker();
75 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
77 // Report the sum of SizeOfIncludingThis() for all wrapped JS in the map.
78 // Each wrapped JS is only in one map.
79 size_t SizeOfWrappedJS(mozilla::MallocSizeOf mallocSizeOf
) const;
82 JSObject2WrappedJSMap() {}
85 * This function is called during minor GCs for each key in the HashMap that
88 static void KeyMarkCallback(JSTracer
* trc
, JSObject
* key
, void* data
) {
89 JSObject2WrappedJSMap
* self
= static_cast<JSObject2WrappedJSMap
*>(data
);
90 JSObject
* prior
= key
;
91 JS_CallUnbarrieredObjectTracer(trc
, &key
, "XPCJSRuntime::mWrappedJSMap key");
92 self
->mTable
.rekeyIfMoved(prior
, key
);
98 /*************************/
100 class Native2WrappedNativeMap
103 struct Entry
: public PLDHashEntryHdr
106 XPCWrappedNative
* value
;
109 static Native2WrappedNativeMap
* newMap(int length
);
111 inline XPCWrappedNative
* Find(nsISupports
* Obj
)
113 NS_PRECONDITION(Obj
,"bad param");
114 Entry
* entry
= (Entry
*)
115 PL_DHashTableOperate(mTable
, Obj
, PL_DHASH_LOOKUP
);
116 if (PL_DHASH_ENTRY_IS_FREE(entry
))
121 inline XPCWrappedNative
* Add(XPCWrappedNative
* wrapper
)
123 NS_PRECONDITION(wrapper
,"bad param");
124 nsISupports
* obj
= wrapper
->GetIdentityObject();
125 MOZ_ASSERT(!Find(obj
), "wrapper already in new scope!");
126 Entry
* entry
= (Entry
*)
127 PL_DHashTableOperate(mTable
, obj
, PL_DHASH_ADD
);
133 entry
->value
= wrapper
;
137 inline void Remove(XPCWrappedNative
* wrapper
)
139 NS_PRECONDITION(wrapper
,"bad param");
141 XPCWrappedNative
* wrapperInMap
= Find(wrapper
->GetIdentityObject());
142 MOZ_ASSERT(!wrapperInMap
|| wrapperInMap
== wrapper
,
143 "About to remove a different wrapper with the same "
144 "nsISupports identity! This will most likely cause serious "
147 PL_DHashTableOperate(mTable
, wrapper
->GetIdentityObject(), PL_DHASH_REMOVE
);
150 inline uint32_t Count() { return mTable
->EntryCount(); }
151 inline uint32_t Enumerate(PLDHashEnumerator f
, void* arg
)
152 {return PL_DHashTableEnumerate(mTable
, f
, arg
);}
154 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
);
156 ~Native2WrappedNativeMap();
158 Native2WrappedNativeMap(); // no implementation
159 explicit Native2WrappedNativeMap(int size
);
161 static size_t SizeOfEntryExcludingThis(PLDHashEntryHdr
* hdr
, mozilla::MallocSizeOf mallocSizeOf
, void*);
164 PLDHashTable
* mTable
;
167 /*************************/
169 class IID2WrappedJSClassMap
172 struct Entry
: public PLDHashEntryHdr
175 nsXPCWrappedJSClass
* value
;
177 static const struct PLDHashTableOps sOps
;
180 static IID2WrappedJSClassMap
* newMap(int length
);
182 inline nsXPCWrappedJSClass
* Find(REFNSIID iid
)
184 Entry
* entry
= (Entry
*)
185 PL_DHashTableOperate(mTable
, &iid
, PL_DHASH_LOOKUP
);
186 if (PL_DHASH_ENTRY_IS_FREE(entry
))
191 inline nsXPCWrappedJSClass
* Add(nsXPCWrappedJSClass
* clazz
)
193 NS_PRECONDITION(clazz
,"bad param");
194 const nsIID
* iid
= &clazz
->GetIID();
195 Entry
* entry
= (Entry
*)
196 PL_DHashTableOperate(mTable
, iid
, PL_DHASH_ADD
);
202 entry
->value
= clazz
;
206 inline void Remove(nsXPCWrappedJSClass
* clazz
)
208 NS_PRECONDITION(clazz
,"bad param");
209 PL_DHashTableOperate(mTable
, &clazz
->GetIID(), PL_DHASH_REMOVE
);
212 inline uint32_t Count() { return mTable
->EntryCount(); }
213 inline uint32_t Enumerate(PLDHashEnumerator f
, void* arg
)
214 {return PL_DHashTableEnumerate(mTable
, f
, arg
);}
216 ~IID2WrappedJSClassMap();
218 IID2WrappedJSClassMap(); // no implementation
219 explicit IID2WrappedJSClassMap(int size
);
221 PLDHashTable
* mTable
;
224 /*************************/
226 class IID2NativeInterfaceMap
229 struct Entry
: public PLDHashEntryHdr
232 XPCNativeInterface
* value
;
234 static const struct PLDHashTableOps sOps
;
237 static IID2NativeInterfaceMap
* newMap(int length
);
239 inline XPCNativeInterface
* Find(REFNSIID iid
)
241 Entry
* entry
= (Entry
*)
242 PL_DHashTableOperate(mTable
, &iid
, PL_DHASH_LOOKUP
);
243 if (PL_DHASH_ENTRY_IS_FREE(entry
))
248 inline XPCNativeInterface
* Add(XPCNativeInterface
* iface
)
250 NS_PRECONDITION(iface
,"bad param");
251 const nsIID
* iid
= iface
->GetIID();
252 Entry
* entry
= (Entry
*)
253 PL_DHashTableOperate(mTable
, iid
, PL_DHASH_ADD
);
259 entry
->value
= iface
;
263 inline void Remove(XPCNativeInterface
* iface
)
265 NS_PRECONDITION(iface
,"bad param");
266 PL_DHashTableOperate(mTable
, iface
->GetIID(), PL_DHASH_REMOVE
);
269 inline uint32_t Count() { return mTable
->EntryCount(); }
270 inline uint32_t Enumerate(PLDHashEnumerator f
, void* arg
)
271 {return PL_DHashTableEnumerate(mTable
, f
, arg
);}
273 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
);
275 ~IID2NativeInterfaceMap();
277 IID2NativeInterfaceMap(); // no implementation
278 explicit IID2NativeInterfaceMap(int size
);
280 static size_t SizeOfEntryExcludingThis(PLDHashEntryHdr
* hdr
, mozilla::MallocSizeOf mallocSizeOf
, void*);
283 PLDHashTable
* mTable
;
286 /*************************/
288 class ClassInfo2NativeSetMap
291 struct Entry
: public PLDHashEntryHdr
297 static ClassInfo2NativeSetMap
* newMap(int length
);
299 inline XPCNativeSet
* Find(nsIClassInfo
* info
)
301 Entry
* entry
= (Entry
*)
302 PL_DHashTableOperate(mTable
, info
, PL_DHASH_LOOKUP
);
303 if (PL_DHASH_ENTRY_IS_FREE(entry
))
308 inline XPCNativeSet
* Add(nsIClassInfo
* info
, XPCNativeSet
* set
)
310 NS_PRECONDITION(info
,"bad param");
311 Entry
* entry
= (Entry
*)
312 PL_DHashTableOperate(mTable
, info
, PL_DHASH_ADD
);
322 inline void Remove(nsIClassInfo
* info
)
324 NS_PRECONDITION(info
,"bad param");
325 PL_DHashTableOperate(mTable
, info
, PL_DHASH_REMOVE
);
328 inline uint32_t Count() { return mTable
->EntryCount(); }
329 inline uint32_t Enumerate(PLDHashEnumerator f
, void* arg
)
330 {return PL_DHashTableEnumerate(mTable
, f
, arg
);}
332 // ClassInfo2NativeSetMap holds pointers to *some* XPCNativeSets.
333 // So we don't want to count those XPCNativeSets, because they are better
334 // counted elsewhere (i.e. in XPCJSRuntime::mNativeSetMap, which holds
335 // pointers to *all* XPCNativeSets). Hence the "Shallow".
336 size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
);
338 ~ClassInfo2NativeSetMap();
340 ClassInfo2NativeSetMap(); // no implementation
341 explicit ClassInfo2NativeSetMap(int size
);
343 PLDHashTable
* mTable
;
346 /*************************/
348 class ClassInfo2WrappedNativeProtoMap
351 struct Entry
: public PLDHashEntryHdr
354 XPCWrappedNativeProto
* value
;
357 static ClassInfo2WrappedNativeProtoMap
* newMap(int length
);
359 inline XPCWrappedNativeProto
* Find(nsIClassInfo
* info
)
361 Entry
* entry
= (Entry
*)
362 PL_DHashTableOperate(mTable
, info
, PL_DHASH_LOOKUP
);
363 if (PL_DHASH_ENTRY_IS_FREE(entry
))
368 inline XPCWrappedNativeProto
* Add(nsIClassInfo
* info
, XPCWrappedNativeProto
* proto
)
370 NS_PRECONDITION(info
,"bad param");
371 Entry
* entry
= (Entry
*)
372 PL_DHashTableOperate(mTable
, info
, PL_DHASH_ADD
);
378 entry
->value
= proto
;
382 inline void Remove(nsIClassInfo
* info
)
384 NS_PRECONDITION(info
,"bad param");
385 PL_DHashTableOperate(mTable
, info
, PL_DHASH_REMOVE
);
388 inline uint32_t Count() { return mTable
->EntryCount(); }
389 inline uint32_t Enumerate(PLDHashEnumerator f
, void* arg
)
390 {return PL_DHashTableEnumerate(mTable
, f
, arg
);}
392 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
);
394 ~ClassInfo2WrappedNativeProtoMap();
396 ClassInfo2WrappedNativeProtoMap(); // no implementation
397 explicit ClassInfo2WrappedNativeProtoMap(int size
);
399 static size_t SizeOfEntryExcludingThis(PLDHashEntryHdr
* hdr
, mozilla::MallocSizeOf mallocSizeOf
, void*);
402 PLDHashTable
* mTable
;
405 /*************************/
410 struct Entry
: public PLDHashEntryHdr
412 XPCNativeSet
* key_value
;
415 Match(PLDHashTable
* table
,
416 const PLDHashEntryHdr
* entry
,
419 static const struct PLDHashTableOps sOps
;
422 static NativeSetMap
* newMap(int length
);
424 inline XPCNativeSet
* Find(XPCNativeSetKey
* key
)
426 Entry
* entry
= (Entry
*)
427 PL_DHashTableOperate(mTable
, key
, PL_DHASH_LOOKUP
);
428 if (PL_DHASH_ENTRY_IS_FREE(entry
))
430 return entry
->key_value
;
433 inline XPCNativeSet
* Add(const XPCNativeSetKey
* key
, XPCNativeSet
* set
)
435 NS_PRECONDITION(key
,"bad param");
436 NS_PRECONDITION(set
,"bad param");
437 Entry
* entry
= (Entry
*)
438 PL_DHashTableOperate(mTable
, key
, PL_DHASH_ADD
);
441 if (entry
->key_value
)
442 return entry
->key_value
;
443 entry
->key_value
= set
;
447 inline XPCNativeSet
* Add(XPCNativeSet
* set
)
449 XPCNativeSetKey
key(set
, nullptr, 0);
450 return Add(&key
, set
);
453 inline void Remove(XPCNativeSet
* set
)
455 NS_PRECONDITION(set
,"bad param");
457 XPCNativeSetKey
key(set
, nullptr, 0);
458 PL_DHashTableOperate(mTable
, &key
, PL_DHASH_REMOVE
);
461 inline uint32_t Count() { return mTable
->EntryCount(); }
462 inline uint32_t Enumerate(PLDHashEnumerator f
, void* arg
)
463 {return PL_DHashTableEnumerate(mTable
, f
, arg
);}
465 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
);
469 NativeSetMap(); // no implementation
470 explicit NativeSetMap(int size
);
472 static size_t SizeOfEntryExcludingThis(PLDHashEntryHdr
* hdr
, mozilla::MallocSizeOf mallocSizeOf
, void*);
475 PLDHashTable
* mTable
;
478 /***************************************************************************/
480 class IID2ThisTranslatorMap
483 struct Entry
: public PLDHashEntryHdr
486 nsCOMPtr
<nsIXPCFunctionThisTranslator
> value
;
489 Match(PLDHashTable
* table
,
490 const PLDHashEntryHdr
* entry
,
494 Clear(PLDHashTable
* table
, PLDHashEntryHdr
* entry
);
496 static const struct PLDHashTableOps sOps
;
499 static IID2ThisTranslatorMap
* newMap(int length
);
501 inline nsIXPCFunctionThisTranslator
* Find(REFNSIID iid
)
503 Entry
* entry
= (Entry
*)
504 PL_DHashTableOperate(mTable
, &iid
, PL_DHASH_LOOKUP
);
505 if (PL_DHASH_ENTRY_IS_FREE(entry
))
510 inline nsIXPCFunctionThisTranslator
* Add(REFNSIID iid
,
511 nsIXPCFunctionThisTranslator
* obj
)
514 Entry
* entry
= (Entry
*)
515 PL_DHashTableOperate(mTable
, &iid
, PL_DHASH_ADD
);
523 inline void Remove(REFNSIID iid
)
525 PL_DHashTableOperate(mTable
, &iid
, PL_DHASH_REMOVE
);
528 inline uint32_t Count() { return mTable
->EntryCount(); }
529 inline uint32_t Enumerate(PLDHashEnumerator f
, void* arg
)
530 {return PL_DHashTableEnumerate(mTable
, f
, arg
);}
532 ~IID2ThisTranslatorMap();
534 IID2ThisTranslatorMap(); // no implementation
535 explicit IID2ThisTranslatorMap(int size
);
537 PLDHashTable
* mTable
;
540 /***************************************************************************/
542 class XPCNativeScriptableSharedMap
545 struct Entry
: public PLDHashEntryHdr
547 XPCNativeScriptableShared
* key
;
550 Hash(PLDHashTable
* table
, const void* key
);
553 Match(PLDHashTable
* table
,
554 const PLDHashEntryHdr
* entry
,
557 static const struct PLDHashTableOps sOps
;
560 static XPCNativeScriptableSharedMap
* newMap(int length
);
562 bool GetNewOrUsed(uint32_t flags
, char* name
, uint32_t interfacesBitmap
,
563 XPCNativeScriptableInfo
* si
);
565 inline uint32_t Count() { return mTable
->EntryCount(); }
566 inline uint32_t Enumerate(PLDHashEnumerator f
, void* arg
)
567 {return PL_DHashTableEnumerate(mTable
, f
, arg
);}
569 ~XPCNativeScriptableSharedMap();
571 XPCNativeScriptableSharedMap(); // no implementation
572 explicit XPCNativeScriptableSharedMap(int size
);
574 PLDHashTable
* mTable
;
577 /***************************************************************************/
579 class XPCWrappedNativeProtoMap
582 static XPCWrappedNativeProtoMap
* newMap(int length
);
584 inline XPCWrappedNativeProto
* Add(XPCWrappedNativeProto
* proto
)
586 NS_PRECONDITION(proto
,"bad param");
587 PLDHashEntryStub
* entry
= (PLDHashEntryStub
*)
588 PL_DHashTableOperate(mTable
, proto
, PL_DHASH_ADD
);
592 return (XPCWrappedNativeProto
*) entry
->key
;
597 inline void Remove(XPCWrappedNativeProto
* proto
)
599 NS_PRECONDITION(proto
,"bad param");
600 PL_DHashTableOperate(mTable
, proto
, PL_DHASH_REMOVE
);
603 inline uint32_t Count() { return mTable
->EntryCount(); }
604 inline uint32_t Enumerate(PLDHashEnumerator f
, void* arg
)
605 {return PL_DHashTableEnumerate(mTable
, f
, arg
);}
607 ~XPCWrappedNativeProtoMap();
609 XPCWrappedNativeProtoMap(); // no implementation
610 explicit XPCWrappedNativeProtoMap(int size
);
612 PLDHashTable
* mTable
;
615 /***************************************************************************/
617 class JSObject2JSObjectMap
619 typedef js::HashMap
<JSObject
*, JS::Heap
<JSObject
*>, js::PointerHasher
<JSObject
*, 3>,
620 js::SystemAllocPolicy
> Map
;
623 static JSObject2JSObjectMap
* newMap(int length
) {
624 JSObject2JSObjectMap
* map
= new JSObject2JSObjectMap();
625 if (map
&& map
->mTable
.init(length
))
631 inline JSObject
* Find(JSObject
* key
) {
632 NS_PRECONDITION(key
, "bad param");
633 if (Map::Ptr p
= mTable
.lookup(key
))
638 /* Note: If the entry already exists, return the old value. */
639 inline JSObject
* Add(JSContext
* cx
, JSObject
* key
, JSObject
* value
) {
640 NS_PRECONDITION(key
,"bad param");
641 Map::AddPtr p
= mTable
.lookupForAdd(key
);
644 if (!mTable
.add(p
, key
, value
))
646 MOZ_ASSERT(xpc::CompartmentPrivate::Get(key
)->scope
->mWaiverWrapperMap
== this);
647 JS_StoreObjectPostBarrierCallback(cx
, KeyMarkCallback
, key
, this);
651 inline void Remove(JSObject
* key
) {
652 NS_PRECONDITION(key
,"bad param");
656 inline uint32_t Count() { return mTable
.count(); }
659 for (Map::Enum
e(mTable
); !e
.empty(); e
.popFront()) {
660 JSObject
* updated
= e
.front().key();
661 if (JS_IsAboutToBeFinalizedUnbarriered(&updated
) || JS_IsAboutToBeFinalized(&e
.front().value()))
663 else if (updated
!= e
.front().key())
664 e
.rekeyFront(updated
);
668 void Reparent(JSContext
* aCx
, JSObject
* aNewInnerArg
) {
669 JS::RootedObject
aNewInner(aCx
, aNewInnerArg
);
670 for (Map::Enum
e(mTable
); !e
.empty(); e
.popFront()) {
672 * We reparent wrappers that have as their parent an inner window
673 * whose outer has the new inner window as its current inner.
675 JS::RootedObject
wrapper(aCx
, e
.front().value());
676 JS::RootedObject
parent(aCx
, JS_GetParent(wrapper
));
677 JS::RootedObject
outer(aCx
, JS_ObjectToOuterObject(aCx
, parent
));
679 JSObject
* inner
= JS_ObjectToInnerObject(aCx
, outer
);
680 if (inner
== aNewInner
&& inner
!= parent
)
681 JS_SetParent(aCx
, wrapper
, aNewInner
);
683 JS_ClearPendingException(aCx
);
689 JSObject2JSObjectMap() {}
692 * This function is called during minor GCs for each key in the HashMap that
695 static void KeyMarkCallback(JSTracer
* trc
, JSObject
* key
, void* data
) {
697 * To stop the barriers on the values of mTable firing while we are
698 * marking the store buffer, we cast the table to one that is
699 * binary-equivatlent but without the barriers, and update that.
701 typedef js::HashMap
<JSObject
*, JSObject
*, js::PointerHasher
<JSObject
*, 3>,
702 js::SystemAllocPolicy
> UnbarrieredMap
;
703 JSObject2JSObjectMap
* self
= static_cast<JSObject2JSObjectMap
*>(data
);
704 UnbarrieredMap
& table
= reinterpret_cast<UnbarrieredMap
&>(self
->mTable
);
706 JSObject
* prior
= key
;
707 JS_CallUnbarrieredObjectTracer(trc
, &key
, "XPCWrappedNativeScope::mWaiverWrapperMap key");
708 table
.rekeyIfMoved(prior
, key
);
714 #endif /* xpcmaps_h___ */