/* -*- 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). */ #include "mozilla/MathAlgorithms.h" #include "mozilla/MemoryReporting.h" #include "xpcprivate.h" #include "js/HashTable.h" using namespace mozilla; /***************************************************************************/ // static shared... // Note this is returning the bit pattern of the first part of the nsID, not // the pointer to the nsID. static PLDHashNumber HashIIDPtrKey(const void* key) { return *((js::HashNumber*)key); } static bool MatchIIDPtrKey(const PLDHashEntryHdr* entry, const void* key) { return ((const nsID*)key)-> Equals(*((const nsID*)((PLDHashEntryStub*)entry)->key)); } static PLDHashNumber HashNativeKey(const void* data) { return static_cast(data)->Hash(); } /***************************************************************************/ // implement JSObject2WrappedJSMap... void JSObject2WrappedJSMap::UpdateWeakPointersAfterGC(XPCJSContext* context) { // Check all wrappers and update their JSObject pointer if it has been // moved. Release any wrappers whose weakly held JSObject has died. nsTArray> dying; for (Map::Enum e(mTable); !e.empty(); e.popFront()) { nsXPCWrappedJS* wrapper = e.front().value(); MOZ_ASSERT(wrapper, "found a null JS wrapper!"); // Walk the wrapper chain and update all JSObjects. while (wrapper) { #ifdef DEBUG if (!wrapper->IsSubjectToFinalization()) { // If a wrapper is not subject to finalization then it roots its // JS object. If so, then it will not be about to be finalized // and any necessary pointer update will have already happened // when it was marked. JSObject* obj = wrapper->GetJSObjectPreserveColor(); JSObject* prior = obj; JS_UpdateWeakPointerAfterGCUnbarriered(&obj); MOZ_ASSERT(obj == prior); } #endif if (wrapper->IsSubjectToFinalization()) { wrapper->UpdateObjectPointerAfterGC(); if (!wrapper->GetJSObjectPreserveColor()) dying.AppendElement(dont_AddRef(wrapper)); } wrapper = wrapper->GetNextWrapper(); } // Remove or update the JSObject key in the table if necessary. JSObject* obj = e.front().key().unbarrieredGet(); JS_UpdateWeakPointerAfterGCUnbarriered(&obj); if (!obj) e.removeFront(); else e.front().mutableKey() = obj; } } void JSObject2WrappedJSMap::ShutdownMarker() { for (Map::Range r = mTable.all(); !r.empty(); r.popFront()) { nsXPCWrappedJS* wrapper = r.front().value(); MOZ_ASSERT(wrapper, "found a null JS wrapper!"); MOZ_ASSERT(wrapper->IsValid(), "found an invalid JS wrapper!"); wrapper->SystemIsBeingShutDown(); } } size_t JSObject2WrappedJSMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { size_t n = mallocSizeOf(this); n += mTable.sizeOfExcludingThis(mallocSizeOf); return n; } size_t JSObject2WrappedJSMap::SizeOfWrappedJS(mozilla::MallocSizeOf mallocSizeOf) const { size_t n = 0; for (Map::Range r = mTable.all(); !r.empty(); r.popFront()) n += r.front().value()->SizeOfIncludingThis(mallocSizeOf); return n; } /***************************************************************************/ // implement Native2WrappedNativeMap... // static Native2WrappedNativeMap* Native2WrappedNativeMap::newMap(int length) { return new Native2WrappedNativeMap(length); } Native2WrappedNativeMap::Native2WrappedNativeMap(int length) : mTable(PLDHashTable::StubOps(), sizeof(Entry), length) { } size_t Native2WrappedNativeMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { size_t n = mallocSizeOf(this); n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf); for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) { auto entry = static_cast(iter.Get()); n += mallocSizeOf(entry->value); } return n; } /***************************************************************************/ // implement IID2WrappedJSClassMap... const struct PLDHashTableOps IID2WrappedJSClassMap::Entry::sOps = { HashIIDPtrKey, MatchIIDPtrKey, PLDHashTable::MoveEntryStub, PLDHashTable::ClearEntryStub }; // static IID2WrappedJSClassMap* IID2WrappedJSClassMap::newMap(int length) { return new IID2WrappedJSClassMap(length); } IID2WrappedJSClassMap::IID2WrappedJSClassMap(int length) : mTable(&Entry::sOps, sizeof(Entry), length) { } /***************************************************************************/ // implement IID2NativeInterfaceMap... const struct PLDHashTableOps IID2NativeInterfaceMap::Entry::sOps = { HashIIDPtrKey, MatchIIDPtrKey, PLDHashTable::MoveEntryStub, PLDHashTable::ClearEntryStub }; // static IID2NativeInterfaceMap* IID2NativeInterfaceMap::newMap(int length) { return new IID2NativeInterfaceMap(length); } IID2NativeInterfaceMap::IID2NativeInterfaceMap(int length) : mTable(&Entry::sOps, sizeof(Entry), length) { } size_t IID2NativeInterfaceMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { size_t n = mallocSizeOf(this); n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf); for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) { auto entry = static_cast(iter.Get()); n += entry->value->SizeOfIncludingThis(mallocSizeOf); } return n; } /***************************************************************************/ // implement ClassInfo2NativeSetMap... // static bool ClassInfo2NativeSetMap::Entry::Match(const PLDHashEntryHdr* aEntry, const void* aKey) { return static_cast(aEntry)->key == aKey; } // static void ClassInfo2NativeSetMap::Entry::Clear(PLDHashTable* aTable, PLDHashEntryHdr* aEntry) { auto entry = static_cast(aEntry); NS_RELEASE(entry->value); entry->key = nullptr; entry->value = nullptr; } const PLDHashTableOps ClassInfo2NativeSetMap::Entry::sOps = { PLDHashTable::HashVoidPtrKeyStub, Match, PLDHashTable::MoveEntryStub, Clear, nullptr }; // static ClassInfo2NativeSetMap* ClassInfo2NativeSetMap::newMap(int length) { return new ClassInfo2NativeSetMap(length); } ClassInfo2NativeSetMap::ClassInfo2NativeSetMap(int length) : mTable(&ClassInfo2NativeSetMap::Entry::sOps, sizeof(Entry), length) { } size_t ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) { size_t n = mallocSizeOf(this); n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf); return n; } /***************************************************************************/ // implement ClassInfo2WrappedNativeProtoMap... // static ClassInfo2WrappedNativeProtoMap* ClassInfo2WrappedNativeProtoMap::newMap(int length) { return new ClassInfo2WrappedNativeProtoMap(length); } ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap(int length) : mTable(PLDHashTable::StubOps(), sizeof(Entry), length) { } size_t ClassInfo2WrappedNativeProtoMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { size_t n = mallocSizeOf(this); n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf); for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) { auto entry = static_cast(iter.Get()); n += mallocSizeOf(entry->value); } return n; } /***************************************************************************/ // implement NativeSetMap... bool NativeSetMap::Entry::Match(const PLDHashEntryHdr* entry, const void* key) { auto Key = static_cast(key); XPCNativeSet* SetInTable = ((Entry*)entry)->key_value; XPCNativeSet* Set = Key->GetBaseSet(); XPCNativeInterface* Addition = Key->GetAddition(); if (!Set) { // This is a special case to deal with the invariant that says: // "All sets have exactly one nsISupports interface and it comes first." // See XPCNativeSet::NewInstance for details. // // Though we might have a key that represents only one interface, we // know that if that one interface were contructed into a set then // it would end up really being a set with two interfaces (except for // the case where the one interface happened to be nsISupports). return (SetInTable->GetInterfaceCount() == 1 && SetInTable->GetInterfaceAt(0) == Addition) || (SetInTable->GetInterfaceCount() == 2 && SetInTable->GetInterfaceAt(1) == Addition); } if (!Addition && Set == SetInTable) return true; uint16_t count = Set->GetInterfaceCount(); if (count + (Addition ? 1 : 0) != SetInTable->GetInterfaceCount()) return false; XPCNativeInterface** CurrentInTable = SetInTable->GetInterfaceArray(); XPCNativeInterface** Current = Set->GetInterfaceArray(); for (uint16_t i = 0; i < count; i++) { if (*(Current++) != *(CurrentInTable++)) return false; } return !Addition || Addition == *(CurrentInTable++); } const struct PLDHashTableOps NativeSetMap::Entry::sOps = { HashNativeKey, Match, PLDHashTable::MoveEntryStub, PLDHashTable::ClearEntryStub }; // static NativeSetMap* NativeSetMap::newMap(int length) { return new NativeSetMap(length); } NativeSetMap::NativeSetMap(int length) : mTable(&Entry::sOps, sizeof(Entry), length) { } size_t NativeSetMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { size_t n = mallocSizeOf(this); n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf); for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) { auto entry = static_cast(iter.Get()); n += entry->key_value->SizeOfIncludingThis(mallocSizeOf); } return n; } /***************************************************************************/ // implement IID2ThisTranslatorMap... bool IID2ThisTranslatorMap::Entry::Match(const PLDHashEntryHdr* entry, const void* key) { return ((const nsID*)key)->Equals(((Entry*)entry)->key); } void IID2ThisTranslatorMap::Entry::Clear(PLDHashTable* table, PLDHashEntryHdr* entry) { static_cast(entry)->value = nullptr; memset(entry, 0, table->EntrySize()); } const struct PLDHashTableOps IID2ThisTranslatorMap::Entry::sOps = { HashIIDPtrKey, Match, PLDHashTable::MoveEntryStub, Clear }; // static IID2ThisTranslatorMap* IID2ThisTranslatorMap::newMap(int length) { return new IID2ThisTranslatorMap(length); } IID2ThisTranslatorMap::IID2ThisTranslatorMap(int length) : mTable(&Entry::sOps, sizeof(Entry), length) { } /***************************************************************************/ // implement XPCWrappedNativeProtoMap... // static XPCWrappedNativeProtoMap* XPCWrappedNativeProtoMap::newMap(int length) { return new XPCWrappedNativeProtoMap(length); } XPCWrappedNativeProtoMap::XPCWrappedNativeProtoMap(int length) : mTable(PLDHashTable::StubOps(), sizeof(PLDHashEntryStub), length) { } /***************************************************************************/