xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp

changeset 0
6474c204b198
     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 +}

mercurial