https://github.com/mozilla/gecko-dev
Raw File
Tip revision: ad95adbc91bc07724b97464c6641f0fbdf37b301 authored by Mark Banner on 25 January 2022, 19:41:24 UTC
Bug 1751746 - Change search-telemetry to use strict partner code matching. r=daleharvey,mkaply a=dsmith
Tip revision: ad95adb
XPCMaps.cpp
/* -*- 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) {}

/***************************************************************************/
back to top