Line data Source code
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/. */
6 :
7 : /* Private maps (hashtables). */
8 :
9 : #ifndef xpcmaps_h___
10 : #define xpcmaps_h___
11 :
12 : #include "mozilla/MemoryReporting.h"
13 :
14 : #include "js/GCHashTable.h"
15 :
16 : // Maps...
17 :
18 : // Note that most of the declarations for hash table entries begin with
19 : // a pointer to something or another. This makes them look enough like
20 : // the PLDHashEntryStub struct that the default ops (PLDHashTable::StubOps())
21 : // just do the right thing for most of our needs.
22 :
23 : // no virtuals in the maps - all the common stuff inlined
24 : // templates could be used to good effect here.
25 :
26 : /*************************/
27 :
28 0 : class JSObject2WrappedJSMap
29 : {
30 : using Map = js::HashMap<JS::Heap<JSObject*>,
31 : nsXPCWrappedJS*,
32 : js::MovableCellHasher<JS::Heap<JSObject*>>,
33 : InfallibleAllocPolicy>;
34 :
35 : public:
36 296 : static JSObject2WrappedJSMap* newMap(int length) {
37 296 : auto* map = new JSObject2WrappedJSMap();
38 296 : if (!map->mTable.init(length)) {
39 : // This is a decent estimate of the size of the hash table's
40 : // entry storage. The |2| is because on average the capacity is
41 : // twice the requested length.
42 0 : NS_ABORT_OOM(length * 2 * sizeof(Map::Entry));
43 : }
44 296 : return map;
45 : }
46 :
47 2556 : inline nsXPCWrappedJS* Find(JSObject* Obj) {
48 2556 : NS_PRECONDITION(Obj,"bad param");
49 2556 : Map::Ptr p = mTable.lookup(Obj);
50 2556 : return p ? p->value() : nullptr;
51 : }
52 :
53 : #ifdef DEBUG
54 49203 : inline bool HasWrapper(nsXPCWrappedJS* wrapper) {
55 136983 : for (auto r = mTable.all(); !r.empty(); r.popFront()) {
56 87780 : if (r.front().value() == wrapper)
57 0 : return true;
58 : }
59 49203 : return false;
60 : }
61 : #endif
62 :
63 844 : inline nsXPCWrappedJS* Add(JSContext* cx, nsXPCWrappedJS* wrapper) {
64 844 : NS_PRECONDITION(wrapper,"bad param");
65 844 : JSObject* obj = wrapper->GetJSObjectPreserveColor();
66 844 : Map::AddPtr p = mTable.lookupForAdd(obj);
67 844 : if (p)
68 8 : return p->value();
69 836 : if (!mTable.add(p, obj, wrapper))
70 0 : return nullptr;
71 836 : return wrapper;
72 : }
73 :
74 536 : inline void Remove(nsXPCWrappedJS* wrapper) {
75 536 : NS_PRECONDITION(wrapper,"bad param");
76 536 : mTable.remove(wrapper->GetJSObjectPreserveColor());
77 536 : }
78 :
79 0 : inline uint32_t Count() {return mTable.count();}
80 :
81 0 : inline void Dump(int16_t depth) {
82 0 : for (Map::Range r = mTable.all(); !r.empty(); r.popFront())
83 0 : r.front().value()->DebugDump(depth);
84 0 : }
85 :
86 : void UpdateWeakPointersAfterGC();
87 :
88 : void ShutdownMarker();
89 :
90 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
91 :
92 : // Report the sum of SizeOfIncludingThis() for all wrapped JS in the map.
93 : // Each wrapped JS is only in one map.
94 : size_t SizeOfWrappedJS(mozilla::MallocSizeOf mallocSizeOf) const;
95 :
96 : private:
97 296 : JSObject2WrappedJSMap() {}
98 :
99 : Map mTable;
100 : };
101 :
102 : /*************************/
103 :
104 0 : class Native2WrappedNativeMap
105 : {
106 : public:
107 : struct Entry : public PLDHashEntryHdr
108 : {
109 : nsISupports* key;
110 : XPCWrappedNative* value;
111 : };
112 :
113 : static Native2WrappedNativeMap* newMap(int length);
114 :
115 14050 : inline XPCWrappedNative* Find(nsISupports* Obj)
116 : {
117 14050 : NS_PRECONDITION(Obj,"bad param");
118 14050 : auto entry = static_cast<Entry*>(mTable.Search(Obj));
119 14050 : return entry ? entry->value : nullptr;
120 : }
121 :
122 5711 : inline XPCWrappedNative* Add(XPCWrappedNative* wrapper)
123 : {
124 5711 : NS_PRECONDITION(wrapper,"bad param");
125 5711 : nsISupports* obj = wrapper->GetIdentityObject();
126 5711 : MOZ_ASSERT(!Find(obj), "wrapper already in new scope!");
127 5711 : auto entry = static_cast<Entry*>(mTable.Add(obj, mozilla::fallible));
128 5711 : if (!entry)
129 0 : return nullptr;
130 5711 : if (entry->key)
131 0 : return entry->value;
132 5711 : entry->key = obj;
133 5711 : entry->value = wrapper;
134 5711 : return wrapper;
135 : }
136 :
137 : inline void Remove(XPCWrappedNative* wrapper)
138 : {
139 : NS_PRECONDITION(wrapper,"bad param");
140 : #ifdef DEBUG
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 "
145 : "problems!");
146 : #endif
147 : mTable.Remove(wrapper->GetIdentityObject());
148 : }
149 :
150 0 : inline void Clear() { mTable.Clear(); }
151 :
152 0 : inline uint32_t Count() { return mTable.EntryCount(); }
153 :
154 211 : PLDHashTable::Iterator Iter() { return mTable.Iter(); }
155 :
156 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
157 :
158 : private:
159 : Native2WrappedNativeMap(); // no implementation
160 : explicit Native2WrappedNativeMap(int size);
161 :
162 : private:
163 : PLDHashTable mTable;
164 : };
165 :
166 : /*************************/
167 :
168 0 : class IID2WrappedJSClassMap
169 : {
170 : public:
171 : struct Entry : public PLDHashEntryHdr
172 : {
173 : const nsIID* key;
174 : nsXPCWrappedJSClass* value;
175 :
176 : static const struct PLDHashTableOps sOps;
177 : };
178 :
179 : static IID2WrappedJSClassMap* newMap(int length);
180 :
181 1415 : inline nsXPCWrappedJSClass* Find(REFNSIID iid)
182 : {
183 1415 : auto entry = static_cast<Entry*>(mTable.Search(&iid));
184 1415 : return entry ? entry->value : nullptr;
185 : }
186 :
187 92 : inline nsXPCWrappedJSClass* Add(nsXPCWrappedJSClass* clazz)
188 : {
189 92 : NS_PRECONDITION(clazz,"bad param");
190 92 : const nsIID* iid = &clazz->GetIID();
191 92 : auto entry = static_cast<Entry*>(mTable.Add(iid, mozilla::fallible));
192 92 : if (!entry)
193 0 : return nullptr;
194 92 : if (entry->key)
195 0 : return entry->value;
196 92 : entry->key = iid;
197 92 : entry->value = clazz;
198 92 : return clazz;
199 : }
200 :
201 25 : inline void Remove(nsXPCWrappedJSClass* clazz)
202 : {
203 25 : NS_PRECONDITION(clazz,"bad param");
204 25 : mTable.Remove(&clazz->GetIID());
205 25 : }
206 :
207 0 : inline uint32_t Count() { return mTable.EntryCount(); }
208 :
209 : #ifdef DEBUG
210 0 : PLDHashTable::Iterator Iter() { return mTable.Iter(); }
211 : #endif
212 :
213 : private:
214 : IID2WrappedJSClassMap(); // no implementation
215 : explicit IID2WrappedJSClassMap(int size);
216 : private:
217 : PLDHashTable mTable;
218 : };
219 :
220 : /*************************/
221 :
222 0 : class IID2NativeInterfaceMap
223 : {
224 : public:
225 : struct Entry : public PLDHashEntryHdr
226 : {
227 : const nsIID* key;
228 : XPCNativeInterface* value;
229 :
230 : static const struct PLDHashTableOps sOps;
231 : };
232 :
233 : static IID2NativeInterfaceMap* newMap(int length);
234 :
235 15396 : inline XPCNativeInterface* Find(REFNSIID iid)
236 : {
237 15396 : auto entry = static_cast<Entry*>(mTable.Search(&iid));
238 15396 : return entry ? entry->value : nullptr;
239 : }
240 :
241 1825 : inline XPCNativeInterface* Add(XPCNativeInterface* iface)
242 : {
243 1825 : NS_PRECONDITION(iface,"bad param");
244 1825 : const nsIID* iid = iface->GetIID();
245 1825 : auto entry = static_cast<Entry*>(mTable.Add(iid, mozilla::fallible));
246 1825 : if (!entry)
247 0 : return nullptr;
248 1825 : if (entry->key)
249 0 : return entry->value;
250 1825 : entry->key = iid;
251 1825 : entry->value = iface;
252 1825 : return iface;
253 : }
254 :
255 1557 : inline void Remove(XPCNativeInterface* iface)
256 : {
257 1557 : NS_PRECONDITION(iface,"bad param");
258 1557 : mTable.Remove(iface->GetIID());
259 1557 : }
260 :
261 0 : inline uint32_t Count() { return mTable.EntryCount(); }
262 :
263 : PLDHashTable::Iterator Iter() { return mTable.Iter(); }
264 :
265 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
266 :
267 : private:
268 : IID2NativeInterfaceMap(); // no implementation
269 : explicit IID2NativeInterfaceMap(int size);
270 :
271 : private:
272 : PLDHashTable mTable;
273 : };
274 :
275 : /*************************/
276 :
277 0 : class ClassInfo2NativeSetMap
278 : {
279 : public:
280 : struct Entry : public PLDHashEntryHdr
281 : {
282 : nsIClassInfo* key;
283 : XPCNativeSet* value; // strong reference
284 : static const PLDHashTableOps sOps;
285 :
286 : private:
287 : static bool Match(const PLDHashEntryHdr* aEntry, const void* aKey);
288 : static void Clear(PLDHashTable* aTable, PLDHashEntryHdr* aEntry);
289 : };
290 :
291 : static ClassInfo2NativeSetMap* newMap(int length);
292 :
293 1824 : inline XPCNativeSet* Find(nsIClassInfo* info)
294 : {
295 1824 : auto entry = static_cast<Entry*>(mTable.Search(info));
296 1824 : return entry ? entry->value : nullptr;
297 : }
298 :
299 1069 : inline XPCNativeSet* Add(nsIClassInfo* info, XPCNativeSet* set)
300 : {
301 1069 : NS_PRECONDITION(info,"bad param");
302 1069 : auto entry = static_cast<Entry*>(mTable.Add(info, mozilla::fallible));
303 1069 : if (!entry)
304 0 : return nullptr;
305 1069 : if (entry->key)
306 0 : return entry->value;
307 1069 : entry->key = info;
308 1069 : NS_ADDREF(entry->value = set);
309 1069 : return set;
310 : }
311 :
312 0 : inline void Remove(nsIClassInfo* info)
313 : {
314 0 : NS_PRECONDITION(info,"bad param");
315 0 : mTable.Remove(info);
316 0 : }
317 :
318 0 : inline uint32_t Count() { return mTable.EntryCount(); }
319 :
320 : // ClassInfo2NativeSetMap holds pointers to *some* XPCNativeSets.
321 : // So we don't want to count those XPCNativeSets, because they are better
322 : // counted elsewhere (i.e. in XPCJSContext::mNativeSetMap, which holds
323 : // pointers to *all* XPCNativeSets). Hence the "Shallow".
324 : size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
325 :
326 : private:
327 : ClassInfo2NativeSetMap(); // no implementation
328 : explicit ClassInfo2NativeSetMap(int size);
329 : private:
330 : PLDHashTable mTable;
331 : };
332 :
333 : /*************************/
334 :
335 0 : class ClassInfo2WrappedNativeProtoMap
336 : {
337 : public:
338 : struct Entry : public PLDHashEntryHdr
339 : {
340 : nsIClassInfo* key;
341 : XPCWrappedNativeProto* value;
342 : };
343 :
344 : static ClassInfo2WrappedNativeProtoMap* newMap(int length);
345 :
346 4378 : inline XPCWrappedNativeProto* Find(nsIClassInfo* info)
347 : {
348 4378 : auto entry = static_cast<Entry*>(mTable.Search(info));
349 4378 : return entry ? entry->value : nullptr;
350 : }
351 :
352 1824 : inline XPCWrappedNativeProto* Add(nsIClassInfo* info, XPCWrappedNativeProto* proto)
353 : {
354 1824 : NS_PRECONDITION(info,"bad param");
355 1824 : auto entry = static_cast<Entry*>(mTable.Add(info, mozilla::fallible));
356 1824 : if (!entry)
357 0 : return nullptr;
358 1824 : if (entry->key)
359 0 : return entry->value;
360 1824 : entry->key = info;
361 1824 : entry->value = proto;
362 1824 : return proto;
363 : }
364 :
365 : inline void Remove(nsIClassInfo* info)
366 : {
367 : NS_PRECONDITION(info,"bad param");
368 : mTable.Remove(info);
369 : }
370 :
371 0 : inline void Clear() { mTable.Clear(); }
372 :
373 0 : inline uint32_t Count() { return mTable.EntryCount(); }
374 :
375 0 : PLDHashTable::Iterator Iter() { return mTable.Iter(); }
376 :
377 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
378 :
379 : private:
380 : ClassInfo2WrappedNativeProtoMap(); // no implementation
381 : explicit ClassInfo2WrappedNativeProtoMap(int size);
382 :
383 : private:
384 : PLDHashTable mTable;
385 : };
386 :
387 : /*************************/
388 :
389 0 : class NativeSetMap
390 : {
391 : public:
392 : struct Entry : public PLDHashEntryHdr
393 : {
394 : XPCNativeSet* key_value;
395 :
396 : static bool
397 : Match(const PLDHashEntryHdr* entry, const void* key);
398 :
399 : static const struct PLDHashTableOps sOps;
400 : };
401 :
402 : static NativeSetMap* newMap(int length);
403 :
404 1942 : inline XPCNativeSet* Find(XPCNativeSetKey* key)
405 : {
406 1942 : auto entry = static_cast<Entry*>(mTable.Search(key));
407 1942 : return entry ? entry->key_value : nullptr;
408 : }
409 :
410 940 : inline XPCNativeSet* Add(const XPCNativeSetKey* key, XPCNativeSet* set)
411 : {
412 940 : MOZ_ASSERT(key, "bad param");
413 940 : MOZ_ASSERT(set, "bad param");
414 940 : auto entry = static_cast<Entry*>(mTable.Add(key, mozilla::fallible));
415 940 : if (!entry)
416 0 : return nullptr;
417 940 : if (entry->key_value)
418 329 : return entry->key_value;
419 611 : entry->key_value = set;
420 611 : return set;
421 : }
422 :
423 245 : bool AddNew(const XPCNativeSetKey* key, XPCNativeSet* set)
424 : {
425 245 : XPCNativeSet* set2 = Add(key, set);
426 245 : if (!set2) {
427 0 : return false;
428 : }
429 : #ifdef DEBUG
430 490 : XPCNativeSetKey key2(set);
431 245 : MOZ_ASSERT(key->Hash() == key2.Hash());
432 245 : MOZ_ASSERT(set2 == set, "Should not have found an existing entry");
433 : #endif
434 245 : return true;
435 : }
436 :
437 376 : inline void Remove(XPCNativeSet* set)
438 : {
439 376 : MOZ_ASSERT(set, "bad param");
440 :
441 752 : XPCNativeSetKey key(set);
442 376 : mTable.Remove(&key);
443 376 : }
444 :
445 0 : inline uint32_t Count() { return mTable.EntryCount(); }
446 :
447 0 : PLDHashTable::Iterator Iter() { return mTable.Iter(); }
448 :
449 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
450 :
451 : private:
452 : NativeSetMap(); // no implementation
453 : explicit NativeSetMap(int size);
454 :
455 : private:
456 : PLDHashTable mTable;
457 : };
458 :
459 : /***************************************************************************/
460 :
461 0 : class IID2ThisTranslatorMap
462 : {
463 : public:
464 : struct Entry : public PLDHashEntryHdr
465 : {
466 : nsIID key;
467 : nsCOMPtr<nsIXPCFunctionThisTranslator> value;
468 :
469 : static bool
470 : Match(const PLDHashEntryHdr* entry, const void* key);
471 :
472 : static void
473 : Clear(PLDHashTable* table, PLDHashEntryHdr* entry);
474 :
475 : static const struct PLDHashTableOps sOps;
476 : };
477 :
478 : static IID2ThisTranslatorMap* newMap(int length);
479 :
480 44 : inline nsIXPCFunctionThisTranslator* Find(REFNSIID iid)
481 : {
482 44 : auto entry = static_cast<Entry*>(mTable.Search(&iid));
483 44 : if (!entry) {
484 24 : return nullptr;
485 : }
486 20 : return entry->value;
487 : }
488 :
489 3 : inline nsIXPCFunctionThisTranslator* Add(REFNSIID iid,
490 : nsIXPCFunctionThisTranslator* obj)
491 : {
492 3 : auto entry = static_cast<Entry*>(mTable.Add(&iid, mozilla::fallible));
493 3 : if (!entry)
494 0 : return nullptr;
495 3 : entry->value = obj;
496 3 : entry->key = iid;
497 3 : return obj;
498 : }
499 :
500 : inline void Remove(REFNSIID iid)
501 : {
502 : mTable.Remove(&iid);
503 : }
504 :
505 0 : inline uint32_t Count() { return mTable.EntryCount(); }
506 :
507 : private:
508 : IID2ThisTranslatorMap(); // no implementation
509 : explicit IID2ThisTranslatorMap(int size);
510 : private:
511 : PLDHashTable mTable;
512 : };
513 :
514 : /***************************************************************************/
515 :
516 0 : class XPCWrappedNativeProtoMap
517 : {
518 : public:
519 : typedef PLDHashEntryStub Entry;
520 :
521 : static XPCWrappedNativeProtoMap* newMap(int length);
522 :
523 0 : inline XPCWrappedNativeProto* Add(XPCWrappedNativeProto* proto)
524 : {
525 0 : NS_PRECONDITION(proto,"bad param");
526 : auto entry = static_cast<PLDHashEntryStub*>
527 0 : (mTable.Add(proto, mozilla::fallible));
528 0 : if (!entry)
529 0 : return nullptr;
530 0 : if (entry->key)
531 0 : return (XPCWrappedNativeProto*) entry->key;
532 0 : entry->key = proto;
533 0 : return proto;
534 : }
535 :
536 : inline void Remove(XPCWrappedNativeProto* proto)
537 : {
538 : NS_PRECONDITION(proto,"bad param");
539 : mTable.Remove(proto);
540 : }
541 :
542 : inline uint32_t Count() { return mTable.EntryCount(); }
543 :
544 0 : PLDHashTable::Iterator Iter() { return mTable.Iter(); }
545 :
546 : private:
547 : XPCWrappedNativeProtoMap(); // no implementation
548 : explicit XPCWrappedNativeProtoMap(int size);
549 : private:
550 : PLDHashTable mTable;
551 : };
552 :
553 : /***************************************************************************/
554 :
555 0 : class JSObject2JSObjectMap
556 : {
557 : using Map = JS::GCHashMap<JS::Heap<JSObject*>,
558 : JS::Heap<JSObject*>,
559 : js::MovableCellHasher<JS::Heap<JSObject*>>,
560 : js::SystemAllocPolicy>;
561 :
562 : public:
563 1 : static JSObject2JSObjectMap* newMap(int length) {
564 1 : auto* map = new JSObject2JSObjectMap();
565 1 : if (!map->mTable.init(length)) {
566 : // This is a decent estimate of the size of the hash table's
567 : // entry storage. The |2| is because on average the capacity is
568 : // twice the requested length.
569 0 : NS_ABORT_OOM(length * 2 * sizeof(Map::Entry));
570 : }
571 1 : return map;
572 : }
573 :
574 1 : inline JSObject* Find(JSObject* key) {
575 1 : NS_PRECONDITION(key, "bad param");
576 1 : if (Map::Ptr p = mTable.lookup(key))
577 1 : return p->value();
578 0 : return nullptr;
579 : }
580 :
581 : /* Note: If the entry already exists, return the old value. */
582 1 : inline JSObject* Add(JSContext* cx, JSObject* key, JSObject* value) {
583 1 : NS_PRECONDITION(key,"bad param");
584 1 : Map::AddPtr p = mTable.lookupForAdd(key);
585 1 : if (p)
586 0 : return p->value();
587 1 : if (!mTable.add(p, key, value))
588 0 : return nullptr;
589 1 : MOZ_ASSERT(xpc::CompartmentPrivate::Get(key)->scope->mWaiverWrapperMap == this);
590 1 : return value;
591 : }
592 :
593 0 : inline void Remove(JSObject* key) {
594 0 : NS_PRECONDITION(key,"bad param");
595 0 : mTable.remove(key);
596 0 : }
597 :
598 : inline uint32_t Count() { return mTable.count(); }
599 :
600 0 : void Sweep() {
601 0 : mTable.sweep();
602 0 : }
603 :
604 : private:
605 1 : JSObject2JSObjectMap() {}
606 :
607 : Map mTable;
608 : };
609 :
610 : #endif /* xpcmaps_h___ */
|