diff options
Diffstat (limited to 'js/xpconnect/src/XPCMaps.cpp')
-rw-r--r-- | js/xpconnect/src/XPCMaps.cpp | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/js/xpconnect/src/XPCMaps.cpp b/js/xpconnect/src/XPCMaps.cpp new file mode 100644 index 0000000000..91ea7228f7 --- /dev/null +++ b/js/xpconnect/src/XPCMaps.cpp @@ -0,0 +1,257 @@ +/* -*- 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<const XPCNativeSetKey*>(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<RefPtr<nsXPCWrappedJS>> 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<Native2WrappedNativeMap::Entry*>(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<IID2NativeInterfaceMap::Entry*>(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<const Entry*>(aEntry)->key == aKey; +} + +// static +void ClassInfo2NativeSetMap::Entry::Clear(PLDHashTable* aTable, + PLDHashEntryHdr* aEntry) { + auto entry = static_cast<Entry*>(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<ClassInfo2WrappedNativeProtoMap::Entry*>(iter.Get()); + n += mallocSizeOf(entry->value); + } + return n; +} + +/***************************************************************************/ +// implement NativeSetMap... + +bool NativeSetMap::Entry::Match(const PLDHashEntryHdr* entry, const void* key) { + auto Key = static_cast<const XPCNativeSetKey*>(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<NativeSetMap::Entry*>(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) {} + +/***************************************************************************/ |