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.h386
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___ */