diff options
Diffstat (limited to 'js/xpconnect/src/XPCMaps.h')
-rw-r--r-- | js/xpconnect/src/XPCMaps.h | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/js/xpconnect/src/XPCMaps.h b/js/xpconnect/src/XPCMaps.h new file mode 100644 index 0000000000..f1d32ab61c --- /dev/null +++ b/js/xpconnect/src/XPCMaps.h @@ -0,0 +1,386 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Private maps (hashtables). */ + +#ifndef xpcmaps_h___ +#define xpcmaps_h___ + +#include "mozilla/AllocPolicy.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/HashTable.h" + +#include "js/GCHashTable.h" + +/***************************************************************************/ +// default initial sizes for maps (hashtables) + +#define XPC_JS_MAP_LENGTH 32 + +#define XPC_NATIVE_MAP_LENGTH 8 +#define XPC_NATIVE_PROTO_MAP_LENGTH 8 +#define XPC_DYING_NATIVE_PROTO_MAP_LENGTH 8 +#define XPC_NATIVE_INTERFACE_MAP_LENGTH 32 +#define XPC_NATIVE_SET_MAP_LENGTH 32 +#define XPC_WRAPPER_MAP_LENGTH 8 + +/*************************/ + +class JSObject2WrappedJSMap { + using Map = js::HashMap<JS::Heap<JSObject*>, nsXPCWrappedJS*, + js::StableCellHasher<JS::Heap<JSObject*>>, + InfallibleAllocPolicy>; + + public: + JSObject2WrappedJSMap() = default; + + inline nsXPCWrappedJS* Find(JSObject* Obj) { + MOZ_ASSERT(Obj, "bad param"); + Map::Ptr p = mTable.lookup(Obj); + return p ? p->value() : nullptr; + } + +#ifdef DEBUG + inline bool HasWrapper(nsXPCWrappedJS* wrapper) { + for (auto iter = mTable.iter(); !iter.done(); iter.next()) { + if (iter.get().value() == wrapper) { + return true; + } + } + return false; + } +#endif + + inline nsXPCWrappedJS* Add(JSContext* cx, nsXPCWrappedJS* wrapper) { + MOZ_ASSERT(wrapper, "bad param"); + JSObject* obj = wrapper->GetJSObjectPreserveColor(); + Map::AddPtr p = mTable.lookupForAdd(obj); + if (p) { + return p->value(); + } + if (!mTable.add(p, obj, wrapper)) { + return nullptr; + } + return wrapper; + } + + inline void Remove(nsXPCWrappedJS* wrapper) { + MOZ_ASSERT(wrapper, "bad param"); + mTable.remove(wrapper->GetJSObjectPreserveColor()); + } + + inline uint32_t Count() { return mTable.count(); } + + inline void Dump(int16_t depth) { + for (auto iter = mTable.iter(); !iter.done(); iter.next()) { + iter.get().value()->DebugDump(depth); + } + } + + void UpdateWeakPointersAfterGC(JSTracer* trc); + + void ShutdownMarker(); + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + // Report the sum of SizeOfIncludingThis() for all wrapped JS in the map. + // Each wrapped JS is only in one map. + size_t SizeOfWrappedJS(mozilla::MallocSizeOf mallocSizeOf) const; + + private: + Map mTable{XPC_JS_MAP_LENGTH}; +}; + +/*************************/ + +class Native2WrappedNativeMap { + using Map = mozilla::HashMap<nsISupports*, XPCWrappedNative*, + mozilla::DefaultHasher<nsISupports*>, + mozilla::MallocAllocPolicy>; + + public: + Native2WrappedNativeMap(); + + XPCWrappedNative* Find(nsISupports* obj) const { + MOZ_ASSERT(obj, "bad param"); + Map::Ptr ptr = mMap.lookup(obj); + return ptr ? ptr->value() : nullptr; + } + + XPCWrappedNative* Add(XPCWrappedNative* wrapper) { + MOZ_ASSERT(wrapper, "bad param"); + nsISupports* obj = wrapper->GetIdentityObject(); + Map::AddPtr ptr = mMap.lookupForAdd(obj); + MOZ_ASSERT(!ptr, "wrapper already in new scope!"); + if (ptr) { + return ptr->value(); + } + if (!mMap.add(ptr, obj, wrapper)) { + return nullptr; + } + return wrapper; + } + + void Clear() { mMap.clear(); } + + uint32_t Count() { return mMap.count(); } + + Map::Iterator Iter() { return mMap.iter(); } + Map::ModIterator ModIter() { return mMap.modIter(); } + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + private: + Map mMap; +}; + +/*************************/ + +struct IIDHasher { + using Key = const nsIID*; + using Lookup = Key; + + // Note this is returning the hash of the bit pattern of the first part of the + // nsID, not the hash of the pointer to the nsID. + static mozilla::HashNumber hash(Lookup lookup) { + uintptr_t v; + memcpy(&v, lookup, sizeof(v)); + return mozilla::HashGeneric(v); + } + + static bool match(Key key, Lookup lookup) { return key->Equals(*lookup); } +}; + +class IID2NativeInterfaceMap { + using Map = mozilla::HashMap<const nsIID*, XPCNativeInterface*, IIDHasher, + mozilla::MallocAllocPolicy>; + + public: + IID2NativeInterfaceMap(); + + XPCNativeInterface* Find(REFNSIID iid) const { + Map::Ptr ptr = mMap.lookup(&iid); + return ptr ? ptr->value() : nullptr; + } + + bool AddNew(XPCNativeInterface* iface) { + MOZ_ASSERT(iface, "bad param"); + const nsIID* iid = iface->GetIID(); + return mMap.putNew(iid, iface); + } + + void Remove(XPCNativeInterface* iface) { + MOZ_ASSERT(iface, "bad param"); + mMap.remove(iface->GetIID()); + } + + uint32_t Count() { return mMap.count(); } + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + void Trace(JSTracer* trc); + + private: + Map mMap; +}; + +/*************************/ + +class ClassInfo2NativeSetMap { + using Map = mozilla::HashMap<nsIClassInfo*, RefPtr<XPCNativeSet>, + mozilla::DefaultHasher<nsIClassInfo*>, + mozilla::MallocAllocPolicy>; + + public: + ClassInfo2NativeSetMap(); + + XPCNativeSet* Find(nsIClassInfo* info) const { + auto ptr = mMap.lookup(info); + return ptr ? ptr->value().get() : nullptr; + } + + XPCNativeSet* Add(nsIClassInfo* info, XPCNativeSet* set) { + MOZ_ASSERT(info, "bad param"); + auto ptr = mMap.lookupForAdd(info); + if (ptr) { + return ptr->value(); + } + if (!mMap.add(ptr, info, set)) { + return nullptr; + } + return set; + } + + void Remove(nsIClassInfo* info) { + MOZ_ASSERT(info, "bad param"); + mMap.remove(info); + } + + uint32_t Count() { return mMap.count(); } + + // ClassInfo2NativeSetMap holds pointers to *some* XPCNativeSets. + // So we don't want to count those XPCNativeSets, because they are better + // counted elsewhere (i.e. in XPCJSContext::mNativeSetMap, which holds + // pointers to *all* XPCNativeSets). Hence the "Shallow". + size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); + + private: + Map mMap; +}; + +/*************************/ + +class ClassInfo2WrappedNativeProtoMap { + using Map = mozilla::HashMap<nsIClassInfo*, XPCWrappedNativeProto*, + mozilla::DefaultHasher<nsIClassInfo*>, + mozilla::MallocAllocPolicy>; + + public: + ClassInfo2WrappedNativeProtoMap(); + + XPCWrappedNativeProto* Find(nsIClassInfo* info) const { + auto ptr = mMap.lookup(info); + return ptr ? ptr->value() : nullptr; + } + + XPCWrappedNativeProto* Add(nsIClassInfo* info, XPCWrappedNativeProto* proto) { + MOZ_ASSERT(info, "bad param"); + auto ptr = mMap.lookupForAdd(info); + if (ptr) { + return ptr->value(); + } + if (!mMap.add(ptr, info, proto)) { + return nullptr; + } + return proto; + } + + void Clear() { mMap.clear(); } + + uint32_t Count() { return mMap.count(); } + + Map::Iterator Iter() { return mMap.iter(); } + Map::ModIterator ModIter() { return mMap.modIter(); } + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + private: + Map mMap; +}; + +/*************************/ + +struct NativeSetHasher { + using Key = XPCNativeSet*; + using Lookup = const XPCNativeSetKey*; + + static mozilla::HashNumber hash(Lookup lookup) { return lookup->Hash(); } + static bool match(Key key, Lookup lookup); +}; + +class NativeSetMap { + using Set = mozilla::HashSet<XPCNativeSet*, NativeSetHasher, + mozilla::MallocAllocPolicy>; + + public: + NativeSetMap(); + + XPCNativeSet* Find(const XPCNativeSetKey* key) const { + auto ptr = mSet.lookup(key); + return ptr ? *ptr : nullptr; + } + + XPCNativeSet* Add(const XPCNativeSetKey* key, XPCNativeSet* set) { + MOZ_ASSERT(key, "bad param"); + MOZ_ASSERT(set, "bad param"); + auto ptr = mSet.lookupForAdd(key); + if (ptr) { + return *ptr; + } + if (!mSet.add(ptr, set)) { + return nullptr; + } + return set; + } + + bool AddNew(const XPCNativeSetKey* key, XPCNativeSet* set) { + XPCNativeSet* set2 = Add(key, set); + if (!set2) { + return false; + } +#ifdef DEBUG + XPCNativeSetKey key2(set); + MOZ_ASSERT(key->Hash() == key2.Hash()); + MOZ_ASSERT(set2 == set, "Should not have found an existing entry"); +#endif + return true; + } + + void Remove(XPCNativeSet* set) { + MOZ_ASSERT(set, "bad param"); + + XPCNativeSetKey key(set); + mSet.remove(&key); + } + + uint32_t Count() { return mSet.count(); } + + Set::Iterator Iter() { return mSet.iter(); } + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + private: + Set mSet; +}; + +/***************************************************************************/ + +class JSObject2JSObjectMap { + using Map = JS::GCHashMap<JS::Heap<JSObject*>, JS::Heap<JSObject*>, + js::StableCellHasher<JS::Heap<JSObject*>>, + js::SystemAllocPolicy>; + + public: + JSObject2JSObjectMap() = default; + + inline JSObject* Find(JSObject* key) { + MOZ_ASSERT(key, "bad param"); + if (Map::Ptr p = mTable.lookup(key)) { + return p->value(); + } + return nullptr; + } + + /* Note: If the entry already exists, return the old value. */ + inline JSObject* Add(JSContext* cx, JSObject* key, JSObject* value) { + MOZ_ASSERT(key, "bad param"); + Map::AddPtr p = mTable.lookupForAdd(key); + if (p) { + JSObject* oldValue = p->value(); + p->value() = value; + return oldValue; + } + if (!mTable.add(p, key, value)) { + return nullptr; + } + MOZ_ASSERT(xpc::ObjectScope(key)->mWaiverWrapperMap == this); + return value; + } + + inline void Remove(JSObject* key) { + MOZ_ASSERT(key, "bad param"); + mTable.remove(key); + } + + inline uint32_t Count() { return mTable.count(); } + + void UpdateWeakPointers(JSTracer* trc) { mTable.traceWeak(trc); } + + private: + Map mTable{XPC_WRAPPER_MAP_LENGTH}; +}; + +#endif /* xpcmaps_h___ */ |