Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
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)
25 {
26 return *((js::HashNumber*)key);
27 }
29 static bool
30 MatchIIDPtrKey(PLDHashTable *table,
31 const PLDHashEntryHdr *entry,
32 const void *key)
33 {
34 return ((const nsID*)key)->
35 Equals(*((const nsID*)((PLDHashEntryStub*)entry)->key));
36 }
38 static PLDHashNumber
39 HashNativeKey(PLDHashTable *table, const void *key)
40 {
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;
57 }
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;
74 }
75 } else {
76 for (uint16_t i = 0; i < count; i++)
77 h ^= (js::HashNumber) NS_PTR_TO_INT32(*(Current++)) >> 2;
78 }
79 }
81 return h;
82 }
84 /***************************************************************************/
85 // implement JSObject2WrappedJSMap...
87 void
88 JSObject2WrappedJSMap::FindDyingJSObjects(nsTArray<nsXPCWrappedJS*>* dying)
89 {
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();
99 }
100 }
101 }
103 void
104 JSObject2WrappedJSMap::ShutdownMarker()
105 {
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();
111 }
112 }
114 /***************************************************************************/
115 // implement Native2WrappedNativeMap...
117 // static
118 Native2WrappedNativeMap*
119 Native2WrappedNativeMap::newMap(int size)
120 {
121 Native2WrappedNativeMap* map = new Native2WrappedNativeMap(size);
122 if (map && map->mTable)
123 return map;
124 // Allocation of the map or the creation of its hash table has
125 // failed. This will cause a nullptr deref later when we attempt
126 // to use the map, so we abort immediately to provide a more
127 // useful crash stack.
128 NS_RUNTIMEABORT("Ran out of memory.");
129 return nullptr;
130 }
132 Native2WrappedNativeMap::Native2WrappedNativeMap(int size)
133 {
134 mTable = PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
135 sizeof(Entry), size);
136 }
138 Native2WrappedNativeMap::~Native2WrappedNativeMap()
139 {
140 if (mTable)
141 PL_DHashTableDestroy(mTable);
142 }
144 size_t
145 Native2WrappedNativeMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
146 {
147 size_t n = 0;
148 n += mallocSizeOf(this);
149 n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
150 return n;
151 }
153 /* static */ size_t
154 Native2WrappedNativeMap::SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr,
155 mozilla::MallocSizeOf mallocSizeOf, void *)
156 {
157 return mallocSizeOf(((Native2WrappedNativeMap::Entry*)hdr)->value);
158 }
160 /***************************************************************************/
161 // implement IID2WrappedJSClassMap...
163 const struct PLDHashTableOps IID2WrappedJSClassMap::Entry::sOps =
164 {
165 PL_DHashAllocTable,
166 PL_DHashFreeTable,
167 HashIIDPtrKey,
168 MatchIIDPtrKey,
169 PL_DHashMoveEntryStub,
170 PL_DHashClearEntryStub,
171 PL_DHashFinalizeStub
172 };
174 // static
175 IID2WrappedJSClassMap*
176 IID2WrappedJSClassMap::newMap(int size)
177 {
178 IID2WrappedJSClassMap* map = new IID2WrappedJSClassMap(size);
179 if (map && map->mTable)
180 return map;
181 delete map;
182 return nullptr;
183 }
185 IID2WrappedJSClassMap::IID2WrappedJSClassMap(int size)
186 {
187 mTable = PL_NewDHashTable(&Entry::sOps, nullptr, sizeof(Entry), size);
188 }
190 IID2WrappedJSClassMap::~IID2WrappedJSClassMap()
191 {
192 if (mTable)
193 PL_DHashTableDestroy(mTable);
194 }
197 /***************************************************************************/
198 // implement IID2NativeInterfaceMap...
200 const struct PLDHashTableOps IID2NativeInterfaceMap::Entry::sOps =
201 {
202 PL_DHashAllocTable,
203 PL_DHashFreeTable,
204 HashIIDPtrKey,
205 MatchIIDPtrKey,
206 PL_DHashMoveEntryStub,
207 PL_DHashClearEntryStub,
208 PL_DHashFinalizeStub
209 };
211 // static
212 IID2NativeInterfaceMap*
213 IID2NativeInterfaceMap::newMap(int size)
214 {
215 IID2NativeInterfaceMap* map = new IID2NativeInterfaceMap(size);
216 if (map && map->mTable)
217 return map;
218 delete map;
219 return nullptr;
220 }
222 IID2NativeInterfaceMap::IID2NativeInterfaceMap(int size)
223 {
224 mTable = PL_NewDHashTable(&Entry::sOps, nullptr, sizeof(Entry), size);
225 }
227 IID2NativeInterfaceMap::~IID2NativeInterfaceMap()
228 {
229 if (mTable)
230 PL_DHashTableDestroy(mTable);
231 }
233 size_t
234 IID2NativeInterfaceMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
235 {
236 size_t n = 0;
237 n += mallocSizeOf(this);
238 n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
239 return n;
240 }
242 /* static */ size_t
243 IID2NativeInterfaceMap::SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr,
244 mozilla::MallocSizeOf mallocSizeOf, void *)
245 {
246 XPCNativeInterface *iface = ((IID2NativeInterfaceMap::Entry*)hdr)->value;
247 return iface->SizeOfIncludingThis(mallocSizeOf);
248 }
250 /***************************************************************************/
251 // implement ClassInfo2NativeSetMap...
253 // static
254 ClassInfo2NativeSetMap*
255 ClassInfo2NativeSetMap::newMap(int size)
256 {
257 ClassInfo2NativeSetMap* map = new ClassInfo2NativeSetMap(size);
258 if (map && map->mTable)
259 return map;
260 delete map;
261 return nullptr;
262 }
264 ClassInfo2NativeSetMap::ClassInfo2NativeSetMap(int size)
265 {
266 mTable = PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
267 sizeof(Entry), size);
268 }
270 ClassInfo2NativeSetMap::~ClassInfo2NativeSetMap()
271 {
272 if (mTable)
273 PL_DHashTableDestroy(mTable);
274 }
276 size_t
277 ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
278 {
279 size_t n = 0;
280 n += mallocSizeOf(this);
281 // The second arg is nullptr because this is a "shallow" measurement of the map.
282 n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, nullptr, mallocSizeOf) : 0;
283 return n;
284 }
286 /***************************************************************************/
287 // implement ClassInfo2WrappedNativeProtoMap...
289 // static
290 ClassInfo2WrappedNativeProtoMap*
291 ClassInfo2WrappedNativeProtoMap::newMap(int size)
292 {
293 ClassInfo2WrappedNativeProtoMap* map = new ClassInfo2WrappedNativeProtoMap(size);
294 if (map && map->mTable)
295 return map;
296 // Allocation of the map or the creation of its hash table has
297 // failed. This will cause a nullptr deref later when we attempt
298 // to use the map, so we abort immediately to provide a more
299 // useful crash stack.
300 NS_RUNTIMEABORT("Ran out of memory.");
301 return nullptr;
302 }
304 ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap(int size)
305 {
306 mTable = PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
307 sizeof(Entry), size);
308 }
310 ClassInfo2WrappedNativeProtoMap::~ClassInfo2WrappedNativeProtoMap()
311 {
312 if (mTable)
313 PL_DHashTableDestroy(mTable);
314 }
316 size_t
317 ClassInfo2WrappedNativeProtoMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
318 {
319 size_t n = 0;
320 n += mallocSizeOf(this);
321 n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
322 return n;
323 }
325 /* static */ size_t
326 ClassInfo2WrappedNativeProtoMap::SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr,
327 mozilla::MallocSizeOf mallocSizeOf, void *)
328 {
329 return mallocSizeOf(((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value);
330 }
332 /***************************************************************************/
333 // implement NativeSetMap...
335 bool
336 NativeSetMap::Entry::Match(PLDHashTable *table,
337 const PLDHashEntryHdr *entry,
338 const void *key)
339 {
340 XPCNativeSetKey* Key = (XPCNativeSetKey*) key;
342 // See the comment in the XPCNativeSetKey declaration in xpcprivate.h.
343 if (!Key->IsAKey()) {
344 XPCNativeSet* Set1 = (XPCNativeSet*) key;
345 XPCNativeSet* Set2 = ((Entry*)entry)->key_value;
347 if (Set1 == Set2)
348 return true;
350 uint16_t count = Set1->GetInterfaceCount();
351 if (count != Set2->GetInterfaceCount())
352 return false;
354 XPCNativeInterface** Current1 = Set1->GetInterfaceArray();
355 XPCNativeInterface** Current2 = Set2->GetInterfaceArray();
356 for (uint16_t i = 0; i < count; i++) {
357 if (*(Current1++) != *(Current2++))
358 return false;
359 }
361 return true;
362 }
364 XPCNativeSet* SetInTable = ((Entry*)entry)->key_value;
365 XPCNativeSet* Set = Key->GetBaseSet();
366 XPCNativeInterface* Addition = Key->GetAddition();
368 if (!Set) {
369 // This is a special case to deal with the invariant that says:
370 // "All sets have exactly one nsISupports interface and it comes first."
371 // See XPCNativeSet::NewInstance for details.
372 //
373 // Though we might have a key that represents only one interface, we
374 // know that if that one interface were contructed into a set then
375 // it would end up really being a set with two interfaces (except for
376 // the case where the one interface happened to be nsISupports).
378 return ((SetInTable->GetInterfaceCount() == 1 &&
379 SetInTable->GetInterfaceAt(0) == Addition) ||
380 (SetInTable->GetInterfaceCount() == 2 &&
381 SetInTable->GetInterfaceAt(1) == Addition));
382 }
384 if (!Addition && Set == SetInTable)
385 return true;
387 uint16_t count = Set->GetInterfaceCount() + (Addition ? 1 : 0);
388 if (count != SetInTable->GetInterfaceCount())
389 return false;
391 uint16_t Position = Key->GetPosition();
392 XPCNativeInterface** CurrentInTable = SetInTable->GetInterfaceArray();
393 XPCNativeInterface** Current = Set->GetInterfaceArray();
394 for (uint16_t i = 0; i < count; i++) {
395 if (Addition && i == Position) {
396 if (Addition != *(CurrentInTable++))
397 return false;
398 } else {
399 if (*(Current++) != *(CurrentInTable++))
400 return false;
401 }
402 }
404 return true;
405 }
407 const struct PLDHashTableOps NativeSetMap::Entry::sOps =
408 {
409 PL_DHashAllocTable,
410 PL_DHashFreeTable,
411 HashNativeKey,
412 Match,
413 PL_DHashMoveEntryStub,
414 PL_DHashClearEntryStub,
415 PL_DHashFinalizeStub
416 };
418 // static
419 NativeSetMap*
420 NativeSetMap::newMap(int size)
421 {
422 NativeSetMap* map = new NativeSetMap(size);
423 if (map && map->mTable)
424 return map;
425 delete map;
426 return nullptr;
427 }
429 NativeSetMap::NativeSetMap(int size)
430 {
431 mTable = PL_NewDHashTable(&Entry::sOps, nullptr, sizeof(Entry), size);
432 }
434 NativeSetMap::~NativeSetMap()
435 {
436 if (mTable)
437 PL_DHashTableDestroy(mTable);
438 }
440 size_t
441 NativeSetMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
442 {
443 size_t n = 0;
444 n += mallocSizeOf(this);
445 n += mTable ? PL_DHashTableSizeOfIncludingThis(mTable, SizeOfEntryExcludingThis, mallocSizeOf) : 0;
446 return n;
447 }
449 /* static */ size_t
450 NativeSetMap::SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr, mozilla::MallocSizeOf mallocSizeOf, void *)
451 {
452 XPCNativeSet *set = ((NativeSetMap::Entry*)hdr)->key_value;
453 return set->SizeOfIncludingThis(mallocSizeOf);
454 }
456 /***************************************************************************/
457 // implement IID2ThisTranslatorMap...
459 bool
460 IID2ThisTranslatorMap::Entry::Match(PLDHashTable *table,
461 const PLDHashEntryHdr *entry,
462 const void *key)
463 {
464 return ((const nsID*)key)->Equals(((Entry*)entry)->key);
465 }
467 void
468 IID2ThisTranslatorMap::Entry::Clear(PLDHashTable *table, PLDHashEntryHdr *entry)
469 {
470 static_cast<Entry*>(entry)->value = nullptr;
471 memset(entry, 0, table->entrySize);
472 }
474 const struct PLDHashTableOps IID2ThisTranslatorMap::Entry::sOps =
475 {
476 PL_DHashAllocTable,
477 PL_DHashFreeTable,
478 HashIIDPtrKey,
479 Match,
480 PL_DHashMoveEntryStub,
481 Clear,
482 PL_DHashFinalizeStub
483 };
485 // static
486 IID2ThisTranslatorMap*
487 IID2ThisTranslatorMap::newMap(int size)
488 {
489 IID2ThisTranslatorMap* map = new IID2ThisTranslatorMap(size);
490 if (map && map->mTable)
491 return map;
492 delete map;
493 return nullptr;
494 }
496 IID2ThisTranslatorMap::IID2ThisTranslatorMap(int size)
497 {
498 mTable = PL_NewDHashTable(&Entry::sOps, nullptr, sizeof(Entry), size);
499 }
501 IID2ThisTranslatorMap::~IID2ThisTranslatorMap()
502 {
503 if (mTable)
504 PL_DHashTableDestroy(mTable);
505 }
507 /***************************************************************************/
509 PLDHashNumber
510 XPCNativeScriptableSharedMap::Entry::Hash(PLDHashTable *table, const void *key)
511 {
512 PLDHashNumber h;
513 const unsigned char *s;
515 XPCNativeScriptableShared* obj =
516 (XPCNativeScriptableShared*) key;
518 // hash together the flags and the classname string, ignore the interfaces
519 // bitmap since it's very rare that it's different when flags and classname
520 // are the same.
522 h = (PLDHashNumber) obj->GetFlags();
523 for (s = (const unsigned char*) obj->GetJSClass()->name; *s != '\0'; s++)
524 h = RotateLeft(h, 4) ^ *s;
525 return h;
526 }
528 bool
529 XPCNativeScriptableSharedMap::Entry::Match(PLDHashTable *table,
530 const PLDHashEntryHdr *entry,
531 const void *key)
532 {
533 XPCNativeScriptableShared* obj1 =
534 ((XPCNativeScriptableSharedMap::Entry*) entry)->key;
536 XPCNativeScriptableShared* obj2 =
537 (XPCNativeScriptableShared*) key;
539 // match the flags, the classname string and the interfaces bitmap
541 if (obj1->GetFlags() != obj2->GetFlags() ||
542 obj1->GetInterfacesBitmap() != obj2->GetInterfacesBitmap())
543 return false;
545 const char* name1 = obj1->GetJSClass()->name;
546 const char* name2 = obj2->GetJSClass()->name;
548 if (!name1 || !name2)
549 return name1 == name2;
551 return 0 == strcmp(name1, name2);
552 }
554 const struct PLDHashTableOps XPCNativeScriptableSharedMap::Entry::sOps =
555 {
556 PL_DHashAllocTable,
557 PL_DHashFreeTable,
558 Hash,
559 Match,
560 PL_DHashMoveEntryStub,
561 PL_DHashClearEntryStub,
562 PL_DHashFinalizeStub
563 };
565 // static
566 XPCNativeScriptableSharedMap*
567 XPCNativeScriptableSharedMap::newMap(int size)
568 {
569 XPCNativeScriptableSharedMap* map =
570 new XPCNativeScriptableSharedMap(size);
571 if (map && map->mTable)
572 return map;
573 delete map;
574 return nullptr;
575 }
577 XPCNativeScriptableSharedMap::XPCNativeScriptableSharedMap(int size)
578 {
579 mTable = PL_NewDHashTable(&Entry::sOps, nullptr, sizeof(Entry), size);
580 }
582 XPCNativeScriptableSharedMap::~XPCNativeScriptableSharedMap()
583 {
584 if (mTable)
585 PL_DHashTableDestroy(mTable);
586 }
588 bool
589 XPCNativeScriptableSharedMap::GetNewOrUsed(uint32_t flags,
590 char* name,
591 uint32_t interfacesBitmap,
592 XPCNativeScriptableInfo* si)
593 {
594 NS_PRECONDITION(name,"bad param");
595 NS_PRECONDITION(si,"bad param");
597 XPCNativeScriptableShared key(flags, name, interfacesBitmap);
598 Entry* entry = (Entry*)
599 PL_DHashTableOperate(mTable, &key, PL_DHASH_ADD);
600 if (!entry)
601 return false;
603 XPCNativeScriptableShared* shared = entry->key;
605 if (!shared) {
606 entry->key = shared =
607 new XPCNativeScriptableShared(flags, key.TransferNameOwnership(),
608 interfacesBitmap);
609 if (!shared)
610 return false;
611 shared->PopulateJSClass();
612 }
613 si->SetScriptableShared(shared);
614 return true;
615 }
617 /***************************************************************************/
618 // implement XPCWrappedNativeProtoMap...
620 // static
621 XPCWrappedNativeProtoMap*
622 XPCWrappedNativeProtoMap::newMap(int size)
623 {
624 XPCWrappedNativeProtoMap* map = new XPCWrappedNativeProtoMap(size);
625 if (map && map->mTable)
626 return map;
627 delete map;
628 return nullptr;
629 }
631 XPCWrappedNativeProtoMap::XPCWrappedNativeProtoMap(int size)
632 {
633 mTable = PL_NewDHashTable(PL_DHashGetStubOps(), nullptr,
634 sizeof(PLDHashEntryStub), size);
635 }
637 XPCWrappedNativeProtoMap::~XPCWrappedNativeProtoMap()
638 {
639 if (mTable)
640 PL_DHashTableDestroy(mTable);
641 }
643 /***************************************************************************/