michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim: set ts=8 sts=4 et sw=4 tw=99: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* Private maps (hashtables). */ michael@0: michael@0: #ifndef xpcmaps_h___ michael@0: #define xpcmaps_h___ michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: michael@0: michael@0: // Maps... michael@0: michael@0: // Note that most of the declarations for hash table entries begin with michael@0: // a pointer to something or another. This makes them look enough like michael@0: // the PLDHashEntryStub struct that the default OPs (PL_DHashGetStubOps()) michael@0: // just do the right thing for most of our needs. michael@0: michael@0: // no virtuals in the maps - all the common stuff inlined michael@0: // templates could be used to good effect here. michael@0: michael@0: /*************************/ michael@0: michael@0: class JSObject2WrappedJSMap michael@0: { michael@0: typedef js::HashMap, michael@0: js::SystemAllocPolicy> Map; michael@0: michael@0: public: michael@0: static JSObject2WrappedJSMap* newMap(int size) { michael@0: JSObject2WrappedJSMap* map = new JSObject2WrappedJSMap(); michael@0: if (map && map->mTable.init(size)) michael@0: return map; michael@0: delete map; michael@0: return nullptr; michael@0: } michael@0: michael@0: inline nsXPCWrappedJS* Find(JSObject* Obj) { michael@0: NS_PRECONDITION(Obj,"bad param"); michael@0: Map::Ptr p = mTable.lookup(Obj); michael@0: return p ? p->value() : nullptr; michael@0: } michael@0: michael@0: inline nsXPCWrappedJS* Add(JSContext* cx, nsXPCWrappedJS* wrapper) { michael@0: NS_PRECONDITION(wrapper,"bad param"); michael@0: JSObject* obj = wrapper->GetJSObjectPreserveColor(); michael@0: Map::AddPtr p = mTable.lookupForAdd(obj); michael@0: if (p) michael@0: return p->value(); michael@0: if (!mTable.add(p, obj, wrapper)) michael@0: return nullptr; michael@0: JS_StoreObjectPostBarrierCallback(cx, KeyMarkCallback, obj, this); michael@0: return wrapper; michael@0: } michael@0: michael@0: inline void Remove(nsXPCWrappedJS* wrapper) { michael@0: NS_PRECONDITION(wrapper,"bad param"); michael@0: mTable.remove(wrapper->GetJSObjectPreserveColor()); michael@0: } michael@0: michael@0: inline uint32_t Count() {return mTable.count();} michael@0: michael@0: inline void Dump(int16_t depth) { michael@0: for (Map::Range r = mTable.all(); !r.empty(); r.popFront()) michael@0: r.front().value()->DebugDump(depth); michael@0: } michael@0: michael@0: void FindDyingJSObjects(nsTArray* dying); michael@0: michael@0: void ShutdownMarker(); michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) { michael@0: size_t n = mallocSizeOf(this); michael@0: n += mTable.sizeOfExcludingThis(mallocSizeOf); michael@0: return n; michael@0: } michael@0: michael@0: private: michael@0: JSObject2WrappedJSMap() {} michael@0: michael@0: /* michael@0: * This function is called during minor GCs for each key in the HashMap that michael@0: * has been moved. michael@0: */ michael@0: static void KeyMarkCallback(JSTracer *trc, JSObject *key, void *data) { michael@0: JSObject2WrappedJSMap* self = static_cast(data); michael@0: JSObject *prior = key; michael@0: JS_CallObjectTracer(trc, &key, "XPCJSRuntime::mWrappedJSMap key"); michael@0: self->mTable.rekeyIfMoved(prior, key); michael@0: } michael@0: michael@0: Map mTable; michael@0: }; michael@0: michael@0: /*************************/ michael@0: michael@0: class Native2WrappedNativeMap michael@0: { michael@0: public: michael@0: struct Entry : public PLDHashEntryHdr michael@0: { michael@0: nsISupports* key; michael@0: XPCWrappedNative* value; michael@0: }; michael@0: michael@0: static Native2WrappedNativeMap* newMap(int size); michael@0: michael@0: inline XPCWrappedNative* Find(nsISupports* Obj) michael@0: { michael@0: NS_PRECONDITION(Obj,"bad param"); michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, Obj, PL_DHASH_LOOKUP); michael@0: if (PL_DHASH_ENTRY_IS_FREE(entry)) michael@0: return nullptr; michael@0: return entry->value; michael@0: } michael@0: michael@0: inline XPCWrappedNative* Add(XPCWrappedNative* wrapper) michael@0: { michael@0: NS_PRECONDITION(wrapper,"bad param"); michael@0: nsISupports* obj = wrapper->GetIdentityObject(); michael@0: MOZ_ASSERT(!Find(obj), "wrapper already in new scope!"); michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, obj, PL_DHASH_ADD); michael@0: if (!entry) michael@0: return nullptr; michael@0: if (entry->key) michael@0: return entry->value; michael@0: entry->key = obj; michael@0: entry->value = wrapper; michael@0: return wrapper; michael@0: } michael@0: michael@0: inline void Remove(XPCWrappedNative* wrapper) michael@0: { michael@0: NS_PRECONDITION(wrapper,"bad param"); michael@0: #ifdef DEBUG michael@0: XPCWrappedNative* wrapperInMap = Find(wrapper->GetIdentityObject()); michael@0: MOZ_ASSERT(!wrapperInMap || wrapperInMap == wrapper, michael@0: "About to remove a different wrapper with the same " michael@0: "nsISupports identity! This will most likely cause serious " michael@0: "problems!"); michael@0: #endif michael@0: PL_DHashTableOperate(mTable, wrapper->GetIdentityObject(), PL_DHASH_REMOVE); michael@0: } michael@0: michael@0: inline uint32_t Count() {return mTable->entryCount;} michael@0: inline uint32_t Enumerate(PLDHashEnumerator f, void *arg) michael@0: {return PL_DHashTableEnumerate(mTable, f, arg);} michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); michael@0: michael@0: ~Native2WrappedNativeMap(); michael@0: private: michael@0: Native2WrappedNativeMap(); // no implementation michael@0: Native2WrappedNativeMap(int size); michael@0: michael@0: static size_t SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr, mozilla::MallocSizeOf mallocSizeOf, void *); michael@0: michael@0: private: michael@0: PLDHashTable *mTable; michael@0: }; michael@0: michael@0: /*************************/ michael@0: michael@0: class IID2WrappedJSClassMap michael@0: { michael@0: public: michael@0: struct Entry : public PLDHashEntryHdr michael@0: { michael@0: const nsIID* key; michael@0: nsXPCWrappedJSClass* value; michael@0: michael@0: static const struct PLDHashTableOps sOps; michael@0: }; michael@0: michael@0: static IID2WrappedJSClassMap* newMap(int size); michael@0: michael@0: inline nsXPCWrappedJSClass* Find(REFNSIID iid) michael@0: { michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, &iid, PL_DHASH_LOOKUP); michael@0: if (PL_DHASH_ENTRY_IS_FREE(entry)) michael@0: return nullptr; michael@0: return entry->value; michael@0: } michael@0: michael@0: inline nsXPCWrappedJSClass* Add(nsXPCWrappedJSClass* clazz) michael@0: { michael@0: NS_PRECONDITION(clazz,"bad param"); michael@0: const nsIID* iid = &clazz->GetIID(); michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, iid, PL_DHASH_ADD); michael@0: if (!entry) michael@0: return nullptr; michael@0: if (entry->key) michael@0: return entry->value; michael@0: entry->key = iid; michael@0: entry->value = clazz; michael@0: return clazz; michael@0: } michael@0: michael@0: inline void Remove(nsXPCWrappedJSClass* clazz) michael@0: { michael@0: NS_PRECONDITION(clazz,"bad param"); michael@0: PL_DHashTableOperate(mTable, &clazz->GetIID(), PL_DHASH_REMOVE); michael@0: } michael@0: michael@0: inline uint32_t Count() {return mTable->entryCount;} michael@0: inline uint32_t Enumerate(PLDHashEnumerator f, void *arg) michael@0: {return PL_DHashTableEnumerate(mTable, f, arg);} michael@0: michael@0: ~IID2WrappedJSClassMap(); michael@0: private: michael@0: IID2WrappedJSClassMap(); // no implementation michael@0: IID2WrappedJSClassMap(int size); michael@0: private: michael@0: PLDHashTable *mTable; michael@0: }; michael@0: michael@0: /*************************/ michael@0: michael@0: class IID2NativeInterfaceMap michael@0: { michael@0: public: michael@0: struct Entry : public PLDHashEntryHdr michael@0: { michael@0: const nsIID* key; michael@0: XPCNativeInterface* value; michael@0: michael@0: static const struct PLDHashTableOps sOps; michael@0: }; michael@0: michael@0: static IID2NativeInterfaceMap* newMap(int size); michael@0: michael@0: inline XPCNativeInterface* Find(REFNSIID iid) michael@0: { michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, &iid, PL_DHASH_LOOKUP); michael@0: if (PL_DHASH_ENTRY_IS_FREE(entry)) michael@0: return nullptr; michael@0: return entry->value; michael@0: } michael@0: michael@0: inline XPCNativeInterface* Add(XPCNativeInterface* iface) michael@0: { michael@0: NS_PRECONDITION(iface,"bad param"); michael@0: const nsIID* iid = iface->GetIID(); michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, iid, PL_DHASH_ADD); michael@0: if (!entry) michael@0: return nullptr; michael@0: if (entry->key) michael@0: return entry->value; michael@0: entry->key = iid; michael@0: entry->value = iface; michael@0: return iface; michael@0: } michael@0: michael@0: inline void Remove(XPCNativeInterface* iface) michael@0: { michael@0: NS_PRECONDITION(iface,"bad param"); michael@0: PL_DHashTableOperate(mTable, iface->GetIID(), PL_DHASH_REMOVE); michael@0: } michael@0: michael@0: inline uint32_t Count() {return mTable->entryCount;} michael@0: inline uint32_t Enumerate(PLDHashEnumerator f, void *arg) michael@0: {return PL_DHashTableEnumerate(mTable, f, arg);} michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); michael@0: michael@0: ~IID2NativeInterfaceMap(); michael@0: private: michael@0: IID2NativeInterfaceMap(); // no implementation michael@0: IID2NativeInterfaceMap(int size); michael@0: michael@0: static size_t SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr, mozilla::MallocSizeOf mallocSizeOf, void *); michael@0: michael@0: private: michael@0: PLDHashTable *mTable; michael@0: }; michael@0: michael@0: /*************************/ michael@0: michael@0: class ClassInfo2NativeSetMap michael@0: { michael@0: public: michael@0: struct Entry : public PLDHashEntryHdr michael@0: { michael@0: nsIClassInfo* key; michael@0: XPCNativeSet* value; michael@0: }; michael@0: michael@0: static ClassInfo2NativeSetMap* newMap(int size); michael@0: michael@0: inline XPCNativeSet* Find(nsIClassInfo* info) michael@0: { michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, info, PL_DHASH_LOOKUP); michael@0: if (PL_DHASH_ENTRY_IS_FREE(entry)) michael@0: return nullptr; michael@0: return entry->value; michael@0: } michael@0: michael@0: inline XPCNativeSet* Add(nsIClassInfo* info, XPCNativeSet* set) michael@0: { michael@0: NS_PRECONDITION(info,"bad param"); michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, info, PL_DHASH_ADD); michael@0: if (!entry) michael@0: return nullptr; michael@0: if (entry->key) michael@0: return entry->value; michael@0: entry->key = info; michael@0: entry->value = set; michael@0: return set; michael@0: } michael@0: michael@0: inline void Remove(nsIClassInfo* info) michael@0: { michael@0: NS_PRECONDITION(info,"bad param"); michael@0: PL_DHashTableOperate(mTable, info, PL_DHASH_REMOVE); michael@0: } michael@0: michael@0: inline uint32_t Count() {return mTable->entryCount;} michael@0: inline uint32_t Enumerate(PLDHashEnumerator f, void *arg) michael@0: {return PL_DHashTableEnumerate(mTable, f, arg);} michael@0: michael@0: // ClassInfo2NativeSetMap holds pointers to *some* XPCNativeSets. michael@0: // So we don't want to count those XPCNativeSets, because they are better michael@0: // counted elsewhere (i.e. in XPCJSRuntime::mNativeSetMap, which holds michael@0: // pointers to *all* XPCNativeSets). Hence the "Shallow". michael@0: size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); michael@0: michael@0: ~ClassInfo2NativeSetMap(); michael@0: private: michael@0: ClassInfo2NativeSetMap(); // no implementation michael@0: ClassInfo2NativeSetMap(int size); michael@0: private: michael@0: PLDHashTable *mTable; michael@0: }; michael@0: michael@0: /*************************/ michael@0: michael@0: class ClassInfo2WrappedNativeProtoMap michael@0: { michael@0: public: michael@0: struct Entry : public PLDHashEntryHdr michael@0: { michael@0: nsIClassInfo* key; michael@0: XPCWrappedNativeProto* value; michael@0: }; michael@0: michael@0: static ClassInfo2WrappedNativeProtoMap* newMap(int size); michael@0: michael@0: inline XPCWrappedNativeProto* Find(nsIClassInfo* info) michael@0: { michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, info, PL_DHASH_LOOKUP); michael@0: if (PL_DHASH_ENTRY_IS_FREE(entry)) michael@0: return nullptr; michael@0: return entry->value; michael@0: } michael@0: michael@0: inline XPCWrappedNativeProto* Add(nsIClassInfo* info, XPCWrappedNativeProto* proto) michael@0: { michael@0: NS_PRECONDITION(info,"bad param"); michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, info, PL_DHASH_ADD); michael@0: if (!entry) michael@0: return nullptr; michael@0: if (entry->key) michael@0: return entry->value; michael@0: entry->key = info; michael@0: entry->value = proto; michael@0: return proto; michael@0: } michael@0: michael@0: inline void Remove(nsIClassInfo* info) michael@0: { michael@0: NS_PRECONDITION(info,"bad param"); michael@0: PL_DHashTableOperate(mTable, info, PL_DHASH_REMOVE); michael@0: } michael@0: michael@0: inline uint32_t Count() {return mTable->entryCount;} michael@0: inline uint32_t Enumerate(PLDHashEnumerator f, void *arg) michael@0: {return PL_DHashTableEnumerate(mTable, f, arg);} michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); michael@0: michael@0: ~ClassInfo2WrappedNativeProtoMap(); michael@0: private: michael@0: ClassInfo2WrappedNativeProtoMap(); // no implementation michael@0: ClassInfo2WrappedNativeProtoMap(int size); michael@0: michael@0: static size_t SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr, mozilla::MallocSizeOf mallocSizeOf, void *); michael@0: michael@0: private: michael@0: PLDHashTable *mTable; michael@0: }; michael@0: michael@0: /*************************/ michael@0: michael@0: class NativeSetMap michael@0: { michael@0: public: michael@0: struct Entry : public PLDHashEntryHdr michael@0: { michael@0: XPCNativeSet* key_value; michael@0: michael@0: static bool michael@0: Match(PLDHashTable *table, michael@0: const PLDHashEntryHdr *entry, michael@0: const void *key); michael@0: michael@0: static const struct PLDHashTableOps sOps; michael@0: }; michael@0: michael@0: static NativeSetMap* newMap(int size); michael@0: michael@0: inline XPCNativeSet* Find(XPCNativeSetKey* key) michael@0: { michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, key, PL_DHASH_LOOKUP); michael@0: if (PL_DHASH_ENTRY_IS_FREE(entry)) michael@0: return nullptr; michael@0: return entry->key_value; michael@0: } michael@0: michael@0: inline XPCNativeSet* Add(const XPCNativeSetKey* key, XPCNativeSet* set) michael@0: { michael@0: NS_PRECONDITION(key,"bad param"); michael@0: NS_PRECONDITION(set,"bad param"); michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, key, PL_DHASH_ADD); michael@0: if (!entry) michael@0: return nullptr; michael@0: if (entry->key_value) michael@0: return entry->key_value; michael@0: entry->key_value = set; michael@0: return set; michael@0: } michael@0: michael@0: inline XPCNativeSet* Add(XPCNativeSet* set) michael@0: { michael@0: XPCNativeSetKey key(set, nullptr, 0); michael@0: return Add(&key, set); michael@0: } michael@0: michael@0: inline void Remove(XPCNativeSet* set) michael@0: { michael@0: NS_PRECONDITION(set,"bad param"); michael@0: michael@0: XPCNativeSetKey key(set, nullptr, 0); michael@0: PL_DHashTableOperate(mTable, &key, PL_DHASH_REMOVE); michael@0: } michael@0: michael@0: inline uint32_t Count() {return mTable->entryCount;} michael@0: inline uint32_t Enumerate(PLDHashEnumerator f, void *arg) michael@0: {return PL_DHashTableEnumerate(mTable, f, arg);} michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); michael@0: michael@0: ~NativeSetMap(); michael@0: private: michael@0: NativeSetMap(); // no implementation michael@0: NativeSetMap(int size); michael@0: michael@0: static size_t SizeOfEntryExcludingThis(PLDHashEntryHdr *hdr, mozilla::MallocSizeOf mallocSizeOf, void *); michael@0: michael@0: private: michael@0: PLDHashTable *mTable; michael@0: }; michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: class IID2ThisTranslatorMap michael@0: { michael@0: public: michael@0: struct Entry : public PLDHashEntryHdr michael@0: { michael@0: nsIID key; michael@0: nsCOMPtr value; michael@0: michael@0: static bool michael@0: Match(PLDHashTable *table, michael@0: const PLDHashEntryHdr *entry, michael@0: const void *key); michael@0: michael@0: static void michael@0: Clear(PLDHashTable *table, PLDHashEntryHdr *entry); michael@0: michael@0: static const struct PLDHashTableOps sOps; michael@0: }; michael@0: michael@0: static IID2ThisTranslatorMap* newMap(int size); michael@0: michael@0: inline nsIXPCFunctionThisTranslator* Find(REFNSIID iid) michael@0: { michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, &iid, PL_DHASH_LOOKUP); michael@0: if (PL_DHASH_ENTRY_IS_FREE(entry)) michael@0: return nullptr; michael@0: return entry->value; michael@0: } michael@0: michael@0: inline nsIXPCFunctionThisTranslator* Add(REFNSIID iid, michael@0: nsIXPCFunctionThisTranslator* obj) michael@0: { michael@0: michael@0: Entry* entry = (Entry*) michael@0: PL_DHashTableOperate(mTable, &iid, PL_DHASH_ADD); michael@0: if (!entry) michael@0: return nullptr; michael@0: entry->value = obj; michael@0: entry->key = iid; michael@0: return obj; michael@0: } michael@0: michael@0: inline void Remove(REFNSIID iid) michael@0: { michael@0: PL_DHashTableOperate(mTable, &iid, PL_DHASH_REMOVE); michael@0: } michael@0: michael@0: inline uint32_t Count() {return mTable->entryCount;} michael@0: inline uint32_t Enumerate(PLDHashEnumerator f, void *arg) michael@0: {return PL_DHashTableEnumerate(mTable, f, arg);} michael@0: michael@0: ~IID2ThisTranslatorMap(); michael@0: private: michael@0: IID2ThisTranslatorMap(); // no implementation michael@0: IID2ThisTranslatorMap(int size); michael@0: private: michael@0: PLDHashTable *mTable; michael@0: }; michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: class XPCNativeScriptableSharedMap michael@0: { michael@0: public: michael@0: struct Entry : public PLDHashEntryHdr michael@0: { michael@0: XPCNativeScriptableShared* key; michael@0: michael@0: static PLDHashNumber michael@0: Hash(PLDHashTable *table, const void *key); michael@0: michael@0: static bool michael@0: Match(PLDHashTable *table, michael@0: const PLDHashEntryHdr *entry, michael@0: const void *key); michael@0: michael@0: static const struct PLDHashTableOps sOps; michael@0: }; michael@0: michael@0: static XPCNativeScriptableSharedMap* newMap(int size); michael@0: michael@0: bool GetNewOrUsed(uint32_t flags, char* name, uint32_t interfacesBitmap, michael@0: XPCNativeScriptableInfo* si); michael@0: michael@0: inline uint32_t Count() {return mTable->entryCount;} michael@0: inline uint32_t Enumerate(PLDHashEnumerator f, void *arg) michael@0: {return PL_DHashTableEnumerate(mTable, f, arg);} michael@0: michael@0: ~XPCNativeScriptableSharedMap(); michael@0: private: michael@0: XPCNativeScriptableSharedMap(); // no implementation michael@0: XPCNativeScriptableSharedMap(int size); michael@0: private: michael@0: PLDHashTable *mTable; michael@0: }; michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: class XPCWrappedNativeProtoMap michael@0: { michael@0: public: michael@0: static XPCWrappedNativeProtoMap* newMap(int size); michael@0: michael@0: inline XPCWrappedNativeProto* Add(XPCWrappedNativeProto* proto) michael@0: { michael@0: NS_PRECONDITION(proto,"bad param"); michael@0: PLDHashEntryStub* entry = (PLDHashEntryStub*) michael@0: PL_DHashTableOperate(mTable, proto, PL_DHASH_ADD); michael@0: if (!entry) michael@0: return nullptr; michael@0: if (entry->key) michael@0: return (XPCWrappedNativeProto*) entry->key; michael@0: entry->key = proto; michael@0: return proto; michael@0: } michael@0: michael@0: inline void Remove(XPCWrappedNativeProto* proto) michael@0: { michael@0: NS_PRECONDITION(proto,"bad param"); michael@0: PL_DHashTableOperate(mTable, proto, PL_DHASH_REMOVE); michael@0: } michael@0: michael@0: inline uint32_t Count() {return mTable->entryCount;} michael@0: inline uint32_t Enumerate(PLDHashEnumerator f, void *arg) michael@0: {return PL_DHashTableEnumerate(mTable, f, arg);} michael@0: michael@0: ~XPCWrappedNativeProtoMap(); michael@0: private: michael@0: XPCWrappedNativeProtoMap(); // no implementation michael@0: XPCWrappedNativeProtoMap(int size); michael@0: private: michael@0: PLDHashTable *mTable; michael@0: }; michael@0: michael@0: /***************************************************************************/ michael@0: michael@0: class JSObject2JSObjectMap michael@0: { michael@0: typedef js::HashMap, js::PointerHasher, michael@0: js::SystemAllocPolicy> Map; michael@0: michael@0: public: michael@0: static JSObject2JSObjectMap* newMap(int size) { michael@0: JSObject2JSObjectMap* map = new JSObject2JSObjectMap(); michael@0: if (map && map->mTable.init(size)) michael@0: return map; michael@0: delete map; michael@0: return nullptr; michael@0: } michael@0: michael@0: inline JSObject* Find(JSObject* key) { michael@0: NS_PRECONDITION(key, "bad param"); michael@0: if (Map::Ptr p = mTable.lookup(key)) michael@0: return p->value(); michael@0: return nullptr; michael@0: } michael@0: michael@0: /* Note: If the entry already exists, return the old value. */ michael@0: inline JSObject* Add(JSContext *cx, JSObject *key, JSObject *value) { michael@0: NS_PRECONDITION(key,"bad param"); michael@0: Map::AddPtr p = mTable.lookupForAdd(key); michael@0: if (p) michael@0: return p->value(); michael@0: if (!mTable.add(p, key, value)) michael@0: return nullptr; michael@0: MOZ_ASSERT(xpc::GetCompartmentPrivate(key)->scope->mWaiverWrapperMap == this); michael@0: JS_StoreObjectPostBarrierCallback(cx, KeyMarkCallback, key, this); michael@0: return value; michael@0: } michael@0: michael@0: inline void Remove(JSObject* key) { michael@0: NS_PRECONDITION(key,"bad param"); michael@0: mTable.remove(key); michael@0: } michael@0: michael@0: inline uint32_t Count() { return mTable.count(); } michael@0: michael@0: void Sweep() { michael@0: for (Map::Enum e(mTable); !e.empty(); e.popFront()) { michael@0: JSObject *updated = e.front().key(); michael@0: if (JS_IsAboutToBeFinalizedUnbarriered(&updated) || JS_IsAboutToBeFinalized(&e.front().value())) michael@0: e.removeFront(); michael@0: else if (updated != e.front().key()) michael@0: e.rekeyFront(updated); michael@0: } michael@0: } michael@0: michael@0: void Reparent(JSContext *aCx, JSObject *aNewInnerArg) { michael@0: JS::RootedObject aNewInner(aCx, aNewInnerArg); michael@0: for (Map::Enum e(mTable); !e.empty(); e.popFront()) { michael@0: /* michael@0: * We reparent wrappers that have as their parent an inner window michael@0: * whose outer has the new inner window as its current inner. michael@0: */ michael@0: JS::RootedObject wrapper(aCx, e.front().value()); michael@0: JS::RootedObject parent(aCx, JS_GetParent(wrapper)); michael@0: JS::RootedObject outer(aCx, JS_ObjectToOuterObject(aCx, parent)); michael@0: if (outer) { michael@0: JSObject *inner = JS_ObjectToInnerObject(aCx, outer); michael@0: if (inner == aNewInner && inner != parent) michael@0: JS_SetParent(aCx, wrapper, aNewInner); michael@0: } else { michael@0: JS_ClearPendingException(aCx); michael@0: } michael@0: } michael@0: } michael@0: michael@0: private: michael@0: JSObject2JSObjectMap() {} michael@0: michael@0: /* michael@0: * This function is called during minor GCs for each key in the HashMap that michael@0: * has been moved. michael@0: */ michael@0: static void KeyMarkCallback(JSTracer *trc, JSObject *key, void *data) { michael@0: /* michael@0: * To stop the barriers on the values of mTable firing while we are michael@0: * marking the store buffer, we cast the table to one that is michael@0: * binary-equivatlent but without the barriers, and update that. michael@0: */ michael@0: typedef js::HashMap, michael@0: js::SystemAllocPolicy> UnbarrieredMap; michael@0: JSObject2JSObjectMap *self = static_cast(data); michael@0: UnbarrieredMap &table = reinterpret_cast(self->mTable); michael@0: michael@0: JSObject *prior = key; michael@0: JS_CallObjectTracer(trc, &key, "XPCWrappedNativeScope::mWaiverWrapperMap key"); michael@0: table.rekeyIfMoved(prior, key); michael@0: } michael@0: michael@0: Map mTable; michael@0: }; michael@0: michael@0: #endif /* xpcmaps_h___ */