diff options
Diffstat (limited to 'xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp')
-rw-r--r-- | xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp b/xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp new file mode 100644 index 000000000..600a99b94 --- /dev/null +++ b/xpcom/reflect/xptinfo/xptiInterfaceInfoManager.cpp @@ -0,0 +1,242 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=8 sts=4 et sw=4 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/. */ + +/* Implementation of xptiInterfaceInfoManager. */ + +#include "mozilla/XPTInterfaceInfoManager.h" + +#include "mozilla/FileUtils.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/StaticPtr.h" + +#include "xptiprivate.h" +#include "nsDependentString.h" +#include "nsString.h" +#include "nsArrayEnumerator.h" +#include "nsDirectoryService.h" +#include "nsIMemoryReporter.h" + +using namespace mozilla; + +NS_IMPL_ISUPPORTS( + XPTInterfaceInfoManager, + nsIInterfaceInfoManager, + nsIMemoryReporter) + +static StaticRefPtr<XPTInterfaceInfoManager> gInterfaceInfoManager; + +size_t +XPTInterfaceInfoManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) +{ + size_t n = aMallocSizeOf(this); + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); + // The entries themselves are allocated out of an arena accounted + // for elsewhere, so don't measure them + n += mWorkingSet.mIIDTable.ShallowSizeOfExcludingThis(aMallocSizeOf); + n += mWorkingSet.mNameTable.ShallowSizeOfExcludingThis(aMallocSizeOf); + return n; +} + +MOZ_DEFINE_MALLOC_SIZE_OF(XPTIMallocSizeOf) + +NS_IMETHODIMP +XPTInterfaceInfoManager::CollectReports(nsIHandleReportCallback* aHandleReport, + nsISupports* aData, bool aAnonymize) +{ + size_t amount = SizeOfIncludingThis(XPTIMallocSizeOf); + + // Measure gXPTIStructArena here, too. This is a bit grotty because it + // doesn't belong to the XPTIInterfaceInfoManager, but there's no + // obviously better place to measure it. + amount += XPT_SizeOfArenaIncludingThis(gXPTIStructArena, XPTIMallocSizeOf); + + MOZ_COLLECT_REPORT( + "explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES, amount, + "Memory used by the XPCOM typelib system."); + + return NS_OK; +} + +// static +XPTInterfaceInfoManager* +XPTInterfaceInfoManager::GetSingleton() +{ + if (!gInterfaceInfoManager) { + gInterfaceInfoManager = new XPTInterfaceInfoManager(); + gInterfaceInfoManager->InitMemoryReporter(); + } + return gInterfaceInfoManager; +} + +void +XPTInterfaceInfoManager::FreeInterfaceInfoManager() +{ + gInterfaceInfoManager = nullptr; +} + +XPTInterfaceInfoManager::XPTInterfaceInfoManager() + : mWorkingSet(), + mResolveLock("XPTInterfaceInfoManager.mResolveLock") +{ +} + +XPTInterfaceInfoManager::~XPTInterfaceInfoManager() +{ + // We only do this on shutdown of the service. + mWorkingSet.InvalidateInterfaceInfos(); + + UnregisterWeakMemoryReporter(this); +} + +void +XPTInterfaceInfoManager::InitMemoryReporter() +{ + RegisterWeakMemoryReporter(this); +} + +void +XPTInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length) +{ + XPTState state; + XPT_InitXDRState(&state, buf, length); + + XPTCursor curs; + NotNull<XPTCursor*> cursor = WrapNotNull(&curs); + if (!XPT_MakeCursor(&state, XPT_HEADER, 0, cursor)) { + return; + } + + XPTHeader *header = nullptr; + if (XPT_DoHeader(gXPTIStructArena, cursor, &header)) { + RegisterXPTHeader(header); + } +} + +void +XPTInterfaceInfoManager::RegisterXPTHeader(XPTHeader* aHeader) +{ + if (aHeader->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) { + NS_ASSERTION(!aHeader->num_interfaces,"bad libxpt"); + LOG_AUTOREG((" file is version %d.%d Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION)); + } + + xptiTypelibGuts* typelib = xptiTypelibGuts::Create(aHeader); + + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); + for(uint16_t k = 0; k < aHeader->num_interfaces; k++) + VerifyAndAddEntryIfNew(aHeader->interface_directory + k, k, typelib); +} + +void +XPTInterfaceInfoManager::VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface, + uint16_t idx, + xptiTypelibGuts* typelib) +{ + if (!iface->interface_descriptor) + return; + + // The number of maximum methods is not arbitrary. It is the same value as + // in xpcom/reflect/xptcall/genstubs.pl; do not change this value + // without changing that one or you WILL see problems. + if (iface->interface_descriptor->num_methods > 250 && + !(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags))) { + NS_ASSERTION(0, "Too many methods to handle for the stub, cannot load"); + fprintf(stderr, "ignoring too large interface: %s\n", iface->name); + return; + } + + mWorkingSet.mTableReentrantMonitor.AssertCurrentThreadIn(); + xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(iface->iid); + if (entry) { + // XXX validate this info to find possible inconsistencies + LOG_AUTOREG((" ignoring repeated interface: %s\n", iface->name)); + return; + } + + // Build a new xptiInterfaceEntry object and hook it up. + + entry = xptiInterfaceEntry::Create(iface->name, + iface->iid, + iface->interface_descriptor, + typelib); + if (!entry) + return; + + //XXX We should SetHeader too as part of the validation, no? + entry->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags)); + entry->SetBuiltinClassFlag(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags)); + entry->SetMainProcessScriptableOnlyFlag( + XPT_ID_IS_MAIN_PROCESS_SCRIPTABLE_ONLY(iface->interface_descriptor->flags)); + + mWorkingSet.mIIDTable.Put(entry->IID(), entry); + mWorkingSet.mNameTable.Put(entry->GetTheName(), entry); + + typelib->SetEntryAt(idx, entry); + + LOG_AUTOREG((" added interface: %s\n", iface->name)); +} + +// this is a private helper +static nsresult +EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval) +{ + if (!entry) { + *_retval = nullptr; + return NS_ERROR_FAILURE; + } + + RefPtr<xptiInterfaceInfo> info = entry->InterfaceInfo(); + info.forget(_retval); + return NS_OK; +} + +xptiInterfaceEntry* +XPTInterfaceInfoManager::GetInterfaceEntryForIID(const nsIID *iid) +{ + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); + return mWorkingSet.mIIDTable.Get(*iid); +} + +NS_IMETHODIMP +XPTInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval) +{ + NS_ASSERTION(iid, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); + xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(*iid); + return EntryToInfo(entry, _retval); +} + +NS_IMETHODIMP +XPTInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval) +{ + NS_ASSERTION(name, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); + xptiInterfaceEntry* entry = mWorkingSet.mNameTable.Get(name); + return EntryToInfo(entry, _retval); +} + +void +XPTInterfaceInfoManager::GetScriptableInterfaces(nsCOMArray<nsIInterfaceInfo>& aInterfaces) +{ + // I didn't want to incur the size overhead of using nsHashtable just to + // make building an enumerator easier. So, this code makes a snapshot of + // the table using an nsCOMArray and builds an enumerator for that. + // We can afford this transient cost. + + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); + aInterfaces.SetCapacity(mWorkingSet.mNameTable.Count()); + for (auto iter = mWorkingSet.mNameTable.Iter(); !iter.Done(); iter.Next()) { + xptiInterfaceEntry* entry = iter.UserData(); + if (entry->GetScriptableFlag()) { + nsCOMPtr<nsIInterfaceInfo> ii = entry->InterfaceInfo(); + aInterfaces.AppendElement(ii); + } + } +} |