summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/src/XPCMaps.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/xpconnect/src/XPCMaps.h')
-rw-r--r--js/xpconnect/src/XPCMaps.h606
1 files changed, 606 insertions, 0 deletions
diff --git a/js/xpconnect/src/XPCMaps.h b/js/xpconnect/src/XPCMaps.h
new file mode 100644
index 000000000..80c51d477
--- /dev/null
+++ b/js/xpconnect/src/XPCMaps.h
@@ -0,0 +1,606 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=99: */
+/* 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/MemoryReporting.h"
+
+#include "js/GCHashTable.h"
+
+// Maps...
+
+// Note that most of the declarations for hash table entries begin with
+// a pointer to something or another. This makes them look enough like
+// the PLDHashEntryStub struct that the default ops (PLDHashTable::StubOps())
+// just do the right thing for most of our needs.
+
+// no virtuals in the maps - all the common stuff inlined
+// templates could be used to good effect here.
+
+/*************************/
+
+class JSObject2WrappedJSMap
+{
+ using Map = js::HashMap<JS::Heap<JSObject*>,
+ nsXPCWrappedJS*,
+ js::MovableCellHasher<JS::Heap<JSObject*>>,
+ InfallibleAllocPolicy>;
+
+public:
+ static JSObject2WrappedJSMap* newMap(int length) {
+ auto* map = new JSObject2WrappedJSMap();
+ if (!map->mTable.init(length)) {
+ // This is a decent estimate of the size of the hash table's
+ // entry storage. The |2| is because on average the capacity is
+ // twice the requested length.
+ NS_ABORT_OOM(length * 2 * sizeof(Map::Entry));
+ }
+ return map;
+ }
+
+ inline nsXPCWrappedJS* Find(JSObject* Obj) {
+ NS_PRECONDITION(Obj,"bad param");
+ Map::Ptr p = mTable.lookup(Obj);
+ return p ? p->value() : nullptr;
+ }
+
+#ifdef DEBUG
+ inline bool HasWrapper(nsXPCWrappedJS* wrapper) {
+ for (auto r = mTable.all(); !r.empty(); r.popFront()) {
+ if (r.front().value() == wrapper)
+ return true;
+ }
+ return false;
+ }
+#endif
+
+ inline nsXPCWrappedJS* Add(JSContext* cx, nsXPCWrappedJS* wrapper) {
+ NS_PRECONDITION(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) {
+ NS_PRECONDITION(wrapper,"bad param");
+ mTable.remove(wrapper->GetJSObjectPreserveColor());
+ }
+
+ inline uint32_t Count() {return mTable.count();}
+
+ inline void Dump(int16_t depth) {
+ for (Map::Range r = mTable.all(); !r.empty(); r.popFront())
+ r.front().value()->DebugDump(depth);
+ }
+
+ void UpdateWeakPointersAfterGC(XPCJSContext* context);
+
+ 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:
+ JSObject2WrappedJSMap() {}
+
+ Map mTable;
+};
+
+/*************************/
+
+class Native2WrappedNativeMap
+{
+public:
+ struct Entry : public PLDHashEntryHdr
+ {
+ nsISupports* key;
+ XPCWrappedNative* value;
+ };
+
+ static Native2WrappedNativeMap* newMap(int length);
+
+ inline XPCWrappedNative* Find(nsISupports* Obj)
+ {
+ NS_PRECONDITION(Obj,"bad param");
+ auto entry = static_cast<Entry*>(mTable.Search(Obj));
+ return entry ? entry->value : nullptr;
+ }
+
+ inline XPCWrappedNative* Add(XPCWrappedNative* wrapper)
+ {
+ NS_PRECONDITION(wrapper,"bad param");
+ nsISupports* obj = wrapper->GetIdentityObject();
+ MOZ_ASSERT(!Find(obj), "wrapper already in new scope!");
+ auto entry = static_cast<Entry*>(mTable.Add(obj, mozilla::fallible));
+ if (!entry)
+ return nullptr;
+ if (entry->key)
+ return entry->value;
+ entry->key = obj;
+ entry->value = wrapper;
+ return wrapper;
+ }
+
+ inline void Remove(XPCWrappedNative* wrapper)
+ {
+ NS_PRECONDITION(wrapper,"bad param");
+#ifdef DEBUG
+ XPCWrappedNative* wrapperInMap = Find(wrapper->GetIdentityObject());
+ MOZ_ASSERT(!wrapperInMap || wrapperInMap == wrapper,
+ "About to remove a different wrapper with the same "
+ "nsISupports identity! This will most likely cause serious "
+ "problems!");
+#endif
+ mTable.Remove(wrapper->GetIdentityObject());
+ }
+
+ inline uint32_t Count() { return mTable.EntryCount(); }
+
+ PLDHashTable::Iterator Iter() { return mTable.Iter(); }
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+
+private:
+ Native2WrappedNativeMap(); // no implementation
+ explicit Native2WrappedNativeMap(int size);
+
+private:
+ PLDHashTable mTable;
+};
+
+/*************************/
+
+class IID2WrappedJSClassMap
+{
+public:
+ struct Entry : public PLDHashEntryHdr
+ {
+ const nsIID* key;
+ nsXPCWrappedJSClass* value;
+
+ static const struct PLDHashTableOps sOps;
+ };
+
+ static IID2WrappedJSClassMap* newMap(int length);
+
+ inline nsXPCWrappedJSClass* Find(REFNSIID iid)
+ {
+ auto entry = static_cast<Entry*>(mTable.Search(&iid));
+ return entry ? entry->value : nullptr;
+ }
+
+ inline nsXPCWrappedJSClass* Add(nsXPCWrappedJSClass* clazz)
+ {
+ NS_PRECONDITION(clazz,"bad param");
+ const nsIID* iid = &clazz->GetIID();
+ auto entry = static_cast<Entry*>(mTable.Add(iid, mozilla::fallible));
+ if (!entry)
+ return nullptr;
+ if (entry->key)
+ return entry->value;
+ entry->key = iid;
+ entry->value = clazz;
+ return clazz;
+ }
+
+ inline void Remove(nsXPCWrappedJSClass* clazz)
+ {
+ NS_PRECONDITION(clazz,"bad param");
+ mTable.Remove(&clazz->GetIID());
+ }
+
+ inline uint32_t Count() { return mTable.EntryCount(); }
+
+#ifdef DEBUG
+ PLDHashTable::Iterator Iter() { return mTable.Iter(); }
+#endif
+
+private:
+ IID2WrappedJSClassMap(); // no implementation
+ explicit IID2WrappedJSClassMap(int size);
+private:
+ PLDHashTable mTable;
+};
+
+/*************************/
+
+class IID2NativeInterfaceMap
+{
+public:
+ struct Entry : public PLDHashEntryHdr
+ {
+ const nsIID* key;
+ XPCNativeInterface* value;
+
+ static const struct PLDHashTableOps sOps;
+ };
+
+ static IID2NativeInterfaceMap* newMap(int length);
+
+ inline XPCNativeInterface* Find(REFNSIID iid)
+ {
+ auto entry = static_cast<Entry*>(mTable.Search(&iid));
+ return entry ? entry->value : nullptr;
+ }
+
+ inline XPCNativeInterface* Add(XPCNativeInterface* iface)
+ {
+ NS_PRECONDITION(iface,"bad param");
+ const nsIID* iid = iface->GetIID();
+ auto entry = static_cast<Entry*>(mTable.Add(iid, mozilla::fallible));
+ if (!entry)
+ return nullptr;
+ if (entry->key)
+ return entry->value;
+ entry->key = iid;
+ entry->value = iface;
+ return iface;
+ }
+
+ inline void Remove(XPCNativeInterface* iface)
+ {
+ NS_PRECONDITION(iface,"bad param");
+ mTable.Remove(iface->GetIID());
+ }
+
+ inline uint32_t Count() { return mTable.EntryCount(); }
+
+ PLDHashTable::Iterator Iter() { return mTable.Iter(); }
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+
+private:
+ IID2NativeInterfaceMap(); // no implementation
+ explicit IID2NativeInterfaceMap(int size);
+
+private:
+ PLDHashTable mTable;
+};
+
+/*************************/
+
+class ClassInfo2NativeSetMap
+{
+public:
+ struct Entry : public PLDHashEntryHdr
+ {
+ nsIClassInfo* key;
+ XPCNativeSet* value; // strong reference
+ static const PLDHashTableOps sOps;
+
+ private:
+ static bool Match(const PLDHashEntryHdr* aEntry, const void* aKey);
+ static void Clear(PLDHashTable* aTable, PLDHashEntryHdr* aEntry);
+ };
+
+ static ClassInfo2NativeSetMap* newMap(int length);
+
+ inline XPCNativeSet* Find(nsIClassInfo* info)
+ {
+ auto entry = static_cast<Entry*>(mTable.Search(info));
+ return entry ? entry->value : nullptr;
+ }
+
+ inline XPCNativeSet* Add(nsIClassInfo* info, XPCNativeSet* set)
+ {
+ NS_PRECONDITION(info,"bad param");
+ auto entry = static_cast<Entry*>(mTable.Add(info, mozilla::fallible));
+ if (!entry)
+ return nullptr;
+ if (entry->key)
+ return entry->value;
+ entry->key = info;
+ NS_ADDREF(entry->value = set);
+ return set;
+ }
+
+ inline void Remove(nsIClassInfo* info)
+ {
+ NS_PRECONDITION(info,"bad param");
+ mTable.Remove(info);
+ }
+
+ inline uint32_t Count() { return mTable.EntryCount(); }
+
+ // 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:
+ ClassInfo2NativeSetMap(); // no implementation
+ explicit ClassInfo2NativeSetMap(int size);
+private:
+ PLDHashTable mTable;
+};
+
+/*************************/
+
+class ClassInfo2WrappedNativeProtoMap
+{
+public:
+ struct Entry : public PLDHashEntryHdr
+ {
+ nsIClassInfo* key;
+ XPCWrappedNativeProto* value;
+ };
+
+ static ClassInfo2WrappedNativeProtoMap* newMap(int length);
+
+ inline XPCWrappedNativeProto* Find(nsIClassInfo* info)
+ {
+ auto entry = static_cast<Entry*>(mTable.Search(info));
+ return entry ? entry->value : nullptr;
+ }
+
+ inline XPCWrappedNativeProto* Add(nsIClassInfo* info, XPCWrappedNativeProto* proto)
+ {
+ NS_PRECONDITION(info,"bad param");
+ auto entry = static_cast<Entry*>(mTable.Add(info, mozilla::fallible));
+ if (!entry)
+ return nullptr;
+ if (entry->key)
+ return entry->value;
+ entry->key = info;
+ entry->value = proto;
+ return proto;
+ }
+
+ inline void Remove(nsIClassInfo* info)
+ {
+ NS_PRECONDITION(info,"bad param");
+ mTable.Remove(info);
+ }
+
+ inline uint32_t Count() { return mTable.EntryCount(); }
+
+ PLDHashTable::Iterator Iter() { return mTable.Iter(); }
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+
+private:
+ ClassInfo2WrappedNativeProtoMap(); // no implementation
+ explicit ClassInfo2WrappedNativeProtoMap(int size);
+
+private:
+ PLDHashTable mTable;
+};
+
+/*************************/
+
+class NativeSetMap
+{
+public:
+ struct Entry : public PLDHashEntryHdr
+ {
+ XPCNativeSet* key_value;
+
+ static bool
+ Match(const PLDHashEntryHdr* entry, const void* key);
+
+ static const struct PLDHashTableOps sOps;
+ };
+
+ static NativeSetMap* newMap(int length);
+
+ inline XPCNativeSet* Find(XPCNativeSetKey* key)
+ {
+ auto entry = static_cast<Entry*>(mTable.Search(key));
+ return entry ? entry->key_value : nullptr;
+ }
+
+ inline XPCNativeSet* Add(const XPCNativeSetKey* key, XPCNativeSet* set)
+ {
+ MOZ_ASSERT(key, "bad param");
+ MOZ_ASSERT(set, "bad param");
+ auto entry = static_cast<Entry*>(mTable.Add(key, mozilla::fallible));
+ if (!entry)
+ return nullptr;
+ if (entry->key_value)
+ return entry->key_value;
+ entry->key_value = set;
+ 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;
+ }
+
+ inline void Remove(XPCNativeSet* set)
+ {
+ MOZ_ASSERT(set, "bad param");
+
+ XPCNativeSetKey key(set);
+ mTable.Remove(&key);
+ }
+
+ inline uint32_t Count() { return mTable.EntryCount(); }
+
+ PLDHashTable::Iterator Iter() { return mTable.Iter(); }
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+
+private:
+ NativeSetMap(); // no implementation
+ explicit NativeSetMap(int size);
+
+private:
+ PLDHashTable mTable;
+};
+
+/***************************************************************************/
+
+class IID2ThisTranslatorMap
+{
+public:
+ struct Entry : public PLDHashEntryHdr
+ {
+ nsIID key;
+ nsCOMPtr<nsIXPCFunctionThisTranslator> value;
+
+ static bool
+ Match(const PLDHashEntryHdr* entry, const void* key);
+
+ static void
+ Clear(PLDHashTable* table, PLDHashEntryHdr* entry);
+
+ static const struct PLDHashTableOps sOps;
+ };
+
+ static IID2ThisTranslatorMap* newMap(int length);
+
+ inline nsIXPCFunctionThisTranslator* Find(REFNSIID iid)
+ {
+ auto entry = static_cast<Entry*>(mTable.Search(&iid));
+ if (!entry) {
+ return nullptr;
+ }
+ return entry->value;
+ }
+
+ inline nsIXPCFunctionThisTranslator* Add(REFNSIID iid,
+ nsIXPCFunctionThisTranslator* obj)
+ {
+ auto entry = static_cast<Entry*>(mTable.Add(&iid, mozilla::fallible));
+ if (!entry)
+ return nullptr;
+ entry->value = obj;
+ entry->key = iid;
+ return obj;
+ }
+
+ inline void Remove(REFNSIID iid)
+ {
+ mTable.Remove(&iid);
+ }
+
+ inline uint32_t Count() { return mTable.EntryCount(); }
+
+private:
+ IID2ThisTranslatorMap(); // no implementation
+ explicit IID2ThisTranslatorMap(int size);
+private:
+ PLDHashTable mTable;
+};
+
+/***************************************************************************/
+
+class XPCWrappedNativeProtoMap
+{
+public:
+ typedef PLDHashEntryStub Entry;
+
+ static XPCWrappedNativeProtoMap* newMap(int length);
+
+ inline XPCWrappedNativeProto* Add(XPCWrappedNativeProto* proto)
+ {
+ NS_PRECONDITION(proto,"bad param");
+ auto entry = static_cast<PLDHashEntryStub*>
+ (mTable.Add(proto, mozilla::fallible));
+ if (!entry)
+ return nullptr;
+ if (entry->key)
+ return (XPCWrappedNativeProto*) entry->key;
+ entry->key = proto;
+ return proto;
+ }
+
+ inline void Remove(XPCWrappedNativeProto* proto)
+ {
+ NS_PRECONDITION(proto,"bad param");
+ mTable.Remove(proto);
+ }
+
+ inline uint32_t Count() { return mTable.EntryCount(); }
+
+ PLDHashTable::Iterator Iter() { return mTable.Iter(); }
+
+private:
+ XPCWrappedNativeProtoMap(); // no implementation
+ explicit XPCWrappedNativeProtoMap(int size);
+private:
+ PLDHashTable mTable;
+};
+
+/***************************************************************************/
+
+class JSObject2JSObjectMap
+{
+ using Map = JS::GCHashMap<JS::Heap<JSObject*>,
+ JS::Heap<JSObject*>,
+ js::MovableCellHasher<JS::Heap<JSObject*>>,
+ js::SystemAllocPolicy>;
+
+public:
+ static JSObject2JSObjectMap* newMap(int length) {
+ auto* map = new JSObject2JSObjectMap();
+ if (!map->mTable.init(length)) {
+ // This is a decent estimate of the size of the hash table's
+ // entry storage. The |2| is because on average the capacity is
+ // twice the requested length.
+ NS_ABORT_OOM(length * 2 * sizeof(Map::Entry));
+ }
+ return map;
+ }
+
+ inline JSObject* Find(JSObject* key) {
+ NS_PRECONDITION(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) {
+ NS_PRECONDITION(key,"bad param");
+ Map::AddPtr p = mTable.lookupForAdd(key);
+ if (p)
+ return p->value();
+ if (!mTable.add(p, key, value))
+ return nullptr;
+ MOZ_ASSERT(xpc::CompartmentPrivate::Get(key)->scope->mWaiverWrapperMap == this);
+ return value;
+ }
+
+ inline void Remove(JSObject* key) {
+ NS_PRECONDITION(key,"bad param");
+ mTable.remove(key);
+ }
+
+ inline uint32_t Count() { return mTable.count(); }
+
+ void Sweep() {
+ mTable.sweep();
+ }
+
+private:
+ JSObject2JSObjectMap() {}
+
+ Map mTable;
+};
+
+#endif /* xpcmaps_h___ */