XPCMaps.h (10134B)
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 #ifndef xpcmaps_h___ 10 #define xpcmaps_h___ 11 12 #include "mozilla/AllocPolicy.h" 13 #include "mozilla/MemoryReporting.h" 14 #include "mozilla/HashTable.h" 15 16 #include "js/GCHashTable.h" 17 18 /***************************************************************************/ 19 // default initial sizes for maps (hashtables) 20 21 #define XPC_JS_MAP_LENGTH 32 22 23 #define XPC_NATIVE_MAP_LENGTH 8 24 #define XPC_NATIVE_PROTO_MAP_LENGTH 8 25 #define XPC_DYING_NATIVE_PROTO_MAP_LENGTH 8 26 #define XPC_NATIVE_INTERFACE_MAP_LENGTH 32 27 #define XPC_NATIVE_SET_MAP_LENGTH 32 28 #define XPC_WRAPPER_MAP_LENGTH 8 29 30 /*************************/ 31 32 class JSObject2WrappedJSMap { 33 using Map = js::HashMap<JS::Heap<JSObject*>, nsXPCWrappedJS*, 34 js::StableCellHasher<JS::Heap<JSObject*>>, 35 InfallibleAllocPolicy>; 36 37 public: 38 JSObject2WrappedJSMap() = default; 39 40 inline nsXPCWrappedJS* Find(JSObject* Obj) { 41 MOZ_ASSERT(Obj, "bad param"); 42 Map::Ptr p = mTable.lookup(Obj); 43 return p ? p->value() : nullptr; 44 } 45 46 #ifdef DEBUG 47 inline bool HasWrapper(nsXPCWrappedJS* wrapper) { 48 for (auto iter = mTable.iter(); !iter.done(); iter.next()) { 49 if (iter.get().value() == wrapper) { 50 return true; 51 } 52 } 53 return false; 54 } 55 #endif 56 57 inline nsXPCWrappedJS* Add(JSContext* cx, nsXPCWrappedJS* wrapper) { 58 MOZ_ASSERT(wrapper, "bad param"); 59 JSObject* obj = wrapper->GetJSObjectPreserveColor(); 60 Map::AddPtr p = mTable.lookupForAdd(obj); 61 if (p) { 62 return p->value(); 63 } 64 if (!mTable.add(p, obj, wrapper)) { 65 return nullptr; 66 } 67 return wrapper; 68 } 69 70 inline void Remove(nsXPCWrappedJS* wrapper) { 71 MOZ_ASSERT(wrapper, "bad param"); 72 mTable.remove(wrapper->GetJSObjectPreserveColor()); 73 } 74 75 inline uint32_t Count() { return mTable.count(); } 76 77 inline void Dump(int16_t depth) { 78 for (auto iter = mTable.iter(); !iter.done(); iter.next()) { 79 iter.get().value()->DebugDump(depth); 80 } 81 } 82 83 void UpdateWeakPointersAfterGC(JSTracer* trc); 84 85 void ShutdownMarker(); 86 87 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 88 89 // Report the sum of SizeOfIncludingThis() for all wrapped JS in the map. 90 // Each wrapped JS is only in one map. 91 size_t SizeOfWrappedJS(mozilla::MallocSizeOf mallocSizeOf) const; 92 93 private: 94 Map mTable{XPC_JS_MAP_LENGTH}; 95 }; 96 97 /*************************/ 98 99 class Native2WrappedNativeMap { 100 using Map = mozilla::HashMap<nsISupports*, XPCWrappedNative*, 101 mozilla::DefaultHasher<nsISupports*>, 102 mozilla::MallocAllocPolicy>; 103 104 public: 105 Native2WrappedNativeMap(); 106 107 XPCWrappedNative* Find(nsISupports* obj) const { 108 MOZ_ASSERT(obj, "bad param"); 109 Map::Ptr ptr = mMap.lookup(obj); 110 return ptr ? ptr->value() : nullptr; 111 } 112 113 XPCWrappedNative* Add(XPCWrappedNative* wrapper) { 114 MOZ_ASSERT(wrapper, "bad param"); 115 nsISupports* obj = wrapper->GetIdentityObject(); 116 Map::AddPtr ptr = mMap.lookupForAdd(obj); 117 MOZ_ASSERT(!ptr, "wrapper already in new scope!"); 118 if (ptr) { 119 return ptr->value(); 120 } 121 if (!mMap.add(ptr, obj, wrapper)) { 122 return nullptr; 123 } 124 return wrapper; 125 } 126 127 void Clear() { mMap.clear(); } 128 129 uint32_t Count() { return mMap.count(); } 130 131 Map::Iterator Iter() { return mMap.iter(); } 132 Map::ModIterator ModIter() { return mMap.modIter(); } 133 134 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 135 136 private: 137 Map mMap; 138 }; 139 140 /*************************/ 141 142 struct IIDHasher { 143 using Key = const nsIID*; 144 using Lookup = Key; 145 146 // Note this is returning the hash of the bit pattern of the first part of the 147 // nsID, not the hash of the pointer to the nsID. 148 static mozilla::HashNumber hash(Lookup lookup) { 149 uintptr_t v; 150 memcpy(&v, lookup, sizeof(v)); 151 return mozilla::HashGeneric(v); 152 } 153 154 static bool match(Key key, Lookup lookup) { return key->Equals(*lookup); } 155 }; 156 157 class IID2NativeInterfaceMap { 158 using Map = mozilla::HashMap<const nsIID*, XPCNativeInterface*, IIDHasher, 159 mozilla::MallocAllocPolicy>; 160 161 public: 162 IID2NativeInterfaceMap(); 163 164 XPCNativeInterface* Find(REFNSIID iid) const { 165 Map::Ptr ptr = mMap.lookup(&iid); 166 return ptr ? ptr->value() : nullptr; 167 } 168 169 bool AddNew(XPCNativeInterface* iface) { 170 MOZ_ASSERT(iface, "bad param"); 171 const nsIID* iid = iface->GetIID(); 172 return mMap.putNew(iid, iface); 173 } 174 175 void Remove(XPCNativeInterface* iface) { 176 MOZ_ASSERT(iface, "bad param"); 177 mMap.remove(iface->GetIID()); 178 } 179 180 uint32_t Count() { return mMap.count(); } 181 182 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 183 184 void Trace(JSTracer* trc); 185 186 private: 187 Map mMap; 188 }; 189 190 /*************************/ 191 192 class ClassInfo2NativeSetMap { 193 using Map = mozilla::HashMap<nsIClassInfo*, RefPtr<XPCNativeSet>, 194 mozilla::DefaultHasher<nsIClassInfo*>, 195 mozilla::MallocAllocPolicy>; 196 197 public: 198 ClassInfo2NativeSetMap(); 199 200 XPCNativeSet* Find(nsIClassInfo* info) const { 201 auto ptr = mMap.lookup(info); 202 return ptr ? ptr->value().get() : nullptr; 203 } 204 205 XPCNativeSet* Add(nsIClassInfo* info, XPCNativeSet* set) { 206 MOZ_ASSERT(info, "bad param"); 207 auto ptr = mMap.lookupForAdd(info); 208 if (ptr) { 209 return ptr->value(); 210 } 211 if (!mMap.add(ptr, info, set)) { 212 return nullptr; 213 } 214 return set; 215 } 216 217 void Remove(nsIClassInfo* info) { 218 MOZ_ASSERT(info, "bad param"); 219 mMap.remove(info); 220 } 221 222 uint32_t Count() { return mMap.count(); } 223 224 // ClassInfo2NativeSetMap holds pointers to *some* XPCNativeSets. 225 // So we don't want to count those XPCNativeSets, because they are better 226 // counted elsewhere (i.e. in XPCJSContext::mNativeSetMap, which holds 227 // pointers to *all* XPCNativeSets). Hence the "Shallow". 228 size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); 229 230 private: 231 Map mMap; 232 }; 233 234 /*************************/ 235 236 class ClassInfo2WrappedNativeProtoMap { 237 using Map = mozilla::HashMap<nsIClassInfo*, XPCWrappedNativeProto*, 238 mozilla::DefaultHasher<nsIClassInfo*>, 239 mozilla::MallocAllocPolicy>; 240 241 public: 242 ClassInfo2WrappedNativeProtoMap(); 243 244 XPCWrappedNativeProto* Find(nsIClassInfo* info) const { 245 auto ptr = mMap.lookup(info); 246 return ptr ? ptr->value() : nullptr; 247 } 248 249 XPCWrappedNativeProto* Add(nsIClassInfo* info, XPCWrappedNativeProto* proto) { 250 MOZ_ASSERT(info, "bad param"); 251 auto ptr = mMap.lookupForAdd(info); 252 if (ptr) { 253 return ptr->value(); 254 } 255 if (!mMap.add(ptr, info, proto)) { 256 return nullptr; 257 } 258 return proto; 259 } 260 261 void Clear() { mMap.clear(); } 262 263 uint32_t Count() { return mMap.count(); } 264 265 Map::Iterator Iter() { return mMap.iter(); } 266 Map::ModIterator ModIter() { return mMap.modIter(); } 267 268 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 269 270 private: 271 Map mMap; 272 }; 273 274 /*************************/ 275 276 struct NativeSetHasher { 277 using Key = XPCNativeSet*; 278 using Lookup = const XPCNativeSetKey*; 279 280 static mozilla::HashNumber hash(Lookup lookup) { return lookup->Hash(); } 281 static bool match(Key key, Lookup lookup); 282 }; 283 284 class NativeSetMap { 285 using Set = mozilla::HashSet<XPCNativeSet*, NativeSetHasher, 286 mozilla::MallocAllocPolicy>; 287 288 public: 289 NativeSetMap(); 290 291 XPCNativeSet* Find(const XPCNativeSetKey* key) const { 292 auto ptr = mSet.lookup(key); 293 return ptr ? *ptr : nullptr; 294 } 295 296 XPCNativeSet* Add(const XPCNativeSetKey* key, XPCNativeSet* set) { 297 MOZ_ASSERT(key, "bad param"); 298 MOZ_ASSERT(set, "bad param"); 299 auto ptr = mSet.lookupForAdd(key); 300 if (ptr) { 301 return *ptr; 302 } 303 if (!mSet.add(ptr, set)) { 304 return nullptr; 305 } 306 return set; 307 } 308 309 bool AddNew(const XPCNativeSetKey* key, XPCNativeSet* set) { 310 XPCNativeSet* set2 = Add(key, set); 311 if (!set2) { 312 return false; 313 } 314 #ifdef DEBUG 315 XPCNativeSetKey key2(set); 316 MOZ_ASSERT(key->Hash() == key2.Hash()); 317 MOZ_ASSERT(set2 == set, "Should not have found an existing entry"); 318 #endif 319 return true; 320 } 321 322 void Remove(XPCNativeSet* set) { 323 MOZ_ASSERT(set, "bad param"); 324 325 XPCNativeSetKey key(set); 326 mSet.remove(&key); 327 } 328 329 uint32_t Count() { return mSet.count(); } 330 331 Set::Iterator Iter() { return mSet.iter(); } 332 333 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 334 335 private: 336 Set mSet; 337 }; 338 339 /***************************************************************************/ 340 341 class JSObject2JSObjectMap { 342 using Map = JS::GCHashMap<JS::Heap<JSObject*>, JS::Heap<JSObject*>, 343 js::StableCellHasher<JS::Heap<JSObject*>>, 344 js::SystemAllocPolicy>; 345 346 public: 347 JSObject2JSObjectMap() = default; 348 349 inline JSObject* Find(JSObject* key) { 350 MOZ_ASSERT(key, "bad param"); 351 if (Map::Ptr p = mTable.lookup(key)) { 352 return p->value(); 353 } 354 return nullptr; 355 } 356 357 /* Note: If the entry already exists, return the old value. */ 358 inline JSObject* Add(JSContext* cx, JSObject* key, JSObject* value) { 359 MOZ_ASSERT(key, "bad param"); 360 Map::AddPtr p = mTable.lookupForAdd(key); 361 if (p) { 362 JSObject* oldValue = p->value(); 363 p->value() = value; 364 return oldValue; 365 } 366 if (!mTable.add(p, key, value)) { 367 return nullptr; 368 } 369 MOZ_ASSERT(xpc::ObjectScope(key)->mWaiverWrapperMap == this); 370 return value; 371 } 372 373 inline void Remove(JSObject* key) { 374 MOZ_ASSERT(key, "bad param"); 375 mTable.remove(key); 376 } 377 378 inline uint32_t Count() { return mTable.count(); } 379 380 void UpdateWeakPointers(JSTracer* trc) { mTable.traceWeak(trc); } 381 382 private: 383 Map mTable{XPC_WRAPPER_MAP_LENGTH}; 384 }; 385 386 #endif /* xpcmaps_h___ */