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 #include "mozilla/MathAlgorithms.h"
10 #include "mozilla/MemoryReporting.h"
11 #include "xpcprivate.h"
12
13 #include "js/HashTable.h"
14
15 using namespace mozilla;
16
17 /***************************************************************************/
18 // static shared...
19
20 // Note this is returning the hash of the bit pattern of the first part of the
21 // nsID, not the hash of the pointer to the nsID.
22
HashIIDPtrKey(const void * key)23 static PLDHashNumber HashIIDPtrKey(const void* key) {
24 return HashGeneric(*((uintptr_t*)key));
25 }
26
MatchIIDPtrKey(const PLDHashEntryHdr * entry,const void * key)27 static bool MatchIIDPtrKey(const PLDHashEntryHdr* entry, const void* key) {
28 return ((const nsID*)key)
29 ->Equals(*((const nsID*)((PLDHashEntryStub*)entry)->key));
30 }
31
HashNativeKey(const void * data)32 static PLDHashNumber HashNativeKey(const void* data) {
33 return static_cast<const XPCNativeSetKey*>(data)->Hash();
34 }
35
36 /***************************************************************************/
37 // implement JSObject2WrappedJSMap...
38
UpdateWeakPointersAfterGC()39 void JSObject2WrappedJSMap::UpdateWeakPointersAfterGC() {
40 // Check all wrappers and update their JSObject pointer if it has been
41 // moved. Release any wrappers whose weakly held JSObject has died.
42
43 nsTArray<RefPtr<nsXPCWrappedJS>> dying;
44 for (Map::Enum e(mTable); !e.empty(); e.popFront()) {
45 nsXPCWrappedJS* wrapper = e.front().value();
46 MOZ_ASSERT(wrapper, "found a null JS wrapper!");
47
48 // Walk the wrapper chain and update all JSObjects.
49 while (wrapper) {
50 if (wrapper->IsSubjectToFinalization()) {
51 wrapper->UpdateObjectPointerAfterGC();
52 if (!wrapper->GetJSObjectPreserveColor())
53 dying.AppendElement(dont_AddRef(wrapper));
54 }
55 wrapper = wrapper->GetNextWrapper();
56 }
57
58 // Remove or update the JSObject key in the table if necessary.
59 JSObject* obj = e.front().key().unbarrieredGet();
60 JS_UpdateWeakPointerAfterGCUnbarriered(&obj);
61 if (!obj)
62 e.removeFront();
63 else
64 e.front().mutableKey() = obj;
65 }
66 }
67
ShutdownMarker()68 void JSObject2WrappedJSMap::ShutdownMarker() {
69 for (Map::Range r = mTable.all(); !r.empty(); r.popFront()) {
70 nsXPCWrappedJS* wrapper = r.front().value();
71 MOZ_ASSERT(wrapper, "found a null JS wrapper!");
72 MOZ_ASSERT(wrapper->IsValid(), "found an invalid JS wrapper!");
73 wrapper->SystemIsBeingShutDown();
74 }
75 }
76
SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const77 size_t JSObject2WrappedJSMap::SizeOfIncludingThis(
78 mozilla::MallocSizeOf mallocSizeOf) const {
79 size_t n = mallocSizeOf(this);
80 n += mTable.sizeOfExcludingThis(mallocSizeOf);
81 return n;
82 }
83
SizeOfWrappedJS(mozilla::MallocSizeOf mallocSizeOf) const84 size_t JSObject2WrappedJSMap::SizeOfWrappedJS(
85 mozilla::MallocSizeOf mallocSizeOf) const {
86 size_t n = 0;
87 for (Map::Range r = mTable.all(); !r.empty(); r.popFront())
88 n += r.front().value()->SizeOfIncludingThis(mallocSizeOf);
89 return n;
90 }
91
92 /***************************************************************************/
93 // implement Native2WrappedNativeMap...
94
95 // static
newMap(int length)96 Native2WrappedNativeMap* Native2WrappedNativeMap::newMap(int length) {
97 return new Native2WrappedNativeMap(length);
98 }
99
Native2WrappedNativeMap(int length)100 Native2WrappedNativeMap::Native2WrappedNativeMap(int length)
101 : mTable(PLDHashTable::StubOps(), sizeof(Entry), length) {}
102
SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const103 size_t Native2WrappedNativeMap::SizeOfIncludingThis(
104 mozilla::MallocSizeOf mallocSizeOf) const {
105 size_t n = mallocSizeOf(this);
106 n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf);
107 for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) {
108 auto entry = static_cast<Native2WrappedNativeMap::Entry*>(iter.Get());
109 n += mallocSizeOf(entry->value);
110 }
111 return n;
112 }
113
114 /***************************************************************************/
115 // implement IID2WrappedJSClassMap...
116
117 const struct PLDHashTableOps IID2WrappedJSClassMap::Entry::sOps = {
118 HashIIDPtrKey, MatchIIDPtrKey, PLDHashTable::MoveEntryStub,
119 PLDHashTable::ClearEntryStub};
120
121 // static
newMap(int length)122 IID2WrappedJSClassMap* IID2WrappedJSClassMap::newMap(int length) {
123 return new IID2WrappedJSClassMap(length);
124 }
125
IID2WrappedJSClassMap(int length)126 IID2WrappedJSClassMap::IID2WrappedJSClassMap(int length)
127 : mTable(&Entry::sOps, sizeof(Entry), length) {}
128
129 /***************************************************************************/
130 // implement IID2NativeInterfaceMap...
131
132 const struct PLDHashTableOps IID2NativeInterfaceMap::Entry::sOps = {
133 HashIIDPtrKey, MatchIIDPtrKey, PLDHashTable::MoveEntryStub,
134 PLDHashTable::ClearEntryStub};
135
136 // static
newMap(int length)137 IID2NativeInterfaceMap* IID2NativeInterfaceMap::newMap(int length) {
138 return new IID2NativeInterfaceMap(length);
139 }
140
IID2NativeInterfaceMap(int length)141 IID2NativeInterfaceMap::IID2NativeInterfaceMap(int length)
142 : mTable(&Entry::sOps, sizeof(Entry), length) {}
143
SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const144 size_t IID2NativeInterfaceMap::SizeOfIncludingThis(
145 mozilla::MallocSizeOf mallocSizeOf) const {
146 size_t n = mallocSizeOf(this);
147 n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf);
148 for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) {
149 auto entry = static_cast<IID2NativeInterfaceMap::Entry*>(iter.Get());
150 n += entry->value->SizeOfIncludingThis(mallocSizeOf);
151 }
152 return n;
153 }
154
155 /***************************************************************************/
156 // implement ClassInfo2NativeSetMap...
157
158 // static
Match(const PLDHashEntryHdr * aEntry,const void * aKey)159 bool ClassInfo2NativeSetMap::Entry::Match(const PLDHashEntryHdr* aEntry,
160 const void* aKey) {
161 return static_cast<const Entry*>(aEntry)->key == aKey;
162 }
163
164 // static
Clear(PLDHashTable * aTable,PLDHashEntryHdr * aEntry)165 void ClassInfo2NativeSetMap::Entry::Clear(PLDHashTable* aTable,
166 PLDHashEntryHdr* aEntry) {
167 auto entry = static_cast<Entry*>(aEntry);
168 NS_RELEASE(entry->value);
169
170 entry->key = nullptr;
171 entry->value = nullptr;
172 }
173
174 const PLDHashTableOps ClassInfo2NativeSetMap::Entry::sOps = {
175 PLDHashTable::HashVoidPtrKeyStub, Match, PLDHashTable::MoveEntryStub, Clear,
176 nullptr};
177
178 // static
newMap(int length)179 ClassInfo2NativeSetMap* ClassInfo2NativeSetMap::newMap(int length) {
180 return new ClassInfo2NativeSetMap(length);
181 }
182
ClassInfo2NativeSetMap(int length)183 ClassInfo2NativeSetMap::ClassInfo2NativeSetMap(int length)
184 : mTable(&ClassInfo2NativeSetMap::Entry::sOps, sizeof(Entry), length) {}
185
ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)186 size_t ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis(
187 mozilla::MallocSizeOf mallocSizeOf) {
188 size_t n = mallocSizeOf(this);
189 n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf);
190 return n;
191 }
192
193 /***************************************************************************/
194 // implement ClassInfo2WrappedNativeProtoMap...
195
196 // static
newMap(int length)197 ClassInfo2WrappedNativeProtoMap* ClassInfo2WrappedNativeProtoMap::newMap(
198 int length) {
199 return new ClassInfo2WrappedNativeProtoMap(length);
200 }
201
ClassInfo2WrappedNativeProtoMap(int length)202 ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap(int length)
203 : mTable(PLDHashTable::StubOps(), sizeof(Entry), length) {}
204
SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const205 size_t ClassInfo2WrappedNativeProtoMap::SizeOfIncludingThis(
206 mozilla::MallocSizeOf mallocSizeOf) const {
207 size_t n = mallocSizeOf(this);
208 n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf);
209 for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) {
210 auto entry =
211 static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(iter.Get());
212 n += mallocSizeOf(entry->value);
213 }
214 return n;
215 }
216
217 /***************************************************************************/
218 // implement NativeSetMap...
219
Match(const PLDHashEntryHdr * entry,const void * key)220 bool NativeSetMap::Entry::Match(const PLDHashEntryHdr* entry, const void* key) {
221 auto Key = static_cast<const XPCNativeSetKey*>(key);
222 XPCNativeSet* SetInTable = ((Entry*)entry)->key_value;
223 XPCNativeSet* Set = Key->GetBaseSet();
224 XPCNativeInterface* Addition = Key->GetAddition();
225
226 if (!Set) {
227 // This is a special case to deal with the invariant that says:
228 // "All sets have exactly one nsISupports interface and it comes first."
229 // See XPCNativeSet::NewInstance for details.
230 //
231 // Though we might have a key that represents only one interface, we
232 // know that if that one interface were contructed into a set then
233 // it would end up really being a set with two interfaces (except for
234 // the case where the one interface happened to be nsISupports).
235
236 return (SetInTable->GetInterfaceCount() == 1 &&
237 SetInTable->GetInterfaceAt(0) == Addition) ||
238 (SetInTable->GetInterfaceCount() == 2 &&
239 SetInTable->GetInterfaceAt(1) == Addition);
240 }
241
242 if (!Addition && Set == SetInTable) return true;
243
244 uint16_t count = Set->GetInterfaceCount();
245 if (count + (Addition ? 1 : 0) != SetInTable->GetInterfaceCount())
246 return false;
247
248 XPCNativeInterface** CurrentInTable = SetInTable->GetInterfaceArray();
249 XPCNativeInterface** Current = Set->GetInterfaceArray();
250 for (uint16_t i = 0; i < count; i++) {
251 if (*(Current++) != *(CurrentInTable++)) return false;
252 }
253 return !Addition || Addition == *(CurrentInTable++);
254 }
255
256 const struct PLDHashTableOps NativeSetMap::Entry::sOps = {
257 HashNativeKey, Match, PLDHashTable::MoveEntryStub,
258 PLDHashTable::ClearEntryStub};
259
260 // static
newMap(int length)261 NativeSetMap* NativeSetMap::newMap(int length) {
262 return new NativeSetMap(length);
263 }
264
NativeSetMap(int length)265 NativeSetMap::NativeSetMap(int length)
266 : mTable(&Entry::sOps, sizeof(Entry), length) {}
267
SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const268 size_t NativeSetMap::SizeOfIncludingThis(
269 mozilla::MallocSizeOf mallocSizeOf) const {
270 size_t n = mallocSizeOf(this);
271 n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf);
272 for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) {
273 auto entry = static_cast<NativeSetMap::Entry*>(iter.Get());
274 n += entry->key_value->SizeOfIncludingThis(mallocSizeOf);
275 }
276 return n;
277 }
278
279 /***************************************************************************/
280 // implement IID2ThisTranslatorMap...
281
Match(const PLDHashEntryHdr * entry,const void * key)282 bool IID2ThisTranslatorMap::Entry::Match(const PLDHashEntryHdr* entry,
283 const void* key) {
284 return ((const nsID*)key)->Equals(((Entry*)entry)->key);
285 }
286
Clear(PLDHashTable * table,PLDHashEntryHdr * entry)287 void IID2ThisTranslatorMap::Entry::Clear(PLDHashTable* table,
288 PLDHashEntryHdr* entry) {
289 static_cast<Entry*>(entry)->value = nullptr;
290 memset(entry, 0, table->EntrySize());
291 }
292
293 const struct PLDHashTableOps IID2ThisTranslatorMap::Entry::sOps = {
294 HashIIDPtrKey, Match, PLDHashTable::MoveEntryStub, Clear};
295
296 // static
newMap(int length)297 IID2ThisTranslatorMap* IID2ThisTranslatorMap::newMap(int length) {
298 return new IID2ThisTranslatorMap(length);
299 }
300
IID2ThisTranslatorMap(int length)301 IID2ThisTranslatorMap::IID2ThisTranslatorMap(int length)
302 : mTable(&Entry::sOps, sizeof(Entry), length) {}
303
304 /***************************************************************************/
305 // implement XPCWrappedNativeProtoMap...
306
307 // static
newMap(int length)308 XPCWrappedNativeProtoMap* XPCWrappedNativeProtoMap::newMap(int length) {
309 return new XPCWrappedNativeProtoMap(length);
310 }
311
XPCWrappedNativeProtoMap(int length)312 XPCWrappedNativeProtoMap::XPCWrappedNativeProtoMap(int length)
313 : mTable(PLDHashTable::StubOps(), sizeof(PLDHashEntryStub), length) {}
314
315 /***************************************************************************/
316