1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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   uintptr_t v;
25   memcpy(&v, key, sizeof(v));
26   return HashGeneric(v);
27 }
28 
MatchIIDPtrKey(const PLDHashEntryHdr * entry,const void * key)29 static bool MatchIIDPtrKey(const PLDHashEntryHdr* entry, const void* key) {
30   return ((const nsID*)key)
31       ->Equals(*((const nsID*)((PLDHashEntryStub*)entry)->key));
32 }
33 
HashNativeKey(const void * data)34 static PLDHashNumber HashNativeKey(const void* data) {
35   return static_cast<const XPCNativeSetKey*>(data)->Hash();
36 }
37 
38 /***************************************************************************/
39 // implement JSObject2WrappedJSMap...
40 
UpdateWeakPointersAfterGC()41 void JSObject2WrappedJSMap::UpdateWeakPointersAfterGC() {
42   // Check all wrappers and update their JSObject pointer if it has been
43   // moved. Release any wrappers whose weakly held JSObject has died.
44 
45   nsTArray<RefPtr<nsXPCWrappedJS>> dying;
46   for (auto iter = mTable.modIter(); !iter.done(); iter.next()) {
47     nsXPCWrappedJS* wrapper = iter.get().value();
48     MOZ_ASSERT(wrapper, "found a null JS wrapper!");
49 
50     // Walk the wrapper chain and update all JSObjects.
51     while (wrapper) {
52       if (wrapper->IsSubjectToFinalization()) {
53         wrapper->UpdateObjectPointerAfterGC();
54         if (!wrapper->GetJSObjectPreserveColor()) {
55           dying.AppendElement(dont_AddRef(wrapper));
56         }
57       }
58       wrapper = wrapper->GetNextWrapper();
59     }
60 
61     // Remove or update the JSObject key in the table if necessary.
62     JSObject* obj = iter.get().key().unbarrieredGet();
63     JS_UpdateWeakPointerAfterGCUnbarriered(&obj);
64     if (!obj) {
65       iter.remove();
66     } else {
67       iter.get().mutableKey() = obj;
68     }
69   }
70 }
71 
ShutdownMarker()72 void JSObject2WrappedJSMap::ShutdownMarker() {
73   for (auto iter = mTable.iter(); !iter.done(); iter.next()) {
74     nsXPCWrappedJS* wrapper = iter.get().value();
75     MOZ_ASSERT(wrapper, "found a null JS wrapper!");
76     MOZ_ASSERT(wrapper->IsValid(), "found an invalid JS wrapper!");
77     wrapper->SystemIsBeingShutDown();
78   }
79 }
80 
SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const81 size_t JSObject2WrappedJSMap::SizeOfIncludingThis(
82     mozilla::MallocSizeOf mallocSizeOf) const {
83   size_t n = mallocSizeOf(this);
84   n += mTable.shallowSizeOfExcludingThis(mallocSizeOf);
85   return n;
86 }
87 
SizeOfWrappedJS(mozilla::MallocSizeOf mallocSizeOf) const88 size_t JSObject2WrappedJSMap::SizeOfWrappedJS(
89     mozilla::MallocSizeOf mallocSizeOf) const {
90   size_t n = 0;
91   for (auto iter = mTable.iter(); !iter.done(); iter.next()) {
92     n += iter.get().value()->SizeOfIncludingThis(mallocSizeOf);
93   }
94   return n;
95 }
96 
97 /***************************************************************************/
98 // implement Native2WrappedNativeMap...
99 
Native2WrappedNativeMap()100 Native2WrappedNativeMap::Native2WrappedNativeMap()
101     : mTable(PLDHashTable::StubOps(), sizeof(Entry), XPC_NATIVE_MAP_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 IID2NativeInterfaceMap...
116 
117 const struct PLDHashTableOps IID2NativeInterfaceMap::Entry::sOps = {
118     HashIIDPtrKey, MatchIIDPtrKey, PLDHashTable::MoveEntryStub,
119     PLDHashTable::ClearEntryStub};
120 
IID2NativeInterfaceMap()121 IID2NativeInterfaceMap::IID2NativeInterfaceMap()
122     : mTable(&Entry::sOps, sizeof(Entry), XPC_NATIVE_INTERFACE_MAP_LENGTH) {}
123 
SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const124 size_t IID2NativeInterfaceMap::SizeOfIncludingThis(
125     mozilla::MallocSizeOf mallocSizeOf) const {
126   size_t n = mallocSizeOf(this);
127   n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf);
128   for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) {
129     auto entry = static_cast<IID2NativeInterfaceMap::Entry*>(iter.Get());
130     n += entry->value->SizeOfIncludingThis(mallocSizeOf);
131   }
132   return n;
133 }
134 
135 /***************************************************************************/
136 // implement ClassInfo2NativeSetMap...
137 
138 // static
Match(const PLDHashEntryHdr * aEntry,const void * aKey)139 bool ClassInfo2NativeSetMap::Entry::Match(const PLDHashEntryHdr* aEntry,
140                                           const void* aKey) {
141   return static_cast<const Entry*>(aEntry)->key == aKey;
142 }
143 
144 // static
Clear(PLDHashTable * aTable,PLDHashEntryHdr * aEntry)145 void ClassInfo2NativeSetMap::Entry::Clear(PLDHashTable* aTable,
146                                           PLDHashEntryHdr* aEntry) {
147   auto entry = static_cast<Entry*>(aEntry);
148   NS_RELEASE(entry->value);
149 
150   entry->key = nullptr;
151   entry->value = nullptr;
152 }
153 
154 const PLDHashTableOps ClassInfo2NativeSetMap::Entry::sOps = {
155     PLDHashTable::HashVoidPtrKeyStub, Match, PLDHashTable::MoveEntryStub, Clear,
156     nullptr};
157 
ClassInfo2NativeSetMap()158 ClassInfo2NativeSetMap::ClassInfo2NativeSetMap()
159     : mTable(&ClassInfo2NativeSetMap::Entry::sOps, sizeof(Entry),
160              XPC_NATIVE_SET_MAP_LENGTH) {}
161 
ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)162 size_t ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis(
163     mozilla::MallocSizeOf mallocSizeOf) {
164   size_t n = mallocSizeOf(this);
165   n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf);
166   return n;
167 }
168 
169 /***************************************************************************/
170 // implement ClassInfo2WrappedNativeProtoMap...
171 
ClassInfo2WrappedNativeProtoMap()172 ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap()
173     : mTable(PLDHashTable::StubOps(), sizeof(Entry),
174              XPC_NATIVE_PROTO_MAP_LENGTH) {}
175 
SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const176 size_t ClassInfo2WrappedNativeProtoMap::SizeOfIncludingThis(
177     mozilla::MallocSizeOf mallocSizeOf) const {
178   size_t n = mallocSizeOf(this);
179   n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf);
180   for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) {
181     auto entry =
182         static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(iter.Get());
183     n += mallocSizeOf(entry->value);
184   }
185   return n;
186 }
187 
188 /***************************************************************************/
189 // implement NativeSetMap...
190 
Match(const PLDHashEntryHdr * entry,const void * key)191 bool NativeSetMap::Entry::Match(const PLDHashEntryHdr* entry, const void* key) {
192   auto Key = static_cast<const XPCNativeSetKey*>(key);
193   XPCNativeSet* SetInTable = ((Entry*)entry)->key_value;
194   XPCNativeSet* Set = Key->GetBaseSet();
195   XPCNativeInterface* Addition = Key->GetAddition();
196 
197   if (!Set) {
198     // This is a special case to deal with the invariant that says:
199     // "All sets have exactly one nsISupports interface and it comes first."
200     // See XPCNativeSet::NewInstance for details.
201     //
202     // Though we might have a key that represents only one interface, we
203     // know that if that one interface were contructed into a set then
204     // it would end up really being a set with two interfaces (except for
205     // the case where the one interface happened to be nsISupports).
206 
207     return (SetInTable->GetInterfaceCount() == 1 &&
208             SetInTable->GetInterfaceAt(0) == Addition) ||
209            (SetInTable->GetInterfaceCount() == 2 &&
210             SetInTable->GetInterfaceAt(1) == Addition);
211   }
212 
213   if (!Addition && Set == SetInTable) {
214     return true;
215   }
216 
217   uint16_t count = Set->GetInterfaceCount();
218   if (count + (Addition ? 1 : 0) != SetInTable->GetInterfaceCount()) {
219     return false;
220   }
221 
222   XPCNativeInterface** CurrentInTable = SetInTable->GetInterfaceArray();
223   XPCNativeInterface** Current = Set->GetInterfaceArray();
224   for (uint16_t i = 0; i < count; i++) {
225     if (*(Current++) != *(CurrentInTable++)) {
226       return false;
227     }
228   }
229   return !Addition || Addition == *(CurrentInTable++);
230 }
231 
232 const struct PLDHashTableOps NativeSetMap::Entry::sOps = {
233     HashNativeKey, Match, PLDHashTable::MoveEntryStub,
234     PLDHashTable::ClearEntryStub};
235 
NativeSetMap()236 NativeSetMap::NativeSetMap()
237     : mTable(&Entry::sOps, sizeof(Entry), XPC_NATIVE_SET_MAP_LENGTH) {}
238 
SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const239 size_t NativeSetMap::SizeOfIncludingThis(
240     mozilla::MallocSizeOf mallocSizeOf) const {
241   size_t n = mallocSizeOf(this);
242   n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf);
243   for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) {
244     auto entry = static_cast<NativeSetMap::Entry*>(iter.Get());
245     n += entry->key_value->SizeOfIncludingThis(mallocSizeOf);
246   }
247   return n;
248 }
249 
250 /***************************************************************************/
251 // implement XPCWrappedNativeProtoMap...
252 
XPCWrappedNativeProtoMap()253 XPCWrappedNativeProtoMap::XPCWrappedNativeProtoMap()
254     : mTable(PLDHashTable::StubOps(), sizeof(PLDHashEntryStub),
255              XPC_DYING_NATIVE_PROTO_MAP_LENGTH) {}
256 
257 /***************************************************************************/
258