xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* Implementation of xptiInterfaceInfoManager. */
     9 #include "mozilla/XPTInterfaceInfoManager.h"
    11 #include "mozilla/FileUtils.h"
    12 #include "mozilla/MemoryReporting.h"
    13 #include "mozilla/StaticPtr.h"
    15 #include "xptiprivate.h"
    16 #include "nsDependentString.h"
    17 #include "nsString.h"
    18 #include "nsISupportsArray.h"
    19 #include "nsArrayEnumerator.h"
    20 #include "nsDirectoryService.h"
    21 #include "nsIMemoryReporter.h"
    23 using namespace mozilla;
    25 NS_IMPL_ISUPPORTS(
    26   XPTInterfaceInfoManager,
    27   nsIInterfaceInfoManager,
    28   nsIMemoryReporter)
    30 static StaticRefPtr<XPTInterfaceInfoManager> gInterfaceInfoManager;
    32 size_t
    33 XPTInterfaceInfoManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
    34 {
    35     size_t n = aMallocSizeOf(this);
    36     ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
    37     // The entries themselves are allocated out of an arena accounted
    38     // for elsewhere, so don't measure them
    39     n += mWorkingSet.mIIDTable.SizeOfExcludingThis(nullptr, aMallocSizeOf);
    40     n += mWorkingSet.mNameTable.SizeOfExcludingThis(nullptr, aMallocSizeOf);
    41     return n;
    42 }
    44 MOZ_DEFINE_MALLOC_SIZE_OF(XPTIMallocSizeOf)
    46 NS_IMETHODIMP
    47 XPTInterfaceInfoManager::CollectReports(nsIHandleReportCallback* aHandleReport,
    48                                         nsISupports* aData)
    49 {
    50     size_t amount = SizeOfIncludingThis(XPTIMallocSizeOf);
    52     // Measure gXPTIStructArena here, too.  This is a bit grotty because it
    53     // doesn't belong to the XPTIInterfaceInfoManager, but there's no
    54     // obviously better place to measure it.
    55     amount += XPT_SizeOfArena(gXPTIStructArena, XPTIMallocSizeOf);
    57     return MOZ_COLLECT_REPORT(
    58         "explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES, amount,
    59         "Memory used by the XPCOM typelib system.");
    60 }
    62 // static
    63 XPTInterfaceInfoManager*
    64 XPTInterfaceInfoManager::GetSingleton()
    65 {
    66     if (!gInterfaceInfoManager) {
    67         gInterfaceInfoManager = new XPTInterfaceInfoManager();
    68         gInterfaceInfoManager->InitMemoryReporter();
    69     }
    70     return gInterfaceInfoManager;
    71 }
    73 void
    74 XPTInterfaceInfoManager::FreeInterfaceInfoManager()
    75 {
    76     gInterfaceInfoManager = nullptr;
    77 }
    79 XPTInterfaceInfoManager::XPTInterfaceInfoManager()
    80     :   mWorkingSet(),
    81         mResolveLock("XPTInterfaceInfoManager.mResolveLock")
    82 {
    83 }
    85 XPTInterfaceInfoManager::~XPTInterfaceInfoManager()
    86 {
    87     // We only do this on shutdown of the service.
    88     mWorkingSet.InvalidateInterfaceInfos();
    90     UnregisterWeakMemoryReporter(this);
    91 }
    93 void
    94 XPTInterfaceInfoManager::InitMemoryReporter()
    95 {
    96     RegisterWeakMemoryReporter(this);
    97 }
    99 void
   100 XPTInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length)
   101 {
   102     XPTState *state = XPT_NewXDRState(XPT_DECODE, buf, length);
   103     if (!state)
   104         return;
   106     XPTCursor cursor;
   107     if (!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) {
   108         XPT_DestroyXDRState(state);
   109         return;
   110     }
   112     XPTHeader *header = nullptr;
   113     if (XPT_DoHeader(gXPTIStructArena, &cursor, &header)) {
   114         RegisterXPTHeader(header);
   115     }
   117     XPT_DestroyXDRState(state);
   118 }
   120 void
   121 XPTInterfaceInfoManager::RegisterXPTHeader(XPTHeader* aHeader)
   122 {
   123     if (aHeader->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) {
   124         NS_ASSERTION(!aHeader->num_interfaces,"bad libxpt");
   125         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));
   126     }
   128     xptiTypelibGuts* typelib = xptiTypelibGuts::Create(aHeader);
   130     ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
   131     for(uint16_t k = 0; k < aHeader->num_interfaces; k++)
   132         VerifyAndAddEntryIfNew(aHeader->interface_directory + k, k, typelib);
   133 }
   135 void
   136 XPTInterfaceInfoManager::VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface,
   137                                                 uint16_t idx,
   138                                                 xptiTypelibGuts* typelib)
   139 {
   140     if (!iface->interface_descriptor)
   141         return;
   143     // The number of maximum methods is not arbitrary. It is the same value as
   144     // in xpcom/reflect/xptcall/public/genstubs.pl; do not change this value
   145     // without changing that one or you WILL see problems.
   146     if (iface->interface_descriptor->num_methods > 250 &&
   147             !(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags))) {
   148         NS_ASSERTION(0, "Too many methods to handle for the stub, cannot load");
   149         fprintf(stderr, "ignoring too large interface: %s\n", iface->name);
   150         return;
   151     }
   153     mWorkingSet.mTableReentrantMonitor.AssertCurrentThreadIn();
   154     xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(iface->iid);
   155     if (entry) {
   156         // XXX validate this info to find possible inconsistencies
   157         LOG_AUTOREG(("      ignoring repeated interface: %s\n", iface->name));
   158         return;
   159     }
   161     // Build a new xptiInterfaceEntry object and hook it up. 
   163     entry = xptiInterfaceEntry::Create(iface->name,
   164                                        iface->iid,
   165                                        iface->interface_descriptor,
   166                                        typelib);
   167     if (!entry)
   168         return;
   170     //XXX  We should SetHeader too as part of the validation, no?
   171     entry->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags));
   172     entry->SetBuiltinClassFlag(XPT_ID_IS_BUILTINCLASS(iface->interface_descriptor->flags));
   174     mWorkingSet.mIIDTable.Put(entry->IID(), entry);
   175     mWorkingSet.mNameTable.Put(entry->GetTheName(), entry);
   177     typelib->SetEntryAt(idx, entry);
   179     LOG_AUTOREG(("      added interface: %s\n", iface->name));
   180 }
   182 // this is a private helper
   183 static nsresult 
   184 EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval)
   185 {
   186     if (!entry) {
   187         *_retval = nullptr;
   188         return NS_ERROR_FAILURE;    
   189     }
   191     nsRefPtr<xptiInterfaceInfo> info = entry->InterfaceInfo();
   192     info.forget(_retval);
   193     return NS_OK;    
   194 }
   196 xptiInterfaceEntry*
   197 XPTInterfaceInfoManager::GetInterfaceEntryForIID(const nsIID *iid)
   198 {
   199     ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
   200     return mWorkingSet.mIIDTable.Get(*iid);
   201 }
   203 /* nsIInterfaceInfo getInfoForIID (in nsIIDPtr iid); */
   204 NS_IMETHODIMP
   205 XPTInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval)
   206 {
   207     NS_ASSERTION(iid, "bad param");
   208     NS_ASSERTION(_retval, "bad param");
   210     ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
   211     xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(*iid);
   212     return EntryToInfo(entry, _retval);
   213 }
   215 /* nsIInterfaceInfo getInfoForName (in string name); */
   216 NS_IMETHODIMP
   217 XPTInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval)
   218 {
   219     NS_ASSERTION(name, "bad param");
   220     NS_ASSERTION(_retval, "bad param");
   222     ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
   223     xptiInterfaceEntry* entry = mWorkingSet.mNameTable.Get(name);
   224     return EntryToInfo(entry, _retval);
   225 }
   227 /* nsIIDPtr getIIDForName (in string name); */
   228 NS_IMETHODIMP
   229 XPTInterfaceInfoManager::GetIIDForName(const char *name, nsIID * *_retval)
   230 {
   231     NS_ASSERTION(name, "bad param");
   232     NS_ASSERTION(_retval, "bad param");
   234     ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
   235     xptiInterfaceEntry* entry = mWorkingSet.mNameTable.Get(name);
   236     if (!entry) {
   237         *_retval = nullptr;
   238         return NS_ERROR_FAILURE;    
   239     }
   241     return entry->GetIID(_retval);
   242 }
   244 /* string getNameForIID (in nsIIDPtr iid); */
   245 NS_IMETHODIMP
   246 XPTInterfaceInfoManager::GetNameForIID(const nsIID * iid, char **_retval)
   247 {
   248     NS_ASSERTION(iid, "bad param");
   249     NS_ASSERTION(_retval, "bad param");
   251     ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
   252     xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(*iid);
   253     if (!entry) {
   254         *_retval = nullptr;
   255         return NS_ERROR_FAILURE;    
   256     }
   258     return entry->GetName(_retval);
   259 }
   261 static PLDHashOperator
   262 xpti_ArrayAppender(const char* name, xptiInterfaceEntry* entry, void* arg)
   263 {
   264     nsCOMArray<nsIInterfaceInfo>* array = static_cast<nsCOMArray<nsIInterfaceInfo>*>(arg);
   266     if (entry->GetScriptableFlag()) {
   267         nsCOMPtr<nsIInterfaceInfo> ii = entry->InterfaceInfo();
   268         array->AppendElement(ii);
   269     }
   270     return PL_DHASH_NEXT;
   271 }
   273 /* nsIEnumerator enumerateInterfaces (); */
   274 void
   275 XPTInterfaceInfoManager::GetScriptableInterfaces(nsCOMArray<nsIInterfaceInfo>& aInterfaces)
   276 {
   277     // I didn't want to incur the size overhead of using nsHashtable just to
   278     // make building an enumerator easier. So, this code makes a snapshot of 
   279     // the table using an nsISupportsArray and builds an enumerator for that.
   280     // We can afford this transient cost.
   282     ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
   283     aInterfaces.SetCapacity(mWorkingSet.mNameTable.Count());
   284     mWorkingSet.mNameTable.EnumerateRead(xpti_ArrayAppender, &aInterfaces);
   285 }
   287 struct ArrayAndPrefix
   288 {
   289     nsISupportsArray* array;
   290     const char*       prefix;
   291     uint32_t          length;
   292 };
   294 static PLDHashOperator
   295 xpti_ArrayPrefixAppender(const char* keyname, xptiInterfaceEntry* entry, void* arg)
   296 {
   297     ArrayAndPrefix* args = (ArrayAndPrefix*) arg;
   299     const char* name = entry->GetTheName();
   300     if (name != PL_strnstr(name, args->prefix, args->length))
   301         return PL_DHASH_NEXT;
   303     nsCOMPtr<nsIInterfaceInfo> ii;
   304     if (NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii))))
   305         args->array->AppendElement(ii);
   306     return PL_DHASH_NEXT;
   307 }
   309 /* nsIEnumerator enumerateInterfacesWhoseNamesStartWith (in string prefix); */
   310 NS_IMETHODIMP
   311 XPTInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(const char *prefix, nsIEnumerator **_retval)
   312 {
   313     nsCOMPtr<nsISupportsArray> array;
   314     NS_NewISupportsArray(getter_AddRefs(array));
   315     if (!array)
   316         return NS_ERROR_UNEXPECTED;
   318     ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
   319     ArrayAndPrefix args = {array, prefix, static_cast<uint32_t>(strlen(prefix))};
   320     mWorkingSet.mNameTable.EnumerateRead(xpti_ArrayPrefixAppender, &args);
   322     return array->Enumerate(_retval);
   323 }
   325 /* void autoRegisterInterfaces (); */
   326 NS_IMETHODIMP
   327 XPTInterfaceInfoManager::AutoRegisterInterfaces()
   328 {
   329     return NS_ERROR_NOT_IMPLEMENTED;
   330 }

mercurial