summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/src/XPCMaps.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/xpconnect/src/XPCMaps.cpp')
-rw-r--r--js/xpconnect/src/XPCMaps.cpp257
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) {}
+
+/***************************************************************************/