1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,330 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* Implementation of xptiInterfaceInfoManager. */ 1.11 + 1.12 +#include "mozilla/XPTInterfaceInfoManager.h" 1.13 + 1.14 +#include "mozilla/FileUtils.h" 1.15 +#include "mozilla/MemoryReporting.h" 1.16 +#include "mozilla/StaticPtr.h" 1.17 + 1.18 +#include "xptiprivate.h" 1.19 +#include "nsDependentString.h" 1.20 +#include "nsString.h" 1.21 +#include "nsISupportsArray.h" 1.22 +#include "nsArrayEnumerator.h" 1.23 +#include "nsDirectoryService.h" 1.24 +#include "nsIMemoryReporter.h" 1.25 + 1.26 +using namespace mozilla; 1.27 + 1.28 +NS_IMPL_ISUPPORTS( 1.29 + XPTInterfaceInfoManager, 1.30 + nsIInterfaceInfoManager, 1.31 + nsIMemoryReporter) 1.32 + 1.33 +static StaticRefPtr<XPTInterfaceInfoManager> gInterfaceInfoManager; 1.34 + 1.35 +size_t 1.36 +XPTInterfaceInfoManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) 1.37 +{ 1.38 + size_t n = aMallocSizeOf(this); 1.39 + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); 1.40 + // The entries themselves are allocated out of an arena accounted 1.41 + // for elsewhere, so don't measure them 1.42 + n += mWorkingSet.mIIDTable.SizeOfExcludingThis(nullptr, aMallocSizeOf); 1.43 + n += mWorkingSet.mNameTable.SizeOfExcludingThis(nullptr, aMallocSizeOf); 1.44 + return n; 1.45 +} 1.46 + 1.47 +MOZ_DEFINE_MALLOC_SIZE_OF(XPTIMallocSizeOf) 1.48 + 1.49 +NS_IMETHODIMP 1.50 +XPTInterfaceInfoManager::CollectReports(nsIHandleReportCallback* aHandleReport, 1.51 + nsISupports* aData) 1.52 +{ 1.53 + size_t amount = SizeOfIncludingThis(XPTIMallocSizeOf); 1.54 + 1.55 + // Measure gXPTIStructArena here, too. This is a bit grotty because it 1.56 + // doesn't belong to the XPTIInterfaceInfoManager, but there's no 1.57 + // obviously better place to measure it. 1.58 + amount += XPT_SizeOfArena(gXPTIStructArena, XPTIMallocSizeOf); 1.59 + 1.60 + return MOZ_COLLECT_REPORT( 1.61 + "explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES, amount, 1.62 + "Memory used by the XPCOM typelib system."); 1.63 +} 1.64 + 1.65 +// static 1.66 +XPTInterfaceInfoManager* 1.67 +XPTInterfaceInfoManager::GetSingleton() 1.68 +{ 1.69 + if (!gInterfaceInfoManager) { 1.70 + gInterfaceInfoManager = new XPTInterfaceInfoManager(); 1.71 + gInterfaceInfoManager->InitMemoryReporter(); 1.72 + } 1.73 + return gInterfaceInfoManager; 1.74 +} 1.75 + 1.76 +void 1.77 +XPTInterfaceInfoManager::FreeInterfaceInfoManager() 1.78 +{ 1.79 + gInterfaceInfoManager = nullptr; 1.80 +} 1.81 + 1.82 +XPTInterfaceInfoManager::XPTInterfaceInfoManager() 1.83 + : mWorkingSet(), 1.84 + mResolveLock("XPTInterfaceInfoManager.mResolveLock") 1.85 +{ 1.86 +} 1.87 + 1.88 +XPTInterfaceInfoManager::~XPTInterfaceInfoManager() 1.89 +{ 1.90 + // We only do this on shutdown of the service. 1.91 + mWorkingSet.InvalidateInterfaceInfos(); 1.92 + 1.93 + UnregisterWeakMemoryReporter(this); 1.94 +} 1.95 + 1.96 +void 1.97 +XPTInterfaceInfoManager::InitMemoryReporter() 1.98 +{ 1.99 + RegisterWeakMemoryReporter(this); 1.100 +} 1.101 + 1.102 +void 1.103 +XPTInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length) 1.104 +{ 1.105 + XPTState *state = XPT_NewXDRState(XPT_DECODE, buf, length); 1.106 + if (!state) 1.107 + return; 1.108 + 1.109 + XPTCursor cursor; 1.110 + if (!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) { 1.111 + XPT_DestroyXDRState(state); 1.112 + return; 1.113 + } 1.114 + 1.115 + XPTHeader *header = nullptr; 1.116 + if (XPT_DoHeader(gXPTIStructArena, &cursor, &header)) { 1.117 + RegisterXPTHeader(header); 1.118 + } 1.119 + 1.120 + XPT_DestroyXDRState(state); 1.121 +} 1.122 + 1.123 +void 1.124 +XPTInterfaceInfoManager::RegisterXPTHeader(XPTHeader* aHeader) 1.125 +{ 1.126 + if (aHeader->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) { 1.127 + NS_ASSERTION(!aHeader->num_interfaces,"bad libxpt"); 1.128 + 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)); 1.129 + } 1.130 + 1.131 + xptiTypelibGuts* typelib = xptiTypelibGuts::Create(aHeader); 1.132 + 1.133 + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); 1.134 + for(uint16_t k = 0; k < aHeader->num_interfaces; k++) 1.135 + VerifyAndAddEntryIfNew(aHeader->interface_directory + k, k, typelib); 1.136 +} 1.137 + 1.138 +void 1.139 +XPTInterfaceInfoManager::VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface, 1.140 + uint16_t idx, 1.141 + xptiTypelibGuts* typelib) 1.142 +{ 1.143 + if (!iface->interface_descriptor) 1.144 + return; 1.145 + 1.146 + // The number of maximum methods is not arbitrary. It is the same value as 1.147 + // in xpcom/reflect/xptcall/public/genstubs.pl; do not change this value 1.148 + // without changing that one or you WILL see problems. 1.149 + if (iface->interface_descriptor->num_methods > 250 && 1.150 + !(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags))) { 1.151 + NS_ASSERTION(0, "Too many methods to handle for the stub, cannot load"); 1.152 + fprintf(stderr, "ignoring too large interface: %s\n", iface->name); 1.153 + return; 1.154 + } 1.155 + 1.156 + mWorkingSet.mTableReentrantMonitor.AssertCurrentThreadIn(); 1.157 + xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(iface->iid); 1.158 + if (entry) { 1.159 + // XXX validate this info to find possible inconsistencies 1.160 + LOG_AUTOREG((" ignoring repeated interface: %s\n", iface->name)); 1.161 + return; 1.162 + } 1.163 + 1.164 + // Build a new xptiInterfaceEntry object and hook it up. 1.165 + 1.166 + entry = xptiInterfaceEntry::Create(iface->name, 1.167 + iface->iid, 1.168 + iface->interface_descriptor, 1.169 + typelib); 1.170 + if (!entry) 1.171 + return; 1.172 + 1.173 + //XXX We should SetHeader too as part of the validation, no? 1.174 + entry->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags)); 1.175 + entry->SetBuiltinClassFlag(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags)); 1.176 + 1.177 + mWorkingSet.mIIDTable.Put(entry->IID(), entry); 1.178 + mWorkingSet.mNameTable.Put(entry->GetTheName(), entry); 1.179 + 1.180 + typelib->SetEntryAt(idx, entry); 1.181 + 1.182 + LOG_AUTOREG((" added interface: %s\n", iface->name)); 1.183 +} 1.184 + 1.185 +// this is a private helper 1.186 +static nsresult 1.187 +EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval) 1.188 +{ 1.189 + if (!entry) { 1.190 + *_retval = nullptr; 1.191 + return NS_ERROR_FAILURE; 1.192 + } 1.193 + 1.194 + nsRefPtr<xptiInterfaceInfo> info = entry->InterfaceInfo(); 1.195 + info.forget(_retval); 1.196 + return NS_OK; 1.197 +} 1.198 + 1.199 +xptiInterfaceEntry* 1.200 +XPTInterfaceInfoManager::GetInterfaceEntryForIID(const nsIID *iid) 1.201 +{ 1.202 + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); 1.203 + return mWorkingSet.mIIDTable.Get(*iid); 1.204 +} 1.205 + 1.206 +/* nsIInterfaceInfo getInfoForIID (in nsIIDPtr iid); */ 1.207 +NS_IMETHODIMP 1.208 +XPTInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval) 1.209 +{ 1.210 + NS_ASSERTION(iid, "bad param"); 1.211 + NS_ASSERTION(_retval, "bad param"); 1.212 + 1.213 + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); 1.214 + xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(*iid); 1.215 + return EntryToInfo(entry, _retval); 1.216 +} 1.217 + 1.218 +/* nsIInterfaceInfo getInfoForName (in string name); */ 1.219 +NS_IMETHODIMP 1.220 +XPTInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval) 1.221 +{ 1.222 + NS_ASSERTION(name, "bad param"); 1.223 + NS_ASSERTION(_retval, "bad param"); 1.224 + 1.225 + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); 1.226 + xptiInterfaceEntry* entry = mWorkingSet.mNameTable.Get(name); 1.227 + return EntryToInfo(entry, _retval); 1.228 +} 1.229 + 1.230 +/* nsIIDPtr getIIDForName (in string name); */ 1.231 +NS_IMETHODIMP 1.232 +XPTInterfaceInfoManager::GetIIDForName(const char *name, nsIID * *_retval) 1.233 +{ 1.234 + NS_ASSERTION(name, "bad param"); 1.235 + NS_ASSERTION(_retval, "bad param"); 1.236 + 1.237 + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); 1.238 + xptiInterfaceEntry* entry = mWorkingSet.mNameTable.Get(name); 1.239 + if (!entry) { 1.240 + *_retval = nullptr; 1.241 + return NS_ERROR_FAILURE; 1.242 + } 1.243 + 1.244 + return entry->GetIID(_retval); 1.245 +} 1.246 + 1.247 +/* string getNameForIID (in nsIIDPtr iid); */ 1.248 +NS_IMETHODIMP 1.249 +XPTInterfaceInfoManager::GetNameForIID(const nsIID * iid, char **_retval) 1.250 +{ 1.251 + NS_ASSERTION(iid, "bad param"); 1.252 + NS_ASSERTION(_retval, "bad param"); 1.253 + 1.254 + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); 1.255 + xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(*iid); 1.256 + if (!entry) { 1.257 + *_retval = nullptr; 1.258 + return NS_ERROR_FAILURE; 1.259 + } 1.260 + 1.261 + return entry->GetName(_retval); 1.262 +} 1.263 + 1.264 +static PLDHashOperator 1.265 +xpti_ArrayAppender(const char* name, xptiInterfaceEntry* entry, void* arg) 1.266 +{ 1.267 + nsCOMArray<nsIInterfaceInfo>* array = static_cast<nsCOMArray<nsIInterfaceInfo>*>(arg); 1.268 + 1.269 + if (entry->GetScriptableFlag()) { 1.270 + nsCOMPtr<nsIInterfaceInfo> ii = entry->InterfaceInfo(); 1.271 + array->AppendElement(ii); 1.272 + } 1.273 + return PL_DHASH_NEXT; 1.274 +} 1.275 + 1.276 +/* nsIEnumerator enumerateInterfaces (); */ 1.277 +void 1.278 +XPTInterfaceInfoManager::GetScriptableInterfaces(nsCOMArray<nsIInterfaceInfo>& aInterfaces) 1.279 +{ 1.280 + // I didn't want to incur the size overhead of using nsHashtable just to 1.281 + // make building an enumerator easier. So, this code makes a snapshot of 1.282 + // the table using an nsISupportsArray and builds an enumerator for that. 1.283 + // We can afford this transient cost. 1.284 + 1.285 + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); 1.286 + aInterfaces.SetCapacity(mWorkingSet.mNameTable.Count()); 1.287 + mWorkingSet.mNameTable.EnumerateRead(xpti_ArrayAppender, &aInterfaces); 1.288 +} 1.289 + 1.290 +struct ArrayAndPrefix 1.291 +{ 1.292 + nsISupportsArray* array; 1.293 + const char* prefix; 1.294 + uint32_t length; 1.295 +}; 1.296 + 1.297 +static PLDHashOperator 1.298 +xpti_ArrayPrefixAppender(const char* keyname, xptiInterfaceEntry* entry, void* arg) 1.299 +{ 1.300 + ArrayAndPrefix* args = (ArrayAndPrefix*) arg; 1.301 + 1.302 + const char* name = entry->GetTheName(); 1.303 + if (name != PL_strnstr(name, args->prefix, args->length)) 1.304 + return PL_DHASH_NEXT; 1.305 + 1.306 + nsCOMPtr<nsIInterfaceInfo> ii; 1.307 + if (NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii)))) 1.308 + args->array->AppendElement(ii); 1.309 + return PL_DHASH_NEXT; 1.310 +} 1.311 + 1.312 +/* nsIEnumerator enumerateInterfacesWhoseNamesStartWith (in string prefix); */ 1.313 +NS_IMETHODIMP 1.314 +XPTInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(const char *prefix, nsIEnumerator **_retval) 1.315 +{ 1.316 + nsCOMPtr<nsISupportsArray> array; 1.317 + NS_NewISupportsArray(getter_AddRefs(array)); 1.318 + if (!array) 1.319 + return NS_ERROR_UNEXPECTED; 1.320 + 1.321 + ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor); 1.322 + ArrayAndPrefix args = {array, prefix, static_cast<uint32_t>(strlen(prefix))}; 1.323 + mWorkingSet.mNameTable.EnumerateRead(xpti_ArrayPrefixAppender, &args); 1.324 + 1.325 + return array->Enumerate(_retval); 1.326 +} 1.327 + 1.328 +/* void autoRegisterInterfaces (); */ 1.329 +NS_IMETHODIMP 1.330 +XPTInterfaceInfoManager::AutoRegisterInterfaces() 1.331 +{ 1.332 + return NS_ERROR_NOT_IMPLEMENTED; 1.333 +}