tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

XPCWrappedNativeInfo.cpp (20663B)


      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/. */
      6 
      7 /* Manage the shared info about interfaces for use by wrappedNatives. */
      8 
      9 #include "xpcprivate.h"
     10 #include "XPCMaps.h"
     11 #include "js/Wrapper.h"
     12 
     13 #include "mozilla/MemoryReporting.h"
     14 #include "mozilla/SourceLocation.h"
     15 #include "nsIScriptError.h"
     16 #include "nsPrintfCString.h"
     17 #include "nsPointerHashKeys.h"
     18 
     19 using namespace JS;
     20 using namespace mozilla;
     21 
     22 /***************************************************************************/
     23 
     24 // XPCNativeMember
     25 
     26 // static
     27 bool XPCNativeMember::GetCallInfo(JSObject* funobj,
     28                                  RefPtr<XPCNativeInterface>* pInterface,
     29                                  XPCNativeMember** pMember) {
     30  funobj = js::UncheckedUnwrap(funobj);
     31  Value memberVal =
     32      js::GetFunctionNativeReserved(funobj, XPC_FUNCTION_NATIVE_MEMBER_SLOT);
     33 
     34  *pMember = static_cast<XPCNativeMember*>(memberVal.toPrivate());
     35  *pInterface = (*pMember)->GetInterface();
     36 
     37  return true;
     38 }
     39 
     40 bool XPCNativeMember::NewFunctionObject(XPCCallContext& ccx,
     41                                        XPCNativeInterface* iface,
     42                                        HandleObject parent, Value* pval) {
     43  MOZ_ASSERT(!IsConstant(),
     44             "Only call this if you're sure this is not a constant!");
     45 
     46  return Resolve(ccx, iface, parent, pval);
     47 }
     48 
     49 bool XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface,
     50                              HandleObject parent, Value* vp) {
     51  MOZ_ASSERT(iface == GetInterface());
     52  if (IsConstant()) {
     53    RootedValue resultVal(ccx);
     54    nsCString name;
     55    if (NS_FAILED(iface->GetInterfaceInfo()->GetConstant(mIndex, &resultVal,
     56                                                         getter_Copies(name))))
     57      return false;
     58 
     59    *vp = resultVal;
     60 
     61    return true;
     62  }
     63  // else...
     64 
     65  // This is a method or attribute - we'll be needing a function object
     66 
     67  int argc;
     68  JSNative callback;
     69 
     70  if (IsMethod()) {
     71    const nsXPTMethodInfo* info;
     72    if (NS_FAILED(iface->GetInterfaceInfo()->GetMethodInfo(mIndex, &info))) {
     73      return false;
     74    }
     75 
     76    // Note: ASSUMES that retval is last arg.
     77    argc = (int)info->ParamCount();
     78    if (info->HasRetval()) {
     79      argc--;
     80    }
     81 
     82    callback = XPC_WN_CallMethod;
     83  } else {
     84    argc = 0;
     85    callback = XPC_WN_GetterSetter;
     86  }
     87 
     88  jsid name = GetName();
     89  JS_MarkCrossZoneId(ccx, name);
     90 
     91  JSFunction* fun;
     92  if (name.isString()) {
     93    fun = js::NewFunctionByIdWithReserved(ccx, callback, argc, 0, name);
     94  } else {
     95    fun = js::NewFunctionWithReserved(ccx, callback, argc, 0, nullptr);
     96  }
     97  if (!fun) {
     98    return false;
     99  }
    100 
    101  JSObject* funobj = JS_GetFunctionObject(fun);
    102  if (!funobj) {
    103    return false;
    104  }
    105 
    106  js::SetFunctionNativeReserved(funobj, XPC_FUNCTION_NATIVE_MEMBER_SLOT,
    107                                PrivateValue(this));
    108  js::SetFunctionNativeReserved(funobj, XPC_FUNCTION_PARENT_OBJECT_SLOT,
    109                                ObjectValue(*parent));
    110 
    111  vp->setObject(*funobj);
    112 
    113  return true;
    114 }
    115 
    116 /***************************************************************************/
    117 // XPCNativeInterface
    118 
    119 XPCNativeInterface::~XPCNativeInterface() {
    120  XPCJSRuntime::Get()->GetIID2NativeInterfaceMap()->Remove(this);
    121 }
    122 
    123 // static
    124 already_AddRefed<XPCNativeInterface> XPCNativeInterface::GetNewOrUsed(
    125    JSContext* cx, const nsIID* iid) {
    126  RefPtr<XPCNativeInterface> iface;
    127  XPCJSRuntime* rt = XPCJSRuntime::Get();
    128 
    129  IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
    130  if (!map) {
    131    return nullptr;
    132  }
    133 
    134  iface = map->Find(*iid);
    135 
    136  if (iface) {
    137    return iface.forget();
    138  }
    139 
    140  const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByIID(*iid);
    141  if (!info) {
    142    return nullptr;
    143  }
    144 
    145  return NewInstance(cx, map, info);
    146 }
    147 
    148 // static
    149 already_AddRefed<XPCNativeInterface> XPCNativeInterface::GetNewOrUsed(
    150    JSContext* cx, const nsXPTInterfaceInfo* info) {
    151  RefPtr<XPCNativeInterface> iface;
    152 
    153  XPCJSRuntime* rt = XPCJSRuntime::Get();
    154 
    155  IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
    156  if (!map) {
    157    return nullptr;
    158  }
    159 
    160  iface = map->Find(info->IID());
    161 
    162  if (iface) {
    163    return iface.forget();
    164  }
    165 
    166  return NewInstance(cx, map, info);
    167 }
    168 
    169 // static
    170 already_AddRefed<XPCNativeInterface> XPCNativeInterface::GetNewOrUsed(
    171    JSContext* cx, const char* name) {
    172  const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByName(name);
    173  return info ? GetNewOrUsed(cx, info) : nullptr;
    174 }
    175 
    176 // static
    177 already_AddRefed<XPCNativeInterface> XPCNativeInterface::GetISupports(
    178    JSContext* cx) {
    179  // XXX We should optimize this to cache this common XPCNativeInterface.
    180  return GetNewOrUsed(cx, &NS_GET_IID(nsISupports));
    181 }
    182 
    183 // static
    184 already_AddRefed<XPCNativeInterface> XPCNativeInterface::NewInstance(
    185    JSContext* cx, IID2NativeInterfaceMap* aMap,
    186    const nsXPTInterfaceInfo* aInfo) {
    187  // XXX Investigate lazy init? This is a problem given the
    188  // 'placement new' scheme - we need to at least know how big to make
    189  // the object. We might do a scan of methods to determine needed size,
    190  // then make our object, but avoid init'ing *any* members until asked?
    191  // Find out how often we create these objects w/o really looking at
    192  // (or using) the members.
    193 
    194  if (aInfo->IsMainProcessScriptableOnly() && !XRE_IsParentProcess()) {
    195    nsCOMPtr<nsIConsoleService> console(
    196        do_GetService(NS_CONSOLESERVICE_CONTRACTID));
    197    if (console) {
    198      const char* intfNameChars = aInfo->Name();
    199      nsPrintfCString errorMsg("Use of %s in content process is deprecated.",
    200                               intfNameChars);
    201 
    202      auto location = JSCallingLocation::Get(cx);
    203      nsCOMPtr<nsIScriptError> error(
    204          do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
    205      error->Init(NS_ConvertUTF8toUTF16(errorMsg), location.FileName(),
    206                  location.mLine, location.mColumn, nsIScriptError::warningFlag,
    207                  "chrome javascript"_ns, false /* from private window */,
    208                  true /* from chrome context */);
    209      console->LogMessage(error);
    210    }
    211  }
    212 
    213  // Make sure the code below does not GC. This means we don't need to trace the
    214  // PropertyKeys in the MemberVector, or the XPCNativeInterface we create
    215  // before it's added to the map.
    216  JS::AutoCheckCannotGC nogc;
    217 
    218  const uint16_t methodCount = aInfo->MethodCount();
    219  const uint16_t constCount = aInfo->ConstantCount();
    220  const uint16_t totalCount = methodCount + constCount;
    221 
    222  using MemberVector =
    223      mozilla::Vector<XPCNativeMember, 16, InfallibleAllocPolicy>;
    224  MemberVector members;
    225  MOZ_ALWAYS_TRUE(members.reserve(totalCount));
    226 
    227  // NOTE: since getters and setters share a member, we might not use all
    228  // of the member objects.
    229 
    230  for (unsigned int i = 0; i < methodCount; i++) {
    231    const nsXPTMethodInfo& info = aInfo->Method(i);
    232 
    233    // don't reflect Addref or Release
    234    if (i == 1 || i == 2) {
    235      continue;
    236    }
    237 
    238    if (!info.IsReflectable()) {
    239      continue;
    240    }
    241 
    242    jsid name;
    243    if (!info.GetId(cx, name)) {
    244      NS_ERROR("bad method name");
    245      return nullptr;
    246    }
    247 
    248    if (info.IsSetter()) {
    249      MOZ_ASSERT(!members.empty(), "bad setter");
    250      // Note: ASSUMES Getter/Setter pairs are next to each other
    251      // This is a rule of the typelib spec.
    252      XPCNativeMember* cur = &members.back();
    253      MOZ_ASSERT(cur->GetName() == name, "bad setter");
    254      MOZ_ASSERT(cur->IsReadOnlyAttribute(), "bad setter");
    255      MOZ_ASSERT(cur->GetIndex() == i - 1, "bad setter");
    256      cur->SetWritableAttribute();
    257    } else {
    258      // XXX need better way to find dups
    259      // MOZ_ASSERT(!LookupMemberByID(name),"duplicate method name");
    260      size_t indexInInterface = members.length();
    261      if (indexInInterface == XPCNativeMember::GetMaxIndexInInterface()) {
    262        NS_WARNING("Too many members in interface");
    263        return nullptr;
    264      }
    265      XPCNativeMember cur;
    266      cur.SetName(name);
    267      if (info.IsGetter()) {
    268        cur.SetReadOnlyAttribute(i);
    269      } else {
    270        cur.SetMethod(i);
    271      }
    272      cur.SetIndexInInterface(indexInInterface);
    273      members.infallibleAppend(cur);
    274    }
    275  }
    276 
    277  for (unsigned int i = 0; i < constCount; i++) {
    278    RootedValue constant(cx);
    279    nsCString namestr;
    280    if (NS_FAILED(aInfo->GetConstant(i, &constant, getter_Copies(namestr)))) {
    281      return nullptr;
    282    }
    283 
    284    RootedString str(cx, JS_AtomizeString(cx, namestr.get()));
    285    if (!str) {
    286      NS_ERROR("bad constant name");
    287      return nullptr;
    288    }
    289    jsid name = PropertyKey::NonIntAtom(str);
    290 
    291    // XXX need better way to find dups
    292    // MOZ_ASSERT(!LookupMemberByID(name),"duplicate method/constant name");
    293    size_t indexInInterface = members.length();
    294    if (indexInInterface == XPCNativeMember::GetMaxIndexInInterface()) {
    295      NS_WARNING("Too many members in interface");
    296      return nullptr;
    297    }
    298    XPCNativeMember cur;
    299    cur.SetName(name);
    300    cur.SetConstant(i);
    301    cur.SetIndexInInterface(indexInInterface);
    302    members.infallibleAppend(cur);
    303  }
    304 
    305  const char* bytes = aInfo->Name();
    306  if (!bytes) {
    307    return nullptr;
    308  }
    309  RootedString str(cx, JS_AtomizeString(cx, bytes));
    310  if (!str) {
    311    return nullptr;
    312  }
    313 
    314  RootedId interfaceName(cx, PropertyKey::NonIntAtom(str));
    315 
    316  // Use placement new to create an object with the right amount of space
    317  // to hold the members array
    318  size_t size = sizeof(XPCNativeInterface);
    319  if (members.length() > 1) {
    320    size += (members.length() - 1) * sizeof(XPCNativeMember);
    321  }
    322  void* place = new char[size];
    323  if (!place) {
    324    return nullptr;
    325  }
    326 
    327  RefPtr<XPCNativeInterface> obj =
    328      new (place) XPCNativeInterface(aInfo, interfaceName);
    329 
    330  obj->mMemberCount = members.length();
    331  // copy valid members
    332  if (!members.empty()) {
    333    memcpy(obj->mMembers, members.begin(),
    334           members.length() * sizeof(XPCNativeMember));
    335  }
    336 
    337  if (!aMap->AddNew(obj)) {
    338    NS_ERROR("failed to add our interface!");
    339    return nullptr;
    340  }
    341 
    342  return obj.forget();
    343 }
    344 
    345 // static
    346 void XPCNativeInterface::DestroyInstance(XPCNativeInterface* inst) {
    347  inst->~XPCNativeInterface();
    348  delete[] (char*)inst;
    349 }
    350 
    351 size_t XPCNativeInterface::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) {
    352  return mallocSizeOf(this);
    353 }
    354 
    355 void XPCNativeInterface::Trace(JSTracer* trc) {
    356  JS::TraceRoot(trc, &mName, "XPCNativeInterface::mName");
    357 
    358  for (size_t i = 0; i < mMemberCount; i++) {
    359    JS::PropertyKey key = mMembers[i].GetName();
    360    JS::TraceRoot(trc, &key, "XPCNativeInterface::mMembers");
    361    MOZ_ASSERT(mMembers[i].GetName() == key);
    362  }
    363 }
    364 
    365 void IID2NativeInterfaceMap::Trace(JSTracer* trc) {
    366  for (Map::Enum e(mMap); !e.empty(); e.popFront()) {
    367    XPCNativeInterface* iface = e.front().value();
    368    iface->Trace(trc);
    369  }
    370 }
    371 
    372 void XPCNativeInterface::DebugDump(int16_t depth) {
    373 #ifdef DEBUG
    374  XPC_LOG_ALWAYS(("XPCNativeInterface @ %p", this));
    375  XPC_LOG_INDENT();
    376  XPC_LOG_ALWAYS(("name is %s", GetNameString()));
    377  XPC_LOG_ALWAYS(("mInfo @ %p", mInfo));
    378  XPC_LOG_OUTDENT();
    379 #endif
    380 }
    381 
    382 /***************************************************************************/
    383 // XPCNativeSetKey
    384 
    385 HashNumber XPCNativeSetKey::Hash() const {
    386  HashNumber h = 0;
    387 
    388  if (mBaseSet) {
    389    // If we ever start using mCx here, adjust the constructors accordingly.
    390    XPCNativeInterface** current = mBaseSet->GetInterfaceArray();
    391    uint16_t count = mBaseSet->GetInterfaceCount();
    392    for (uint16_t i = 0; i < count; i++) {
    393      h = AddToHash(h, *(current++));
    394    }
    395  } else {
    396    // A newly created set will contain nsISupports first...
    397    RefPtr<XPCNativeInterface> isupp = XPCNativeInterface::GetISupports(mCx);
    398    h = AddToHash(h, isupp.get());
    399 
    400    // ...but no more than once.
    401    if (isupp == mAddition) {
    402      return h;
    403    }
    404  }
    405 
    406  if (mAddition) {
    407    h = AddToHash(h, mAddition.get());
    408  }
    409 
    410  return h;
    411 }
    412 
    413 /***************************************************************************/
    414 // XPCNativeSet
    415 
    416 XPCNativeSet::~XPCNativeSet() {
    417  // Remove |this| before we clear the interfaces to ensure that the
    418  // hashtable look up is correct.
    419 
    420  XPCJSRuntime::Get()->GetNativeSetMap()->Remove(this);
    421 
    422  for (int i = 0; i < mInterfaceCount; i++) {
    423    NS_RELEASE(mInterfaces[i]);
    424  }
    425 }
    426 
    427 // static
    428 already_AddRefed<XPCNativeSet> XPCNativeSet::GetNewOrUsed(JSContext* cx,
    429                                                          const nsIID* iid) {
    430  RefPtr<XPCNativeInterface> iface = XPCNativeInterface::GetNewOrUsed(cx, iid);
    431  if (!iface) {
    432    return nullptr;
    433  }
    434 
    435  XPCNativeSetKey key(cx, iface);
    436 
    437  XPCJSRuntime* xpcrt = XPCJSRuntime::Get();
    438  NativeSetMap* map = xpcrt->GetNativeSetMap();
    439  if (!map) {
    440    return nullptr;
    441  }
    442 
    443  RefPtr<XPCNativeSet> set = map->Find(&key);
    444 
    445  if (set) {
    446    return set.forget();
    447  }
    448 
    449  set = NewInstance(cx, {std::move(iface)});
    450  if (!set) {
    451    return nullptr;
    452  }
    453 
    454  if (!map->AddNew(&key, set)) {
    455    NS_ERROR("failed to add our set!");
    456    set = nullptr;
    457  }
    458 
    459  return set.forget();
    460 }
    461 
    462 // static
    463 already_AddRefed<XPCNativeSet> XPCNativeSet::GetNewOrUsed(
    464    JSContext* cx, nsIClassInfo* classInfo) {
    465  XPCJSRuntime* xpcrt = XPCJSRuntime::Get();
    466  ClassInfo2NativeSetMap* map = xpcrt->GetClassInfo2NativeSetMap();
    467  if (!map) {
    468    return nullptr;
    469  }
    470 
    471  RefPtr<XPCNativeSet> set = map->Find(classInfo);
    472 
    473  if (set) {
    474    return set.forget();
    475  }
    476 
    477  AutoTArray<nsIID, 4> iids;
    478  if (NS_FAILED(classInfo->GetInterfaces(iids))) {
    479    // Note: I'm making it OK for this call to fail so that one can add
    480    // nsIClassInfo to classes implemented in script without requiring this
    481    // method to be implemented.
    482 
    483    // Make sure these are set correctly...
    484    iids.Clear();
    485  }
    486 
    487  // Try to look up each IID's XPCNativeInterface object.
    488  nsTArray<RefPtr<XPCNativeInterface>> interfaces(iids.Length());
    489  for (auto& iid : iids) {
    490    RefPtr<XPCNativeInterface> iface =
    491        XPCNativeInterface::GetNewOrUsed(cx, &iid);
    492    if (iface) {
    493      interfaces.AppendElement(iface.forget());
    494    }
    495  }
    496 
    497  // Build a set from the interfaces specified here.
    498  if (interfaces.Length() > 0) {
    499    set = NewInstance(cx, std::move(interfaces));
    500    if (set) {
    501      NativeSetMap* map2 = xpcrt->GetNativeSetMap();
    502      if (!map2) {
    503        return set.forget();
    504      }
    505 
    506      XPCNativeSetKey key(set);
    507      XPCNativeSet* set2 = map2->Add(&key, set);
    508      if (!set2) {
    509        NS_ERROR("failed to add our set");
    510        return nullptr;
    511      }
    512 
    513      // It is okay to find an existing entry here because
    514      // we did not look for one before we called Add().
    515      if (set2 != set) {
    516        set = set2;
    517      }
    518    }
    519  } else {
    520    set = GetNewOrUsed(cx, &NS_GET_IID(nsISupports));
    521  }
    522 
    523  if (set) {
    524 #ifdef DEBUG
    525    XPCNativeSet* set2 =
    526 #endif
    527        map->Add(classInfo, set);
    528    MOZ_ASSERT(set2, "failed to add our set!");
    529    MOZ_ASSERT(set2 == set, "hashtables inconsistent!");
    530  }
    531 
    532  return set.forget();
    533 }
    534 
    535 // static
    536 void XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo) {
    537  XPCJSRuntime* xpcrt = nsXPConnect::GetRuntimeInstance();
    538  ClassInfo2NativeSetMap* map = xpcrt->GetClassInfo2NativeSetMap();
    539  if (map) {
    540    map->Remove(classInfo);
    541  }
    542 }
    543 
    544 // static
    545 already_AddRefed<XPCNativeSet> XPCNativeSet::GetNewOrUsed(
    546    JSContext* cx, XPCNativeSetKey* key) {
    547  NativeSetMap* map = XPCJSRuntime::Get()->GetNativeSetMap();
    548  if (!map) {
    549    return nullptr;
    550  }
    551 
    552  RefPtr<XPCNativeSet> set = map->Find(key);
    553 
    554  if (set) {
    555    return set.forget();
    556  }
    557 
    558  if (key->GetBaseSet()) {
    559    set = NewInstanceMutate(key);
    560  } else {
    561    set = NewInstance(cx, {key->GetAddition()});
    562  }
    563 
    564  if (!set) {
    565    return nullptr;
    566  }
    567 
    568  if (!map->AddNew(key, set)) {
    569    NS_ERROR("failed to add our set!");
    570    set = nullptr;
    571  }
    572 
    573  return set.forget();
    574 }
    575 
    576 // static
    577 already_AddRefed<XPCNativeSet> XPCNativeSet::GetNewOrUsed(
    578    JSContext* cx, XPCNativeSet* firstSet, XPCNativeSet* secondSet,
    579    bool preserveFirstSetOrder) {
    580  // Figure out how many interfaces we'll need in the new set.
    581  uint32_t uniqueCount = firstSet->mInterfaceCount;
    582  for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) {
    583    if (!firstSet->HasInterface(secondSet->mInterfaces[i])) {
    584      uniqueCount++;
    585    }
    586  }
    587 
    588  // If everything in secondSet was a duplicate, we can just use the first
    589  // set.
    590  if (uniqueCount == firstSet->mInterfaceCount) {
    591    return RefPtr<XPCNativeSet>(firstSet).forget();
    592  }
    593 
    594  // If the secondSet is just a superset of the first, we can use it provided
    595  // that the caller doesn't care about ordering.
    596  if (!preserveFirstSetOrder && uniqueCount == secondSet->mInterfaceCount) {
    597    return RefPtr<XPCNativeSet>(secondSet).forget();
    598  }
    599 
    600  // Ok, darn. Now we have to make a new set.
    601  //
    602  // It would be faster to just create the new set all at once, but that
    603  // would involve wrangling with some pretty hairy code - especially since
    604  // a lot of stuff assumes that sets are created by adding one interface to an
    605  // existing set. So let's just do the slow and easy thing and hope that the
    606  // above optimizations handle the common cases.
    607  RefPtr<XPCNativeSet> currentSet = firstSet;
    608  for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) {
    609    XPCNativeInterface* iface = secondSet->mInterfaces[i];
    610    if (!currentSet->HasInterface(iface)) {
    611      // Create a new augmented set, inserting this interface at the end.
    612      XPCNativeSetKey key(currentSet, iface);
    613      currentSet = XPCNativeSet::GetNewOrUsed(cx, &key);
    614      if (!currentSet) {
    615        return nullptr;
    616      }
    617    }
    618  }
    619 
    620  // We've got the union set. Hand it back to the caller.
    621  MOZ_ASSERT(currentSet->mInterfaceCount == uniqueCount);
    622  return currentSet.forget();
    623 }
    624 
    625 // static
    626 already_AddRefed<XPCNativeSet> XPCNativeSet::NewInstance(
    627    JSContext* cx, nsTArray<RefPtr<XPCNativeInterface>>&& array) {
    628  if (array.Length() == 0) {
    629    return nullptr;
    630  }
    631 
    632  // We impose the invariant:
    633  // "All sets have exactly one nsISupports interface and it comes first."
    634  // This is the place where we impose that rule - even if given inputs
    635  // that don't exactly follow the rule.
    636 
    637  RefPtr<XPCNativeInterface> isup = XPCNativeInterface::GetISupports(cx);
    638  uint16_t slots = array.Length() + 1;
    639 
    640  for (auto key = array.begin(); key != array.end(); key++) {
    641    if (*key == isup) {
    642      slots--;
    643    }
    644  }
    645 
    646  // Use placement new to create an object with the right amount of space
    647  // to hold the members array
    648  int size = sizeof(XPCNativeSet);
    649  if (slots > 1) {
    650    size += (slots - 1) * sizeof(XPCNativeInterface*);
    651  }
    652  void* place = new char[size];
    653  RefPtr<XPCNativeSet> obj = new (place) XPCNativeSet();
    654 
    655  // Stick the nsISupports in front and skip additional nsISupport(s)
    656  XPCNativeInterface** outp = (XPCNativeInterface**)&obj->mInterfaces;
    657 
    658  NS_ADDREF(*(outp++) = isup);
    659 
    660  for (auto key = array.begin(); key != array.end(); key++) {
    661    RefPtr<XPCNativeInterface> cur = std::move(*key);
    662    if (isup == cur) {
    663      continue;
    664    }
    665    *(outp++) = cur.forget().take();
    666  }
    667  obj->mInterfaceCount = slots;
    668 
    669  return obj.forget();
    670 }
    671 
    672 // static
    673 already_AddRefed<XPCNativeSet> XPCNativeSet::NewInstanceMutate(
    674    XPCNativeSetKey* key) {
    675  XPCNativeSet* otherSet = key->GetBaseSet();
    676  XPCNativeInterface* newInterface = key->GetAddition();
    677 
    678  MOZ_ASSERT(otherSet);
    679 
    680  if (!newInterface) {
    681    return nullptr;
    682  }
    683 
    684  // Use placement new to create an object with the right amount of space
    685  // to hold the members array
    686  int size = sizeof(XPCNativeSet);
    687  size += otherSet->mInterfaceCount * sizeof(XPCNativeInterface*);
    688  void* place = new char[size];
    689  RefPtr<XPCNativeSet> obj = new (place) XPCNativeSet();
    690 
    691  obj->mInterfaceCount = otherSet->mInterfaceCount + 1;
    692 
    693  XPCNativeInterface** src = otherSet->mInterfaces;
    694  XPCNativeInterface** dest = obj->mInterfaces;
    695  for (uint16_t i = 0; i < otherSet->mInterfaceCount; i++) {
    696    NS_ADDREF(*dest++ = *src++);
    697  }
    698  NS_ADDREF(*dest++ = newInterface);
    699 
    700  return obj.forget();
    701 }
    702 
    703 // static
    704 void XPCNativeSet::DestroyInstance(XPCNativeSet* inst) {
    705  inst->~XPCNativeSet();
    706  delete[] (char*)inst;
    707 }
    708 
    709 size_t XPCNativeSet::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) {
    710  return mallocSizeOf(this);
    711 }
    712 
    713 void XPCNativeSet::DebugDump(int16_t depth) {
    714 #ifdef DEBUG
    715  depth--;
    716  XPC_LOG_ALWAYS(("XPCNativeSet @ %p", this));
    717  XPC_LOG_INDENT();
    718 
    719  XPC_LOG_ALWAYS(("mInterfaceCount of %d", mInterfaceCount));
    720  if (depth) {
    721    for (uint16_t i = 0; i < mInterfaceCount; i++) {
    722      mInterfaces[i]->DebugDump(depth);
    723    }
    724  }
    725  XPC_LOG_OUTDENT();
    726 #endif
    727 }