LCOV - code coverage report
Current view: top level - js/xpconnect/src - XPCWrappedNativeInfo.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 307 407 75.4 %
Date: 2017-07-14 16:53:18 Functions: 20 25 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
       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/. */
       6             : 
       7             : /* Manage the shared info about interfaces for use by wrappedNatives. */
       8             : 
       9             : #include "xpcprivate.h"
      10             : #include "jswrapper.h"
      11             : 
      12             : #include "mozilla/MemoryReporting.h"
      13             : #include "mozilla/XPTInterfaceInfoManager.h"
      14             : #include "nsIScriptError.h"
      15             : #include "nsPrintfCString.h"
      16             : 
      17             : using namespace JS;
      18             : using namespace mozilla;
      19             : 
      20             : /***************************************************************************/
      21             : 
      22             : // XPCNativeMember
      23             : 
      24             : // static
      25             : bool
      26       11152 : XPCNativeMember::GetCallInfo(JSObject* funobj,
      27             :                              RefPtr<XPCNativeInterface>* pInterface,
      28             :                              XPCNativeMember**    pMember)
      29             : {
      30       11152 :     funobj = js::UncheckedUnwrap(funobj);
      31             :     Value memberVal =
      32             :         js::GetFunctionNativeReserved(funobj,
      33       11152 :                                       XPC_FUNCTION_NATIVE_MEMBER_SLOT);
      34             : 
      35       11152 :     *pMember = static_cast<XPCNativeMember*>(memberVal.toPrivate());
      36       11152 :     *pInterface = (*pMember)->GetInterface();
      37             : 
      38       11152 :     return true;
      39             : }
      40             : 
      41             : bool
      42        2755 : XPCNativeMember::NewFunctionObject(XPCCallContext& ccx,
      43             :                                    XPCNativeInterface* iface, HandleObject parent,
      44             :                                    Value* pval)
      45             : {
      46        2755 :     MOZ_ASSERT(!IsConstant(), "Only call this if you're sure this is not a constant!");
      47             : 
      48        2755 :     return Resolve(ccx, iface, parent, pval);
      49             : }
      50             : 
      51             : bool
      52        2954 : XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface,
      53             :                          HandleObject parent, Value* vp)
      54             : {
      55        2954 :     MOZ_ASSERT(iface == GetInterface());
      56        2954 :     if (IsConstant()) {
      57         398 :         RootedValue resultVal(ccx);
      58         398 :         nsXPIDLCString name;
      59         199 :         if (NS_FAILED(iface->GetInterfaceInfo()->GetConstant(mIndex, &resultVal,
      60             :                                                              getter_Copies(name))))
      61           0 :             return false;
      62             : 
      63         199 :         *vp = resultVal;
      64             : 
      65         199 :         return true;
      66             :     }
      67             :     // else...
      68             : 
      69             :     // This is a method or attribute - we'll be needing a function object
      70             : 
      71             :     int argc;
      72             :     JSNative callback;
      73             : 
      74        2755 :     if (IsMethod()) {
      75             :         const nsXPTMethodInfo* info;
      76        1379 :         if (NS_FAILED(iface->GetInterfaceInfo()->GetMethodInfo(mIndex, &info)))
      77           0 :             return false;
      78             : 
      79             :         // Note: ASSUMES that retval is last arg.
      80        1379 :         argc = (int) info->GetParamCount();
      81        1379 :         if (argc && info->GetParam((uint8_t)(argc-1)).IsRetval())
      82         906 :             argc-- ;
      83             : 
      84        1379 :         callback = XPC_WN_CallMethod;
      85             :     } else {
      86        1376 :         argc = 0;
      87        1376 :         callback = XPC_WN_GetterSetter;
      88             :     }
      89             : 
      90        2755 :     JSFunction* fun = js::NewFunctionByIdWithReserved(ccx, callback, argc, 0, GetName());
      91        2755 :     if (!fun)
      92           0 :         return false;
      93             : 
      94        2755 :     JSObject* funobj = JS_GetFunctionObject(fun);
      95        2755 :     if (!funobj)
      96           0 :         return false;
      97             : 
      98             :     js::SetFunctionNativeReserved(funobj, XPC_FUNCTION_NATIVE_MEMBER_SLOT,
      99        2755 :                                   PrivateValue(this));
     100             :     js::SetFunctionNativeReserved(funobj, XPC_FUNCTION_PARENT_OBJECT_SLOT,
     101        2755 :                                   ObjectValue(*parent));
     102             : 
     103        2755 :     vp->setObject(*funobj);
     104             : 
     105        2755 :     return true;
     106             : }
     107             : 
     108             : /***************************************************************************/
     109             : // XPCNativeInterface
     110             : 
     111        3114 : XPCNativeInterface::~XPCNativeInterface()
     112             : {
     113        1557 :     XPCJSRuntime::Get()->GetIID2NativeInterfaceMap()->Remove(this);
     114        1557 : }
     115             : 
     116             : // static
     117             : already_AddRefed<XPCNativeInterface>
     118       13594 : XPCNativeInterface::GetNewOrUsed(const nsIID* iid)
     119             : {
     120       27188 :     RefPtr<XPCNativeInterface> iface;
     121       13594 :     XPCJSRuntime* rt = XPCJSRuntime::Get();
     122             : 
     123       13594 :     IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
     124       13594 :     if (!map)
     125           0 :         return nullptr;
     126             : 
     127       13594 :     iface = map->Find(*iid);
     128             : 
     129       13594 :     if (iface)
     130       12143 :         return iface.forget();
     131             : 
     132        2902 :     nsCOMPtr<nsIInterfaceInfo> info;
     133        1451 :     XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(iid, getter_AddRefs(info));
     134        1451 :     if (!info)
     135        1176 :         return nullptr;
     136             : 
     137         275 :     iface = NewInstance(info);
     138         275 :     if (!iface)
     139           0 :         return nullptr;
     140             : 
     141         275 :     XPCNativeInterface* iface2 = map->Add(iface);
     142         275 :     if (!iface2) {
     143           0 :         NS_ERROR("failed to add our interface!");
     144           0 :         iface = nullptr;
     145         275 :     } else if (iface2 != iface) {
     146           0 :         iface = iface2;
     147             :     }
     148             : 
     149         275 :     return iface.forget();
     150             : }
     151             : 
     152             : // static
     153             : already_AddRefed<XPCNativeInterface>
     154        1802 : XPCNativeInterface::GetNewOrUsed(nsIInterfaceInfo* info)
     155             : {
     156        3604 :     RefPtr<XPCNativeInterface> iface;
     157             : 
     158             :     const nsIID* iid;
     159        1802 :     if (NS_FAILED(info->GetIIDShared(&iid)) || !iid)
     160           0 :         return nullptr;
     161             : 
     162        1802 :     XPCJSRuntime* rt = XPCJSRuntime::Get();
     163             : 
     164        1802 :     IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
     165        1802 :     if (!map)
     166           0 :         return nullptr;
     167             : 
     168        1802 :     iface = map->Find(*iid);
     169             : 
     170        1802 :     if (iface)
     171         252 :         return iface.forget();
     172             : 
     173        1550 :     iface = NewInstance(info);
     174        1550 :     if (!iface)
     175           0 :         return nullptr;
     176             : 
     177        3100 :     RefPtr<XPCNativeInterface> iface2 = map->Add(iface);
     178        1550 :     if (!iface2) {
     179           0 :         NS_ERROR("failed to add our interface!");
     180           0 :         iface = nullptr;
     181        1550 :     } else if (iface2 != iface) {
     182           0 :         iface = iface2;
     183             :     }
     184             : 
     185        1550 :     return iface.forget();
     186             : }
     187             : 
     188             : // static
     189             : already_AddRefed<XPCNativeInterface>
     190           3 : XPCNativeInterface::GetNewOrUsed(const char* name)
     191             : {
     192           6 :     nsCOMPtr<nsIInterfaceInfo> info;
     193           3 :     XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(name, getter_AddRefs(info));
     194           6 :     return info ? GetNewOrUsed(info) : nullptr;
     195             : }
     196             : 
     197             : // static
     198             : already_AddRefed<XPCNativeInterface>
     199        2970 : XPCNativeInterface::GetISupports()
     200             : {
     201             :     // XXX We should optimize this to cache this common XPCNativeInterface.
     202        2970 :     return GetNewOrUsed(&NS_GET_IID(nsISupports));
     203             : }
     204             : 
     205             : // static
     206             : already_AddRefed<XPCNativeInterface>
     207        1825 : XPCNativeInterface::NewInstance(nsIInterfaceInfo* aInfo)
     208             : {
     209        3650 :     AutoJSContext cx;
     210             :     static const uint16_t MAX_LOCAL_MEMBER_COUNT = 16;
     211        3650 :     XPCNativeMember local_members[MAX_LOCAL_MEMBER_COUNT];
     212        3650 :     RefPtr<XPCNativeInterface> obj;
     213        1825 :     XPCNativeMember* members = nullptr;
     214             : 
     215             :     int i;
     216        1825 :     bool failed = false;
     217             :     uint16_t constCount;
     218             :     uint16_t methodCount;
     219             :     uint16_t totalCount;
     220        1825 :     uint16_t realTotalCount = 0;
     221             :     XPCNativeMember* cur;
     222        3650 :     RootedString str(cx);
     223        3650 :     RootedId interfaceName(cx);
     224             : 
     225             :     // XXX Investigate lazy init? This is a problem given the
     226             :     // 'placement new' scheme - we need to at least know how big to make
     227             :     // the object. We might do a scan of methods to determine needed size,
     228             :     // then make our object, but avoid init'ing *any* members until asked?
     229             :     // Find out how often we create these objects w/o really looking at
     230             :     // (or using) the members.
     231             : 
     232             :     bool canScript;
     233        1825 :     if (NS_FAILED(aInfo->IsScriptable(&canScript)) || !canScript)
     234           0 :         return nullptr;
     235             : 
     236             :     bool mainProcessScriptableOnly;
     237        1825 :     if (NS_FAILED(aInfo->IsMainProcessScriptableOnly(&mainProcessScriptableOnly)))
     238           0 :         return nullptr;
     239        1825 :     if (mainProcessScriptableOnly && !XRE_IsParentProcess()) {
     240           0 :         nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
     241           0 :         if (console) {
     242             :             const char* intfNameChars;
     243           0 :             aInfo->GetNameShared(&intfNameChars);
     244           0 :             nsPrintfCString errorMsg("Use of %s in content process is deprecated.", intfNameChars);
     245             : 
     246           0 :             nsAutoString filename;
     247           0 :             uint32_t lineno = 0, column = 0;
     248           0 :             nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column);
     249           0 :             nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
     250           0 :             error->Init(NS_ConvertUTF8toUTF16(errorMsg),
     251           0 :                         filename, EmptyString(),
     252           0 :                         lineno, column, nsIScriptError::warningFlag, "chrome javascript");
     253           0 :             console->LogMessage(error);
     254             :         }
     255             :     }
     256             : 
     257        3650 :     if (NS_FAILED(aInfo->GetMethodCount(&methodCount)) ||
     258        1825 :         NS_FAILED(aInfo->GetConstantCount(&constCount)))
     259           0 :         return nullptr;
     260             : 
     261             :     // If the interface does not have nsISupports in its inheritance chain
     262             :     // then we know we can't reflect its methods. However, some interfaces that
     263             :     // are used just to reflect constants are declared this way. We need to
     264             :     // go ahead and build the thing. But, we'll ignore whatever methods it may
     265             :     // have.
     266        1825 :     if (!nsXPConnect::IsISupportsDescendant(aInfo))
     267           0 :         methodCount = 0;
     268             : 
     269        1825 :     totalCount = methodCount + constCount;
     270             : 
     271        1825 :     if (totalCount > MAX_LOCAL_MEMBER_COUNT) {
     272         468 :         members = new XPCNativeMember[totalCount];
     273         234 :         if (!members)
     274           0 :             return nullptr;
     275             :     } else {
     276        1591 :         members = local_members;
     277             :     }
     278             : 
     279             :     // NOTE: since getters and setters share a member, we might not use all
     280             :     // of the member objects.
     281             : 
     282       16070 :     for (i = 0; i < methodCount; i++) {
     283             :         const nsXPTMethodInfo* info;
     284       14245 :         if (NS_FAILED(aInfo->GetMethodInfo(i, &info))) {
     285           0 :             failed = true;
     286           0 :             break;
     287             :         }
     288             : 
     289             :         // don't reflect Addref or Release
     290       14245 :         if (i == 1 || i == 2)
     291        7845 :             continue;
     292             : 
     293       10595 :         if (!XPCConvert::IsMethodReflectable(*info))
     294         545 :             continue;
     295             : 
     296       10050 :         str = JS_AtomizeAndPinString(cx, info->GetName());
     297       10050 :         if (!str) {
     298           0 :             NS_ERROR("bad method name");
     299           0 :             failed = true;
     300           0 :             break;
     301             :         }
     302       10050 :         jsid name = INTERNED_STRING_TO_JSID(cx, str);
     303             : 
     304       10050 :         if (info->IsSetter()) {
     305         550 :             MOZ_ASSERT(realTotalCount,"bad setter");
     306             :             // Note: ASSUMES Getter/Setter pairs are next to each other
     307             :             // This is a rule of the typelib spec.
     308         550 :             cur = &members[realTotalCount-1];
     309         550 :             MOZ_ASSERT(cur->GetName() == name,"bad setter");
     310         550 :             MOZ_ASSERT(cur->IsReadOnlyAttribute(),"bad setter");
     311         550 :             MOZ_ASSERT(cur->GetIndex() == i-1,"bad setter");
     312         550 :             cur->SetWritableAttribute();
     313             :         } else {
     314             :             // XXX need better way to find dups
     315             :             // MOZ_ASSERT(!LookupMemberByID(name),"duplicate method name");
     316        9500 :             if (realTotalCount == XPCNativeMember::GetMaxIndexInInterface()) {
     317           0 :                 NS_WARNING("Too many members in interface");
     318           0 :                 failed = true;
     319           0 :                 break;
     320             :             }
     321        9500 :             cur = &members[realTotalCount];
     322        9500 :             cur->SetName(name);
     323        9500 :             if (info->IsGetter())
     324        1903 :                 cur->SetReadOnlyAttribute(i);
     325             :             else
     326        7597 :                 cur->SetMethod(i);
     327        9500 :             cur->SetIndexInInterface(realTotalCount);
     328        9500 :             ++realTotalCount;
     329             :         }
     330             :     }
     331             : 
     332        1825 :     if (!failed) {
     333        5640 :         for (i = 0; i < constCount; i++) {
     334        7630 :             RootedValue constant(cx);
     335        7630 :             nsXPIDLCString namestr;
     336        3815 :             if (NS_FAILED(aInfo->GetConstant(i, &constant, getter_Copies(namestr)))) {
     337           0 :                 failed = true;
     338           0 :                 break;
     339             :             }
     340             : 
     341        3815 :             str = JS_AtomizeAndPinString(cx, namestr);
     342        3815 :             if (!str) {
     343           0 :                 NS_ERROR("bad constant name");
     344           0 :                 failed = true;
     345           0 :                 break;
     346             :             }
     347        3815 :             jsid name = INTERNED_STRING_TO_JSID(cx, str);
     348             : 
     349             :             // XXX need better way to find dups
     350             :             //MOZ_ASSERT(!LookupMemberByID(name),"duplicate method/constant name");
     351        3815 :             if (realTotalCount == XPCNativeMember::GetMaxIndexInInterface()) {
     352           0 :                 NS_WARNING("Too many members in interface");
     353           0 :                 failed = true;
     354           0 :                 break;
     355             :             }
     356        3815 :             cur = &members[realTotalCount];
     357        3815 :             cur->SetName(name);
     358        3815 :             cur->SetConstant(i);
     359        3815 :             cur->SetIndexInInterface(realTotalCount);
     360        3815 :             ++realTotalCount;
     361             :         }
     362             :     }
     363             : 
     364        1825 :     if (!failed) {
     365             :         const char* bytes;
     366        7300 :         if (NS_FAILED(aInfo->GetNameShared(&bytes)) || !bytes ||
     367        7300 :             nullptr == (str = JS_AtomizeAndPinString(cx, bytes))) {
     368           0 :             failed = true;
     369             :         }
     370        1825 :         interfaceName = INTERNED_STRING_TO_JSID(cx, str);
     371             :     }
     372             : 
     373        1825 :     if (!failed) {
     374             :         // Use placement new to create an object with the right amount of space
     375             :         // to hold the members array
     376        1825 :         int size = sizeof(XPCNativeInterface);
     377        1825 :         if (realTotalCount > 1)
     378        1804 :             size += (realTotalCount - 1) * sizeof(XPCNativeMember);
     379        3650 :         void* place = new char[size];
     380        1825 :         if (place)
     381        1825 :             obj = new(place) XPCNativeInterface(aInfo, interfaceName);
     382             : 
     383        1825 :         if (obj) {
     384        1825 :             obj->mMemberCount = realTotalCount;
     385             :             // copy valid members
     386        1825 :             if (realTotalCount)
     387        1825 :                 memcpy(obj->mMembers, members,
     388        1825 :                        realTotalCount * sizeof(XPCNativeMember));
     389             :         }
     390             :     }
     391             : 
     392        1825 :     if (members && members != local_members)
     393         234 :         delete [] members;
     394             : 
     395        1825 :     return obj.forget();
     396             : }
     397             : 
     398             : // static
     399             : void
     400        1557 : XPCNativeInterface::DestroyInstance(XPCNativeInterface* inst)
     401             : {
     402        1557 :     inst->~XPCNativeInterface();
     403        1557 :     delete [] (char*) inst;
     404        1557 : }
     405             : 
     406             : size_t
     407           0 : XPCNativeInterface::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
     408             : {
     409           0 :     return mallocSizeOf(this);
     410             : }
     411             : 
     412             : void
     413           0 : XPCNativeInterface::DebugDump(int16_t depth)
     414             : {
     415             : #ifdef DEBUG
     416           0 :     depth--;
     417           0 :     XPC_LOG_ALWAYS(("XPCNativeInterface @ %p", this));
     418           0 :         XPC_LOG_INDENT();
     419           0 :         XPC_LOG_ALWAYS(("name is %s", GetNameString()));
     420           0 :         XPC_LOG_ALWAYS(("mMemberCount is %d", mMemberCount));
     421           0 :         XPC_LOG_ALWAYS(("mInfo @ %p", mInfo.get()));
     422           0 :         XPC_LOG_OUTDENT();
     423             : #endif
     424           0 : }
     425             : 
     426             : /***************************************************************************/
     427             : // XPCNativeSetKey
     428             : 
     429             : static PLDHashNumber
     430        7094 : HashPointer(const void* ptr)
     431             : {
     432        7094 :     return NS_PTR_TO_UINT32(ptr) >> 2;
     433             : }
     434             : 
     435             : PLDHashNumber
     436        3745 : XPCNativeSetKey::Hash() const
     437             : {
     438        3745 :     PLDHashNumber h = 0;
     439             : 
     440        3745 :     if (mBaseSet) {
     441        1665 :         XPCNativeInterface** current = mBaseSet->GetInterfaceArray();
     442        1665 :         uint16_t count = mBaseSet->GetInterfaceCount();
     443        5020 :         for (uint16_t i = 0; i < count; i++) {
     444        3355 :             h ^= HashPointer(*(current++));
     445             :         }
     446             :     } else {
     447             :         // A newly created set will contain nsISupports first...
     448        3390 :         RefPtr<XPCNativeInterface> isupp = XPCNativeInterface::GetISupports();
     449        2080 :         h ^= HashPointer(isupp);
     450             : 
     451             :         // ...but no more than once.
     452        2080 :         if (isupp == mAddition)
     453         770 :             return h;
     454             :     }
     455             : 
     456        2975 :     if (mAddition) {
     457        1659 :         h ^= HashPointer(mAddition);
     458             :     }
     459             : 
     460        2975 :     return h;
     461             : }
     462             : 
     463             : /***************************************************************************/
     464             : // XPCNativeSet
     465             : 
     466         752 : XPCNativeSet::~XPCNativeSet()
     467             : {
     468             :     // Remove |this| before we clear the interfaces to ensure that the
     469             :     // hashtable look up is correct.
     470         376 :     XPCJSRuntime::Get()->GetNativeSetMap()->Remove(this);
     471             : 
     472        1143 :     for (int i = 0; i < mInterfaceCount; i++) {
     473         767 :         NS_RELEASE(mInterfaces[i]);
     474             :     }
     475         376 : }
     476             : 
     477             : // static
     478             : already_AddRefed<XPCNativeSet>
     479         374 : XPCNativeSet::GetNewOrUsed(const nsIID* iid)
     480             : {
     481             :     RefPtr<XPCNativeInterface> iface =
     482         748 :         XPCNativeInterface::GetNewOrUsed(iid);
     483         374 :     if (!iface)
     484           0 :         return nullptr;
     485             : 
     486         748 :     XPCNativeSetKey key(iface);
     487             : 
     488         374 :     XPCJSRuntime* xpcrt = XPCJSRuntime::Get();
     489         374 :     NativeSetMap* map = xpcrt->GetNativeSetMap();
     490         374 :     if (!map)
     491           0 :         return nullptr;
     492             : 
     493         748 :     RefPtr<XPCNativeSet> set = map->Find(&key);
     494             : 
     495         374 :     if (set)
     496         371 :         return set.forget();
     497             : 
     498           3 :     set = NewInstance({iface.forget()});
     499           3 :     if (!set)
     500           0 :         return nullptr;
     501             : 
     502           3 :     if (!map->AddNew(&key, set)) {
     503           0 :         NS_ERROR("failed to add our set!");
     504           0 :         set = nullptr;
     505             :     }
     506             : 
     507           3 :     return set.forget();
     508             : }
     509             : 
     510             : // static
     511             : already_AddRefed<XPCNativeSet>
     512        1824 : XPCNativeSet::GetNewOrUsed(nsIClassInfo* classInfo)
     513             : {
     514        1824 :     XPCJSRuntime* xpcrt = XPCJSRuntime::Get();
     515        1824 :     ClassInfo2NativeSetMap* map = xpcrt->GetClassInfo2NativeSetMap();
     516        1824 :     if (!map)
     517           0 :         return nullptr;
     518             : 
     519        3648 :     RefPtr<XPCNativeSet> set = map->Find(classInfo);
     520             : 
     521        1824 :     if (set)
     522         755 :         return set.forget();
     523             : 
     524        1069 :     nsIID** iidArray = nullptr;
     525        1069 :     uint32_t iidCount = 0;
     526             : 
     527        1069 :     if (NS_FAILED(classInfo->GetInterfaces(&iidCount, &iidArray))) {
     528             :         // Note: I'm making it OK for this call to fail so that one can add
     529             :         // nsIClassInfo to classes implemented in script without requiring this
     530             :         // method to be implemented.
     531             : 
     532             :         // Make sure these are set correctly...
     533           0 :         iidArray = nullptr;
     534           0 :         iidCount = 0;
     535             :     }
     536             : 
     537        1069 :     MOZ_ASSERT((iidCount && iidArray) || !(iidCount || iidArray), "GetInterfaces returned bad array");
     538             : 
     539             :     // !!! from here on we only exit through the 'out' label !!!
     540             : 
     541        1069 :     if (iidCount) {
     542        1900 :         nsTArray<RefPtr<XPCNativeInterface>> interfaceArray(iidCount);
     543         950 :         nsIID** currentIID = iidArray;
     544             : 
     545        2864 :         for (uint32_t i = 0; i < iidCount; i++) {
     546        1914 :             nsIID* iid = *(currentIID++);
     547        1914 :             if (!iid) {
     548           0 :                 NS_ERROR("Null found in classinfo interface list");
     549           0 :                 continue;
     550             :             }
     551             : 
     552             :             RefPtr<XPCNativeInterface> iface =
     553        2652 :                 XPCNativeInterface::GetNewOrUsed(iid);
     554             : 
     555        1914 :             if (!iface) {
     556             :                 // XXX warn here
     557        1176 :                 continue;
     558             :             }
     559             : 
     560         738 :             interfaceArray.AppendElement(iface.forget());
     561             :         }
     562             : 
     563         950 :         if (interfaceArray.Length() > 0) {
     564         695 :             set = NewInstance(Move(interfaceArray));
     565         695 :             if (set) {
     566         695 :                 NativeSetMap* map2 = xpcrt->GetNativeSetMap();
     567         695 :                 if (!map2)
     568           0 :                     goto out;
     569             : 
     570        1390 :                 XPCNativeSetKey key(set);
     571             : 
     572         695 :                 XPCNativeSet* set2 = map2->Add(&key, set);
     573         695 :                 if (!set2) {
     574           0 :                     NS_ERROR("failed to add our set!");
     575           0 :                     set = nullptr;
     576           0 :                     goto out;
     577             :                 }
     578             :                 // It is okay to find an existing entry here because
     579             :                 // we did not look for one before we called Add().
     580         695 :                 if (set2 != set) {
     581         329 :                     set = set2;
     582             :                 }
     583             :             }
     584             :         } else
     585         255 :             set = GetNewOrUsed(&NS_GET_IID(nsISupports));
     586             :     } else
     587         119 :         set = GetNewOrUsed(&NS_GET_IID(nsISupports));
     588             : 
     589        1069 :     if (set) {
     590             : #ifdef DEBUG
     591             :         XPCNativeSet* set2 =
     592             : #endif
     593        1069 :           map->Add(classInfo, set);
     594        1069 :         MOZ_ASSERT(set2, "failed to add our set!");
     595        1069 :         MOZ_ASSERT(set2 == set, "hashtables inconsistent!");
     596             :     }
     597             : 
     598             : out:
     599        1069 :     if (iidArray)
     600         950 :         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iidCount, iidArray);
     601             : 
     602        1069 :     return set.forget();
     603             : }
     604             : 
     605             : // static
     606             : void
     607           0 : XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo)
     608             : {
     609           0 :     XPCJSRuntime* xpcrt = nsXPConnect::GetRuntimeInstance();
     610           0 :     ClassInfo2NativeSetMap* map = xpcrt->GetClassInfo2NativeSetMap();
     611           0 :     if (map)
     612           0 :         map->Remove(classInfo);
     613           0 : }
     614             : 
     615             : // static
     616             : already_AddRefed<XPCNativeSet>
     617        1568 : XPCNativeSet::GetNewOrUsed(XPCNativeSetKey* key)
     618             : {
     619        1568 :     NativeSetMap* map = XPCJSRuntime::Get()->GetNativeSetMap();
     620        1568 :     if (!map)
     621           0 :         return nullptr;
     622             : 
     623        3136 :     RefPtr<XPCNativeSet> set = map->Find(key);
     624             : 
     625        1568 :     if (set)
     626        1326 :         return set.forget();
     627             : 
     628         242 :     if (key->GetBaseSet())
     629          57 :         set = NewInstanceMutate(key);
     630             :     else
     631         185 :         set = NewInstance({key->GetAddition()});
     632             : 
     633         242 :     if (!set)
     634           0 :         return nullptr;
     635             : 
     636         242 :     if (!map->AddNew(key, set)) {
     637           0 :         NS_ERROR("failed to add our set!");
     638           0 :         set = nullptr;
     639             :     }
     640             : 
     641         242 :     return set.forget();
     642             : }
     643             : 
     644             : // static
     645             : already_AddRefed<XPCNativeSet>
     646        2766 : XPCNativeSet::GetNewOrUsed(XPCNativeSet* firstSet,
     647             :                            XPCNativeSet* secondSet,
     648             :                            bool preserveFirstSetOrder)
     649             : {
     650             :     // Figure out how many interfaces we'll need in the new set.
     651        2766 :     uint32_t uniqueCount = firstSet->mInterfaceCount;
     652        9873 :     for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) {
     653        7107 :         if (!firstSet->HasInterface(secondSet->mInterfaces[i]))
     654         549 :             uniqueCount++;
     655             :     }
     656             : 
     657             :     // If everything in secondSet was a duplicate, we can just use the first
     658             :     // set.
     659        2766 :     if (uniqueCount == firstSet->mInterfaceCount)
     660        2367 :         return RefPtr<XPCNativeSet>(firstSet).forget();
     661             : 
     662             :     // If the secondSet is just a superset of the first, we can use it provided
     663             :     // that the caller doesn't care about ordering.
     664         399 :     if (!preserveFirstSetOrder && uniqueCount == secondSet->mInterfaceCount)
     665         398 :         return RefPtr<XPCNativeSet>(secondSet).forget();
     666             : 
     667             :     // Ok, darn. Now we have to make a new set.
     668             :     //
     669             :     // It would be faster to just create the new set all at once, but that
     670             :     // would involve wrangling with some pretty hairy code - especially since
     671             :     // a lot of stuff assumes that sets are created by adding one interface to an
     672             :     // existing set. So let's just do the slow and easy thing and hope that the
     673             :     // above optimizations handle the common cases.
     674           2 :     RefPtr<XPCNativeSet> currentSet = firstSet;
     675           4 :     for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) {
     676           3 :         XPCNativeInterface* iface = secondSet->mInterfaces[i];
     677           3 :         if (!currentSet->HasInterface(iface)) {
     678             :             // Create a new augmented set, inserting this interface at the end.
     679           4 :             XPCNativeSetKey key(currentSet, iface);
     680           2 :             currentSet = XPCNativeSet::GetNewOrUsed(&key);
     681           2 :             if (!currentSet)
     682           0 :                 return nullptr;
     683             :         }
     684             :     }
     685             : 
     686             :     // We've got the union set. Hand it back to the caller.
     687           1 :     MOZ_ASSERT(currentSet->mInterfaceCount == uniqueCount);
     688           1 :     return currentSet.forget();
     689             : }
     690             : 
     691             : // static
     692             : already_AddRefed<XPCNativeSet>
     693         883 : XPCNativeSet::NewInstance(nsTArray<RefPtr<XPCNativeInterface>>&& array)
     694             : {
     695         883 :     if (array.Length() == 0)
     696           0 :         return nullptr;
     697             : 
     698             :     // We impose the invariant:
     699             :     // "All sets have exactly one nsISupports interface and it comes first."
     700             :     // This is the place where we impose that rule - even if given inputs
     701             :     // that don't exactly follow the rule.
     702             : 
     703        1766 :     RefPtr<XPCNativeInterface> isup = XPCNativeInterface::GetISupports();
     704         883 :     uint16_t slots = array.Length() + 1;
     705             : 
     706        1809 :     for (auto key = array.begin(); key != array.end(); key++) {
     707         926 :         if (*key == isup)
     708           3 :             slots--;
     709             :     }
     710             : 
     711             :     // Use placement new to create an object with the right amount of space
     712             :     // to hold the members array
     713         883 :     int size = sizeof(XPCNativeSet);
     714         883 :     if (slots > 1)
     715         880 :         size += (slots - 1) * sizeof(XPCNativeInterface*);
     716        1766 :     void* place = new char[size];
     717        1766 :     RefPtr<XPCNativeSet> obj = new(place) XPCNativeSet();
     718             : 
     719             :     // Stick the nsISupports in front and skip additional nsISupport(s)
     720         883 :     XPCNativeInterface** outp = (XPCNativeInterface**) &obj->mInterfaces;
     721         883 :     uint16_t memberCount = 1;   // for the one member in nsISupports
     722             : 
     723         883 :     NS_ADDREF(*(outp++) = isup);
     724             : 
     725        1809 :     for (auto key = array.begin(); key != array.end(); key++) {
     726        1849 :         RefPtr<XPCNativeInterface> cur = key->forget();
     727         926 :         if (isup == cur)
     728           3 :             continue;
     729         923 :         memberCount += cur->GetMemberCount();
     730         923 :         *(outp++) = cur.forget().take();
     731             :     }
     732         883 :     obj->mMemberCount = memberCount;
     733         883 :     obj->mInterfaceCount = slots;
     734             : 
     735         883 :     return obj.forget();
     736             : }
     737             : 
     738             : // static
     739             : already_AddRefed<XPCNativeSet>
     740          57 : XPCNativeSet::NewInstanceMutate(XPCNativeSetKey* key)
     741             : {
     742          57 :     XPCNativeSet* otherSet = key->GetBaseSet();
     743          57 :     XPCNativeInterface* newInterface = key->GetAddition();
     744             : 
     745          57 :     MOZ_ASSERT(otherSet);
     746             : 
     747          57 :     if (!newInterface)
     748           0 :         return nullptr;
     749             : 
     750             :     // Use placement new to create an object with the right amount of space
     751             :     // to hold the members array
     752          57 :     int size = sizeof(XPCNativeSet);
     753          57 :     size += otherSet->mInterfaceCount * sizeof(XPCNativeInterface*);
     754         114 :     void* place = new char[size];
     755         114 :     RefPtr<XPCNativeSet> obj = new(place) XPCNativeSet();
     756             : 
     757         114 :     obj->mMemberCount = otherSet->GetMemberCount() +
     758          57 :         newInterface->GetMemberCount();
     759          57 :     obj->mInterfaceCount = otherSet->mInterfaceCount + 1;
     760             : 
     761          57 :     XPCNativeInterface** src = otherSet->mInterfaces;
     762          57 :     XPCNativeInterface** dest = obj->mInterfaces;
     763         187 :     for (uint16_t i = 0; i < otherSet->mInterfaceCount; i++) {
     764         130 :         NS_ADDREF(*dest++ = *src++);
     765             :     }
     766          57 :     NS_ADDREF(*dest++ = newInterface);
     767             : 
     768          57 :     return obj.forget();
     769             : }
     770             : 
     771             : // static
     772             : void
     773         376 : XPCNativeSet::DestroyInstance(XPCNativeSet* inst)
     774             : {
     775         376 :     inst->~XPCNativeSet();
     776         376 :     delete [] (char*) inst;
     777         376 : }
     778             : 
     779             : size_t
     780           0 : XPCNativeSet::SizeOfIncludingThis(MallocSizeOf mallocSizeOf)
     781             : {
     782           0 :     return mallocSizeOf(this);
     783             : }
     784             : 
     785             : void
     786           0 : XPCNativeSet::DebugDump(int16_t depth)
     787             : {
     788             : #ifdef DEBUG
     789           0 :     depth--;
     790           0 :     XPC_LOG_ALWAYS(("XPCNativeSet @ %p", this));
     791           0 :         XPC_LOG_INDENT();
     792             : 
     793           0 :         XPC_LOG_ALWAYS(("mInterfaceCount of %d", mInterfaceCount));
     794           0 :         if (depth) {
     795           0 :             for (uint16_t i = 0; i < mInterfaceCount; i++)
     796           0 :                 mInterfaces[i]->DebugDump(depth);
     797             :         }
     798           0 :         XPC_LOG_ALWAYS(("mMemberCount of %d", mMemberCount));
     799           0 :         XPC_LOG_OUTDENT();
     800             : #endif
     801           0 : }

Generated by: LCOV version 1.13