/* -*- 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). */ #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 hash of the bit pattern of the first part of the // nsID, not the hash of the pointer to the nsID. static PLDHashNumber HashIIDPtrKey(const void* key) { uintptr_t v; memcpy(&v, key, sizeof(v)); return HashGeneric(v); } 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() { // 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 (auto iter = mTable.modIter(); !iter.done(); iter.next()) { nsXPCWrappedJS* wrapper = iter.get().value(); MOZ_ASSERT(wrapper, "found a null JS wrapper!"); // Walk the wrapper chain and update all JSObjects. while (wrapper) { 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 = iter.get().key().unbarrieredGet(); JS_UpdateWeakPointerAfterGCUnbarriered(&obj); if (!obj) { iter.remove(); } else { iter.get().mutableKey() = obj; } } } void JSObject2WrappedJSMap::ShutdownMarker() { for (auto iter = mTable.iter(); !iter.done(); iter.next()) { nsXPCWrappedJS* wrapper = iter.get().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.shallowSizeOfExcludingThis(mallocSizeOf); return n; } size_t JSObject2WrappedJSMap::SizeOfWrappedJS( mozilla::MallocSizeOf mallocSizeOf) const { size_t n = 0; for (auto iter = mTable.iter(); !iter.done(); iter.next()) { n += iter.get().value()->SizeOfIncludingThis(mallocSizeOf); } return n; } /***************************************************************************/ // implement Native2WrappedNativeMap... Native2WrappedNativeMap::Native2WrappedNativeMap() : mTable(PLDHashTable::StubOps(), sizeof(Entry), XPC_NATIVE_MAP_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 IID2NativeInterfaceMap... const struct PLDHashTableOps IID2NativeInterfaceMap::Entry::sOps = { HashIIDPtrKey, MatchIIDPtrKey, PLDHashTable::MoveEntryStub, PLDHashTable::ClearEntryStub}; IID2NativeInterfaceMap::IID2NativeInterfaceMap() : mTable(&Entry::sOps, sizeof(Entry), XPC_NATIVE_INTERFACE_MAP_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}; ClassInfo2NativeSetMap::ClassInfo2NativeSetMap() : mTable(&ClassInfo2NativeSetMap::Entry::sOps, sizeof(Entry), XPC_NATIVE_SET_MAP_LENGTH) {} size_t ClassInfo2NativeSetMap::ShallowSizeOfIncludingThis( mozilla::MallocSizeOf mallocSizeOf) { size_t n = mallocSizeOf(this); n += mTable.ShallowSizeOfExcludingThis(mallocSizeOf); return n; } /***************************************************************************/ // implement ClassInfo2WrappedNativeProtoMap... ClassInfo2WrappedNativeProtoMap::ClassInfo2WrappedNativeProtoMap() : mTable(PLDHashTable::StubOps(), sizeof(Entry), XPC_NATIVE_PROTO_MAP_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}; NativeSetMap::NativeSetMap() : mTable(&Entry::sOps, sizeof(Entry), XPC_NATIVE_SET_MAP_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 XPCWrappedNativeProtoMap... XPCWrappedNativeProtoMap::XPCWrappedNativeProtoMap() : mTable(PLDHashTable::StubOps(), sizeof(PLDHashEntryStub), XPC_DYING_NATIVE_PROTO_MAP_LENGTH) {} /***************************************************************************/