xpcom/reflect/xptinfo/src/xptiInterfaceInfo.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: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /* Implementation of xptiInterfaceEntry and xptiInterfaceInfo. */
     8 #include "xptiprivate.h"
     9 #include "mozilla/XPTInterfaceInfoManager.h"
    11 using namespace mozilla;
    13 /***************************************************************************/
    14 // Debug Instrumentation...
    16 #ifdef SHOW_INFO_COUNT_STATS
    17 static int DEBUG_TotalInfos = 0;
    18 static int DEBUG_CurrentInfos = 0;
    19 static int DEBUG_MaxInfos = 0;
    20 static int DEBUG_ReentrantMonitorEntryCount = 0;
    22 #define LOG_INFO_CREATE(t)                                                  \
    23     DEBUG_TotalInfos++;                                                     \
    24     DEBUG_CurrentInfos++;                                                   \
    25     if(DEBUG_MaxInfos < DEBUG_CurrentInfos)                                 \
    26         DEBUG_MaxInfos = DEBUG_CurrentInfos /* no ';' */
    28 #define LOG_INFO_DESTROY(t)                                                 \
    29     DEBUG_CurrentInfos-- /* no ';' */
    31 #define LOG_INFO_MONITOR_ENTRY                                              \
    32     DEBUG_ReentrantMonitorEntryCount++ /* no ';' */
    34 #else /* SHOW_INFO_COUNT_STATS */
    36 #define LOG_INFO_CREATE(t)     ((void)0)
    37 #define LOG_INFO_DESTROY(t)    ((void)0)
    38 #define LOG_INFO_MONITOR_ENTRY ((void)0)
    39 #endif /* SHOW_INFO_COUNT_STATS */
    41 /* static */ xptiInterfaceEntry*
    42 xptiInterfaceEntry::Create(const char* name, const nsID& iid,
    43                            XPTInterfaceDescriptor* aDescriptor,
    44                            xptiTypelibGuts* aTypelib)
    45 {
    46     int namelen = strlen(name);
    47     return new (XPT_MALLOC(gXPTIStructArena,
    48                            sizeof(xptiInterfaceEntry) + namelen))
    49         xptiInterfaceEntry(name, namelen, iid, aDescriptor, aTypelib);
    50 }
    52 xptiInterfaceEntry::xptiInterfaceEntry(const char* name,
    53                                        size_t nameLength,
    54                                        const nsID& iid,
    55                                        XPTInterfaceDescriptor* aDescriptor,
    56                                        xptiTypelibGuts* aTypelib)
    57     : mIID(iid)
    58     , mDescriptor(aDescriptor)
    59     , mMethodBaseIndex(0)
    60     , mConstantBaseIndex(0)
    61     , mTypelib(aTypelib)
    62     , mParent(nullptr)
    63     , mInfo(nullptr)
    64     , mFlags(0)
    65 {
    66     memcpy(mName, name, nameLength);
    67     SetResolvedState(PARTIALLY_RESOLVED);
    68 }
    70 bool 
    71 xptiInterfaceEntry::Resolve()
    72 {
    73     MutexAutoLock lock(XPTInterfaceInfoManager::GetResolveLock());
    74     return ResolveLocked();
    75 }
    77 bool 
    78 xptiInterfaceEntry::ResolveLocked()
    79 {
    80     int resolvedState = GetResolveState();
    82     if(resolvedState == FULLY_RESOLVED)
    83         return true;
    84     if(resolvedState == RESOLVE_FAILED)
    85         return false;
    87     NS_ASSERTION(GetResolveState() == PARTIALLY_RESOLVED, "bad state!");    
    89     // Finish out resolution by finding parent and Resolving it so
    90     // we can set the info we get from it.
    92     uint16_t parent_index = mDescriptor->parent_interface;
    94     if(parent_index)
    95     {
    96         xptiInterfaceEntry* parent = 
    97             mTypelib->GetEntryAt(parent_index - 1);
    99         if(!parent || !parent->EnsureResolvedLocked())
   100         {
   101             SetResolvedState(RESOLVE_FAILED);
   102             return false;
   103         }
   105         mParent = parent;
   107         mMethodBaseIndex =
   108             parent->mMethodBaseIndex + 
   109             parent->mDescriptor->num_methods;
   111         mConstantBaseIndex =
   112             parent->mConstantBaseIndex + 
   113             parent->mDescriptor->num_constants;
   115     }
   116     LOG_RESOLVE(("+ complete resolve of %s\n", mName));
   118     SetResolvedState(FULLY_RESOLVED);
   119     return true;
   120 }        
   122 /**************************************************/
   123 // These non-virtual methods handle the delegated nsIInterfaceInfo methods.
   125 nsresult
   126 xptiInterfaceEntry::GetName(char **name)
   127 {
   128     // It is not necessary to Resolve because this info is read from manifest.
   129     *name = (char*) nsMemory::Clone(mName, strlen(mName)+1);
   130     return *name ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
   131 }
   133 nsresult
   134 xptiInterfaceEntry::GetIID(nsIID **iid)
   135 {
   136     // It is not necessary to Resolve because this info is read from manifest.
   137     *iid = (nsIID*) nsMemory::Clone(&mIID, sizeof(nsIID));
   138     return *iid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
   139 }
   141 nsresult
   142 xptiInterfaceEntry::IsScriptable(bool* result)
   143 {
   144     // It is not necessary to Resolve because this info is read from manifest.
   145     *result = GetScriptableFlag();
   146     return NS_OK;
   147 }
   149 nsresult
   150 xptiInterfaceEntry::IsFunction(bool* result)
   151 {
   152     if(!EnsureResolved())
   153         return NS_ERROR_UNEXPECTED;
   155     *result = XPT_ID_IS_FUNCTION(mDescriptor->flags);
   156     return NS_OK;
   157 }
   159 nsresult
   160 xptiInterfaceEntry::GetMethodCount(uint16_t* count)
   161 {
   162     if(!EnsureResolved())
   163         return NS_ERROR_UNEXPECTED;
   165     *count = mMethodBaseIndex + 
   166              mDescriptor->num_methods;
   167     return NS_OK;
   168 }
   170 nsresult
   171 xptiInterfaceEntry::GetConstantCount(uint16_t* count)
   172 {
   173     if(!EnsureResolved())
   174         return NS_ERROR_UNEXPECTED;
   176     *count = mConstantBaseIndex + 
   177              mDescriptor->num_constants;
   178     return NS_OK;
   179 }
   181 nsresult
   182 xptiInterfaceEntry::GetMethodInfo(uint16_t index, const nsXPTMethodInfo** info)
   183 {
   184     if(!EnsureResolved())
   185         return NS_ERROR_UNEXPECTED;
   187     if(index < mMethodBaseIndex)
   188         return mParent->GetMethodInfo(index, info);
   190     if(index >= mMethodBaseIndex + 
   191                 mDescriptor->num_methods)
   192     {
   193         NS_ERROR("bad param");
   194         *info = nullptr;
   195         return NS_ERROR_INVALID_ARG;
   196     }
   198     // else...
   199     *info = reinterpret_cast<nsXPTMethodInfo*>
   200        (&mDescriptor->method_descriptors[index - mMethodBaseIndex]);
   201     return NS_OK;
   202 }
   204 nsresult
   205 xptiInterfaceEntry::GetMethodInfoForName(const char* methodName, uint16_t *index,
   206                                          const nsXPTMethodInfo** result)
   207 {
   208     if(!EnsureResolved())
   209         return NS_ERROR_UNEXPECTED;
   211     // This is a slow algorithm, but this is not expected to be called much.
   212     for(uint16_t i = 0; i < mDescriptor->num_methods; ++i)
   213     {
   214         const nsXPTMethodInfo* info;
   215         info = reinterpret_cast<nsXPTMethodInfo*>
   216                                (&mDescriptor->
   217                                         method_descriptors[i]);
   218         if (PL_strcmp(methodName, info->GetName()) == 0) {
   219             *index = i + mMethodBaseIndex;
   220             *result = info;
   221             return NS_OK;
   222         }
   223     }
   225     if(mParent)
   226         return mParent->GetMethodInfoForName(methodName, index, result);
   227     else
   228     {
   229         *index = 0;
   230         *result = 0;
   231         return NS_ERROR_INVALID_ARG;
   232     }
   233 }
   235 nsresult
   236 xptiInterfaceEntry::GetConstant(uint16_t index, const nsXPTConstant** constant)
   237 {
   238     if(!EnsureResolved())
   239         return NS_ERROR_UNEXPECTED;
   241     if(index < mConstantBaseIndex)
   242         return mParent->GetConstant(index, constant);
   244     if(index >= mConstantBaseIndex + 
   245                 mDescriptor->num_constants)
   246     {
   247         NS_PRECONDITION(0, "bad param");
   248         *constant = nullptr;
   249         return NS_ERROR_INVALID_ARG;
   250     }
   252     // else...
   253     *constant =
   254         reinterpret_cast<nsXPTConstant*>
   255                         (&mDescriptor->
   256                                 const_descriptors[index -
   257                                     mConstantBaseIndex]);
   258     return NS_OK;
   259 }
   261 // this is a private helper
   263 nsresult 
   264 xptiInterfaceEntry::GetEntryForParam(uint16_t methodIndex, 
   265                                      const nsXPTParamInfo * param,
   266                                      xptiInterfaceEntry** entry)
   267 {
   268     if(!EnsureResolved())
   269         return NS_ERROR_UNEXPECTED;
   271     if(methodIndex < mMethodBaseIndex)
   272         return mParent->GetEntryForParam(methodIndex, param, entry);
   274     if(methodIndex >= mMethodBaseIndex + 
   275                       mDescriptor->num_methods)
   276     {
   277         NS_ERROR("bad param");
   278         return NS_ERROR_INVALID_ARG;
   279     }
   281     const XPTTypeDescriptor *td = &param->type;
   283     while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
   284         td = &mDescriptor->additional_types[td->type.additional_type];
   285     }
   287     if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_TYPE) {
   288         NS_ERROR("not an interface");
   289         return NS_ERROR_INVALID_ARG;
   290     }
   292     xptiInterfaceEntry* theEntry = mTypelib->
   293         GetEntryAt(td->type.iface - 1);
   295     // This can happen if a declared interface is not available at runtime.
   296     if(!theEntry)
   297     {
   298         NS_WARNING("Declared InterfaceInfo not found");
   299         *entry = nullptr;
   300         return NS_ERROR_FAILURE;
   301     }
   303     *entry = theEntry;
   304     return NS_OK;
   305 }
   307 nsresult
   308 xptiInterfaceEntry::GetInfoForParam(uint16_t methodIndex,
   309                                     const nsXPTParamInfo *param,
   310                                     nsIInterfaceInfo** info)
   311 {
   312     xptiInterfaceEntry* entry;
   313     nsresult rv = GetEntryForParam(methodIndex, param, &entry);
   314     if(NS_FAILED(rv))
   315         return rv;
   317     *info = entry->InterfaceInfo().take();
   319     return NS_OK;
   320 }
   322 nsresult
   323 xptiInterfaceEntry::GetIIDForParam(uint16_t methodIndex,
   324                                    const nsXPTParamInfo* param, nsIID** iid)
   325 {
   326     xptiInterfaceEntry* entry;
   327     nsresult rv = GetEntryForParam(methodIndex, param, &entry);
   328     if(NS_FAILED(rv))
   329         return rv;
   330     return entry->GetIID(iid);
   331 }
   333 nsresult
   334 xptiInterfaceEntry::GetIIDForParamNoAlloc(uint16_t methodIndex, 
   335                                           const nsXPTParamInfo * param, 
   336                                           nsIID *iid)
   337 {
   338     xptiInterfaceEntry* entry;
   339     nsresult rv = GetEntryForParam(methodIndex, param, &entry);
   340     if(NS_FAILED(rv))
   341         return rv;
   342     *iid = entry->mIID;    
   343     return NS_OK;
   344 }
   346 // this is a private helper
   347 nsresult
   348 xptiInterfaceEntry::GetTypeInArray(const nsXPTParamInfo* param,
   349                                   uint16_t dimension,
   350                                   const XPTTypeDescriptor** type)
   351 {
   352     NS_ASSERTION(IsFullyResolved(), "bad state");
   354     const XPTTypeDescriptor *td = &param->type;
   355     const XPTTypeDescriptor *additional_types =
   356                 mDescriptor->additional_types;
   358     for (uint16_t i = 0; i < dimension; i++) {
   359         if(XPT_TDP_TAG(td->prefix) != TD_ARRAY) {
   360             NS_ERROR("bad dimension");
   361             return NS_ERROR_INVALID_ARG;
   362         }
   363         td = &additional_types[td->type.additional_type];
   364     }
   366     *type = td;
   367     return NS_OK;
   368 }
   370 nsresult
   371 xptiInterfaceEntry::GetTypeForParam(uint16_t methodIndex,
   372                                     const nsXPTParamInfo* param,
   373                                     uint16_t dimension,
   374                                     nsXPTType* type)
   375 {
   376     if(!EnsureResolved())
   377         return NS_ERROR_UNEXPECTED;
   379     if(methodIndex < mMethodBaseIndex)
   380         return mParent->
   381             GetTypeForParam(methodIndex, param, dimension, type);
   383     if(methodIndex >= mMethodBaseIndex + 
   384                       mDescriptor->num_methods)
   385     {
   386         NS_ERROR("bad index");
   387         return NS_ERROR_INVALID_ARG;
   388     }
   390     const XPTTypeDescriptor *td;
   392     if(dimension) {
   393         nsresult rv = GetTypeInArray(param, dimension, &td);
   394         if(NS_FAILED(rv))
   395             return rv;
   396     }
   397     else
   398         td = &param->type;
   400     *type = nsXPTType(td->prefix);
   401     return NS_OK;
   402 }
   404 nsresult
   405 xptiInterfaceEntry::GetSizeIsArgNumberForParam(uint16_t methodIndex,
   406                                                const nsXPTParamInfo* param,
   407                                                uint16_t dimension,
   408                                                uint8_t* argnum)
   409 {
   410     if(!EnsureResolved())
   411         return NS_ERROR_UNEXPECTED;
   413     if(methodIndex < mMethodBaseIndex)
   414         return mParent->
   415             GetSizeIsArgNumberForParam(methodIndex, param, dimension, argnum);
   417     if(methodIndex >= mMethodBaseIndex + 
   418                       mDescriptor->num_methods)
   419     {
   420         NS_ERROR("bad index");
   421         return NS_ERROR_INVALID_ARG;
   422     }
   424     const XPTTypeDescriptor *td;
   426     if(dimension) {
   427         nsresult rv = GetTypeInArray(param, dimension, &td);
   428         if(NS_FAILED(rv))
   429             return rv;
   430     }
   431     else
   432         td = &param->type;
   434     // verify that this is a type that has size_is
   435     switch (XPT_TDP_TAG(td->prefix)) {
   436       case TD_ARRAY:
   437       case TD_PSTRING_SIZE_IS:
   438       case TD_PWSTRING_SIZE_IS:
   439         break;
   440       default:
   441         NS_ERROR("not a size_is");
   442         return NS_ERROR_INVALID_ARG;
   443     }
   445     *argnum = td->argnum;
   446     return NS_OK;
   447 }
   449 nsresult
   450 xptiInterfaceEntry::GetInterfaceIsArgNumberForParam(uint16_t methodIndex,
   451                                                     const nsXPTParamInfo* param,
   452                                                     uint8_t* argnum)
   453 {
   454     if(!EnsureResolved())
   455         return NS_ERROR_UNEXPECTED;
   457     if(methodIndex < mMethodBaseIndex)
   458         return mParent->
   459             GetInterfaceIsArgNumberForParam(methodIndex, param, argnum);
   461     if(methodIndex >= mMethodBaseIndex + 
   462                       mDescriptor->num_methods)
   463     {
   464         NS_ERROR("bad index");
   465         return NS_ERROR_INVALID_ARG;
   466     }
   468     const XPTTypeDescriptor *td = &param->type;
   470     while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
   471         td = &mDescriptor->
   472                                 additional_types[td->type.additional_type];
   473     }
   475     if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_IS_TYPE) {
   476         NS_ERROR("not an iid_is");
   477         return NS_ERROR_INVALID_ARG;
   478     }
   480     *argnum = td->argnum;
   481     return NS_OK;
   482 }
   484 /* bool isIID (in nsIIDPtr IID); */
   485 nsresult 
   486 xptiInterfaceEntry::IsIID(const nsIID * IID, bool *_retval)
   487 {
   488     // It is not necessary to Resolve because this info is read from manifest.
   489     *_retval = mIID.Equals(*IID);
   490     return NS_OK;
   491 }
   493 /* void getNameShared ([shared, retval] out string name); */
   494 nsresult 
   495 xptiInterfaceEntry::GetNameShared(const char **name)
   496 {
   497     // It is not necessary to Resolve because this info is read from manifest.
   498     *name = mName;
   499     return NS_OK;
   500 }
   502 /* void getIIDShared ([shared, retval] out nsIIDPtrShared iid); */
   503 nsresult 
   504 xptiInterfaceEntry::GetIIDShared(const nsIID * *iid)
   505 {
   506     // It is not necessary to Resolve because this info is read from manifest.
   507     *iid = &mIID;
   508     return NS_OK;
   509 }
   511 /* bool hasAncestor (in nsIIDPtr iid); */
   512 nsresult 
   513 xptiInterfaceEntry::HasAncestor(const nsIID * iid, bool *_retval)
   514 {
   515     *_retval = false;
   517     for(xptiInterfaceEntry* current = this; 
   518         current;
   519         current = current->mParent)
   520     {
   521         if(current->mIID.Equals(*iid))
   522         {
   523             *_retval = true;
   524             break;
   525         }
   526         if(!current->EnsureResolved())
   527             return NS_ERROR_UNEXPECTED;
   528     }
   530     return NS_OK;
   531 }
   533 /***************************************************/
   535 already_AddRefed<xptiInterfaceInfo> 
   536 xptiInterfaceEntry::InterfaceInfo()
   537 {
   538 #ifdef DEBUG
   539     XPTInterfaceInfoManager::GetSingleton()->mWorkingSet.mTableReentrantMonitor.
   540         AssertCurrentThreadIn();
   541 #endif
   542     LOG_INFO_MONITOR_ENTRY;
   544     if(!mInfo)
   545     {
   546         mInfo = new xptiInterfaceInfo(this);
   547     }
   549     nsRefPtr<xptiInterfaceInfo> info = mInfo;
   550     return info.forget();
   551 }
   553 void     
   554 xptiInterfaceEntry::LockedInvalidateInterfaceInfo()
   555 {
   556     if(mInfo)
   557     {
   558         mInfo->Invalidate(); 
   559         mInfo = nullptr;
   560     }
   561 }
   563 bool
   564 xptiInterfaceInfo::BuildParent()
   565 {
   566     mozilla::ReentrantMonitorAutoEnter monitor(XPTInterfaceInfoManager::GetSingleton()->
   567                                     mWorkingSet.mTableReentrantMonitor);
   568     NS_ASSERTION(mEntry && 
   569                  mEntry->IsFullyResolved() && 
   570                  !mParent &&
   571                  mEntry->Parent(),
   572                 "bad BuildParent call");
   573     mParent = mEntry->Parent()->InterfaceInfo().take();
   574     return true;
   575 }
   577 /***************************************************************************/
   579 NS_IMPL_QUERY_INTERFACE(xptiInterfaceInfo, nsIInterfaceInfo)
   581 xptiInterfaceInfo::xptiInterfaceInfo(xptiInterfaceEntry* entry)
   582     : mEntry(entry), mParent(nullptr)
   583 {
   584     LOG_INFO_CREATE(this);
   585 }
   587 xptiInterfaceInfo::~xptiInterfaceInfo() 
   588 {
   589     LOG_INFO_DESTROY(this);
   590     NS_IF_RELEASE(mParent); 
   591     NS_ASSERTION(!mEntry, "bad state in dtor");
   592 }
   594 MozExternalRefCountType
   595 xptiInterfaceInfo::AddRef(void)
   596 {
   597     nsrefcnt cnt = ++mRefCnt;
   598     NS_LOG_ADDREF(this, cnt, "xptiInterfaceInfo", sizeof(*this));
   599     return cnt;
   600 }
   602 MozExternalRefCountType
   603 xptiInterfaceInfo::Release(void)
   604 {
   605     xptiInterfaceEntry* entry = mEntry;
   606     nsrefcnt cnt = --mRefCnt;
   607     NS_LOG_RELEASE(this, cnt, "xptiInterfaceInfo");
   608     if(!cnt)
   609     {
   610         mozilla::ReentrantMonitorAutoEnter monitor(XPTInterfaceInfoManager::
   611                                           GetSingleton()->mWorkingSet.
   612                                           mTableReentrantMonitor);
   613         LOG_INFO_MONITOR_ENTRY;
   615         // If InterfaceInfo added and *released* a reference before we 
   616         // acquired the monitor then 'this' might already be dead. In that
   617         // case we would not want to try to access any instance data. We
   618         // would want to bail immediately. If 'this' is already dead then the
   619         // entry will no longer have a pointer to 'this'. So, we can protect 
   620         // ourselves from danger without more aggressive locking.
   621         if(entry && !entry->InterfaceInfoEquals(this))
   622             return 0;
   624         // If InterfaceInfo added a reference before we acquired the monitor
   625         // then we want to bail out of here without destorying the object.
   626         if(mRefCnt)
   627             return 1;
   629         if(mEntry)
   630         {
   631             mEntry->LockedInterfaceInfoDeathNotification();
   632             mEntry = nullptr;
   633         }
   635         delete this;
   636         return 0;    
   637     }
   638     return cnt;
   639 }
   641 /***************************************************************************/

mercurial