diff options
Diffstat (limited to 'js/xpconnect/src/XPCMaps.cpp')
-rw-r--r-- | js/xpconnect/src/XPCMaps.cpp | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/js/xpconnect/src/XPCMaps.cpp b/js/xpconnect/src/XPCMaps.cpp new file mode 100644 index 0000000000..0d728d7de4 --- /dev/null +++ b/js/xpconnect/src/XPCMaps.cpp @@ -0,0 +1,405 @@ +/* -*- 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<const XPCNativeSetKey*>(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<RefPtr<nsXPCWrappedJS>> 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<Native2WrappedNativeMap::Entry*>(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<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 +}; + +// 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<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 +}; + +// 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<NativeSetMap::Entry*>(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*>(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) +{ +} + +/***************************************************************************/ |