Bug 1288870, part 2 - Make XPCNativeInterface refcounted. r=billm
☠☠ backed out by 93545d47fddb ☠ ☠
authorAndrew McCreight <continuation@gmail.com>
Thu, 18 Aug 2016 15:20:48 -0700
changeset 353702 4f0ab1a0d8dd56c0deeda13250ebb69e37c4a575
parent 353701 8d71aba5c1e7b96308a6e87ba0c66edafbd1dbdc
child 353703 83bbd356da976384d6971b5ef83d415b02c7193b
push id1324
push usermtabara@mozilla.com
push dateMon, 16 Jan 2017 13:07:44 +0000
treeherdermozilla-release@a01c49833940 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1288870
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1288870, part 2 - Make XPCNativeInterface refcounted. r=billm There are four classes that call Root() on XPCNativeInterface, and thus keep interfaces alive. Each of these gets converted to use a RefPtr: 1. XPCCallContext. This could be on some kind of hot path, but the FindMemberCall involves various string operations and hashtable lookups, so adding a single AddRef shouldn't matter. One weirdness here is that the context only roots the interface when |mState >= HAVE_NAME|. With a RefPtr<>, this requires nulling out mInterface. Fortunately, in most cases where it moves from rooting to non-rooting, it already does this. The one case it does not is in SystemIsBeingShutDown(), so my patch adds that. 2. XPCNativeSet. This holds an array of interfaces in a weird placement new array at the end of the object. I wasn't sure how a non-POD class would interact with the way the array is handled with casting, so I manually AddRef and Release things put into or removed from the array. 3. AutoMarkingNativeInterfacePtr simply becomes RefPtr<>. This is the bulk of the patch, in terms of number of lines changed. 4. Similarly, the one AutoMarkingNativeInterfacePtrArrayPtr becomes nsTArray<RefPtr<>>. This is the last use of the auto marking array class, so I deleted it. Here are some other notes on what the patch does: - XPCNativeInterfaces are created with placement new. This requires a special version of refcounting that calls DestroyInstance, defined in the previous patch. The GetNewOrUsed methods used to explicitly call DestroyInstance(), but with refcounting this is no longer needed. - The Mark() etc. methods are gutted so they don't do anything and mMarked is removed because it is no longer used. The methods will be cleaned up in later patches in this bug. - Interfaces are removed from mIID2NativeInterfaceMap in the dtor instead of during sweeping, requiring an extra hash table lookup. - All of the methods that can create a new interface (NewInstance, GetISupports, GetNewOrUsed) now return an already_AddRefed<>, which gives some static checking that we don't accidentally fail to hold onto a newly created interface. MozReview-Commit-ID: CrlH1ENAzvr
js/xpconnect/src/XPCCallContext.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCInlines.h
js/xpconnect/src/XPCJSID.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeInfo.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
--- a/js/xpconnect/src/XPCCallContext.cpp
+++ b/js/xpconnect/src/XPCCallContext.cpp
@@ -194,16 +194,18 @@ void
 XPCCallContext::SystemIsBeingShutDown()
 {
     // XXX This is pretty questionable since the per thread cleanup stuff
     // can be making this call on one thread for call contexts on another
     // thread.
     NS_WARNING("Shutting Down XPConnect even through there is a live XPCCallContext");
     mXPCJSRuntime = nullptr;
     mState = SYSTEM_SHUTDOWN;
+    mInterface = nullptr;
+
     if (mPrevCallContext)
         mPrevCallContext->SystemIsBeingShutDown();
 }
 
 XPCCallContext::~XPCCallContext()
 {
     if (mXPCJSRuntime) {
         DebugOnly<XPCCallContext*> old = mXPCJSRuntime->SetCallContext(mPrevCallContext);
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -815,19 +815,18 @@ XPCConvert::NativeInterface2JSObject(Mut
     if (cpow) {
         if (!JS_WrapObject(cx, &cpow))
             return false;
         d.setObject(*cpow);
         return true;
     }
 
     // Go ahead and create an XPCWrappedNative for this object.
-    AutoMarkingNativeInterfacePtr iface(cx);
-
-    iface = XPCNativeInterface::GetNewOrUsed(iid);
+    RefPtr<XPCNativeInterface> iface =
+        XPCNativeInterface::GetNewOrUsed(iid);
     if (!iface)
         return false;
 
     RefPtr<XPCWrappedNative> wrapper;
     nsresult rv = XPCWrappedNative::GetNewOrUsed(aHelper, xpcscope, iface,
                                                  getter_AddRefs(wrapper));
     if (NS_FAILED(rv) && pErr)
         *pErr = rv;
--- a/js/xpconnect/src/XPCInlines.h
+++ b/js/xpconnect/src/XPCInlines.h
@@ -316,50 +316,51 @@ XPCNativeSet::FindMember(jsid name, XPCN
             return true;
         }
     }
     return false;
 }
 
 inline bool
 XPCNativeSet::FindMember(jsid name, XPCNativeMember** pMember,
-                         XPCNativeInterface** pInterface) const
+                         RefPtr<XPCNativeInterface>* pInterface) const
 {
     uint16_t index;
     if (!FindMember(name, pMember, &index))
         return false;
     *pInterface = mInterfaces[index];
     return true;
 }
 
 inline bool
 XPCNativeSet::FindMember(jsid name,
                          XPCNativeMember** pMember,
-                         XPCNativeInterface** pInterface,
+                         RefPtr<XPCNativeInterface>* pInterface,
                          XPCNativeSet* protoSet,
                          bool* pIsLocal) const
 {
     XPCNativeMember* Member;
-    XPCNativeInterface* Interface;
+    RefPtr<XPCNativeInterface> Interface;
     XPCNativeMember* protoMember;
 
     if (!FindMember(name, &Member, &Interface))
         return false;
 
     *pMember = Member;
-    *pInterface = Interface;
 
     *pIsLocal =
         !Member ||
         !protoSet ||
         (protoSet != this &&
          !protoSet->MatchesSetUpToInterface(this, Interface) &&
          (!protoSet->FindMember(name, &protoMember, (uint16_t*)nullptr) ||
           protoMember != Member));
 
+    *pInterface = Interface.forget();
+
     return true;
 }
 
 inline XPCNativeInterface*
 XPCNativeSet::FindNamedInterface(jsid name) const
 {
     XPCNativeInterface* const * pp = mInterfaces;
 
--- a/js/xpconnect/src/XPCJSID.cpp
+++ b/js/xpconnect/src/XPCJSID.cpp
@@ -381,19 +381,18 @@ nsJSIID::Resolve(nsIXPConnectWrappedNati
                  JSContext * cx, JSObject * objArg,
                  jsid idArg, bool* resolvedp,
                  bool* _retval)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
     XPCCallContext ccx(cx);
 
-    AutoMarkingNativeInterfacePtr iface(ccx);
-
-    iface = XPCNativeInterface::GetNewOrUsed(mInfo);
+    RefPtr<XPCNativeInterface> iface =
+        XPCNativeInterface::GetNewOrUsed(mInfo);
 
     if (!iface)
         return NS_OK;
 
     XPCNativeMember* member = iface->FindMember(id);
     if (member && member->IsConstant()) {
         RootedValue val(cx);
         if (!member->GetConstantValue(ccx, iface, val.address()))
@@ -412,19 +411,18 @@ NS_IMETHODIMP
 nsJSIID::Enumerate(nsIXPConnectWrappedNative* wrapper,
                    JSContext * cx, JSObject * objArg, bool* _retval)
 {
     // In this case, let's just eagerly resolve...
 
     RootedObject obj(cx, objArg);
     XPCCallContext ccx(cx);
 
-    AutoMarkingNativeInterfacePtr iface(ccx);
-
-    iface = XPCNativeInterface::GetNewOrUsed(mInfo);
+    RefPtr<XPCNativeInterface> iface =
+        XPCNativeInterface::GetNewOrUsed(mInfo);
 
     if (!iface)
         return NS_OK;
 
     uint16_t count = iface->GetMemberCount();
     for (uint16_t i = 0; i < count; i++) {
         XPCNativeMember* member = iface->GetMemberAt(i);
         if (member && member->IsConstant() &&
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -840,27 +840,16 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp*
                 if (set->IsMarked()) {
                     set->Unmark();
                 } else if (doSweep) {
                     XPCNativeSet::DestroyInstance(set);
                     i.Remove();
                 }
             }
 
-            for (auto i = self->mIID2NativeInterfaceMap->Iter(); !i.Done(); i.Next()) {
-                auto entry = static_cast<IID2NativeInterfaceMap::Entry*>(i.Get());
-                XPCNativeInterface* iface = entry->value;
-                if (iface->IsMarked()) {
-                    iface->Unmark();
-                } else if (doSweep) {
-                    XPCNativeInterface::DestroyInstance(iface);
-                    i.Remove();
-                }
-            }
-
 #ifdef DEBUG
             XPCWrappedNativeScope::ASSERT_NoInterfaceSetsAreMarked();
 #endif
 
             // Now we are going to recycle any unused WrappedNativeTearoffs.
             // We do this by iterating all the live callcontexts
             // and marking the tearoffs in use. And then we
             // iterate over all the WrappedNative wrappers and sweep their
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -261,17 +261,17 @@ XPCWrappedNative::WrapNewGlobal(xpcObjec
     success = wrapper->FinishInit();
     MOZ_ASSERT(success);
 
     // Go through some extra work to find the tearoff. This is kind of silly
     // on a conceptual level: the point of tearoffs is to cache the results
     // of QI-ing mIdentity to different interfaces, and we don't need that
     // since we're dealing with nsISupports. But lots of code expects tearoffs
     // to exist for everything, so we just follow along.
-    XPCNativeInterface* iface = XPCNativeInterface::GetNewOrUsed(&NS_GET_IID(nsISupports));
+    RefPtr<XPCNativeInterface> iface = XPCNativeInterface::GetNewOrUsed(&NS_GET_IID(nsISupports));
     MOZ_ASSERT(iface);
     nsresult status;
     success = wrapper->FindTearOff(iface, false, &status);
     if (!success)
         return status;
 
     // Call the common creation finish routine. This does all of the bookkeeping
     // like inserting the wrapper into the wrapper map and setting up the wrapper
@@ -422,17 +422,17 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
 
     if (info && !isClassInfoSingleton) {
         proto = XPCWrappedNativeProto::GetNewOrUsed(Scope, info, &sciProto);
         if (!proto)
             return NS_ERROR_FAILURE;
 
         wrapper = new XPCWrappedNative(helper.forgetCanonical(), proto);
     } else {
-        AutoMarkingNativeInterfacePtr iface(cx, Interface);
+        RefPtr<XPCNativeInterface> iface = Interface;
         if (!iface)
             iface = XPCNativeInterface::GetISupports();
 
         AutoMarkingNativeSetPtr set(cx);
         set = XPCNativeSet::GetNewOrUsed(nullptr, iface, 0);
 
         if (!set)
             return NS_ERROR_FAILURE;
@@ -1083,19 +1083,17 @@ XPCWrappedNative::FindTearOff(XPCNativeI
 
     if (pError)
         *pError = rv;
     return to;
 }
 
 XPCWrappedNativeTearOff*
 XPCWrappedNative::FindTearOff(const nsIID& iid) {
-    AutoJSContext cx;
-    AutoMarkingNativeInterfacePtr iface(cx);
-    iface = XPCNativeInterface::GetNewOrUsed(&iid);
+    RefPtr<XPCNativeInterface> iface = XPCNativeInterface::GetNewOrUsed(&iid);
     return iface ? FindTearOff(iface) : nullptr;
 }
 
 nsresult
 XPCWrappedNative::InitTearOff(XPCWrappedNativeTearOff* aTearOff,
                               XPCNativeInterface* aInterface,
                               bool needJSObject)
 {
@@ -2110,17 +2108,17 @@ XPCWrappedNative::GetObjectPrincipal() c
     }
 #endif
     return principal;
 }
 
 NS_IMETHODIMP XPCWrappedNative::FindInterfaceWithMember(HandleId name,
                                                         nsIInterfaceInfo * *_retval)
 {
-    XPCNativeInterface* iface;
+    RefPtr<XPCNativeInterface> iface;
     XPCNativeMember*  member;
 
     if (GetSet()->FindMember(name, &member, &iface) && iface) {
         nsCOMPtr<nsIInterfaceInfo> temp = iface->GetInterfaceInfo();
         temp.forget(_retval);
     } else
         *_retval = nullptr;
     return NS_OK;
@@ -2206,22 +2204,22 @@ XPCWrappedNative::ToString(XPCWrappedNat
         name = JS_smprintf("%s", si->GetJSClass()->name);
     if (to) {
         const char* fmt = name ? " (%s)" : "%s";
         name = JS_sprintf_append(name, fmt,
                                  to->GetInterface()->GetNameString());
     } else if (!name) {
         XPCNativeSet* set = GetSet();
         XPCNativeInterface** array = set->GetInterfaceArray();
+        RefPtr<XPCNativeInterface> isupp = XPCNativeInterface::GetISupports();
         uint16_t count = set->GetInterfaceCount();
 
         if (count == 1)
             name = JS_sprintf_append(name, "%s", array[0]->GetNameString());
-        else if (count == 2 &&
-                 array[0] == XPCNativeInterface::GetISupports()) {
+        else if (count == 2 && array[0] == isupp) {
             name = JS_sprintf_append(name, "%s", array[1]->GetNameString());
         } else {
             for (uint16_t i = 0; i < count; i++) {
                 const char* fmt = (i == 0) ?
                                     "(%s" : (i == count-1) ?
                                         ", %s)" : ", %s";
                 name = JS_sprintf_append(name, fmt,
                                          array[i]->GetNameString());
--- a/js/xpconnect/src/XPCWrappedNativeInfo.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeInfo.cpp
@@ -18,17 +18,17 @@ using namespace mozilla;
 
 /***************************************************************************/
 
 // XPCNativeMember
 
 // static
 bool
 XPCNativeMember::GetCallInfo(JSObject* funobj,
-                             XPCNativeInterface** pInterface,
+                             RefPtr<XPCNativeInterface>* pInterface,
                              XPCNativeMember**    pMember)
 {
     funobj = js::UncheckedUnwrap(funobj);
     Value memberVal =
         js::GetFunctionNativeReserved(funobj,
                                       XPC_FUNCTION_NATIVE_MEMBER_SLOT);
 
     *pMember = static_cast<XPCNativeMember*>(memberVal.toPrivate());
@@ -102,119 +102,118 @@ XPCNativeMember::Resolve(XPCCallContext&
     vp->setObject(*funobj);
 
     return true;
 }
 
 /***************************************************************************/
 // XPCNativeInterface
 
+XPCNativeInterface::~XPCNativeInterface()
+{
+    XPCJSRuntime::Get()->GetIID2NativeInterfaceMap()->Remove(this);
+}
+
 // static
-XPCNativeInterface*
+already_AddRefed<XPCNativeInterface>
 XPCNativeInterface::GetNewOrUsed(const nsIID* iid)
 {
-    AutoJSContext cx;
-    AutoMarkingNativeInterfacePtr iface(cx);
+    RefPtr<XPCNativeInterface> iface;
     XPCJSRuntime* rt = XPCJSRuntime::Get();
 
     IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
     if (!map)
         return nullptr;
 
     iface = map->Find(*iid);
 
     if (iface)
-        return iface;
+        return iface.forget();
 
     nsCOMPtr<nsIInterfaceInfo> info;
     XPTInterfaceInfoManager::GetSingleton()->GetInfoForIID(iid, getter_AddRefs(info));
     if (!info)
         return nullptr;
 
     iface = NewInstance(info);
     if (!iface)
         return nullptr;
 
     XPCNativeInterface* iface2 = map->Add(iface);
     if (!iface2) {
         NS_ERROR("failed to add our interface!");
-        DestroyInstance(iface);
         iface = nullptr;
     } else if (iface2 != iface) {
-        DestroyInstance(iface);
         iface = iface2;
     }
 
-    return iface;
+    return iface.forget();
 }
 
 // static
-XPCNativeInterface*
+already_AddRefed<XPCNativeInterface>
 XPCNativeInterface::GetNewOrUsed(nsIInterfaceInfo* info)
 {
-    AutoJSContext cx;
-    AutoMarkingNativeInterfacePtr iface(cx);
+    RefPtr<XPCNativeInterface> iface;
 
     const nsIID* iid;
     if (NS_FAILED(info->GetIIDShared(&iid)) || !iid)
         return nullptr;
 
     XPCJSRuntime* rt = XPCJSRuntime::Get();
 
     IID2NativeInterfaceMap* map = rt->GetIID2NativeInterfaceMap();
     if (!map)
         return nullptr;
 
     iface = map->Find(*iid);
 
     if (iface)
-        return iface;
+        return iface.forget();
 
     iface = NewInstance(info);
     if (!iface)
         return nullptr;
 
-    XPCNativeInterface* iface2 = map->Add(iface);
+    RefPtr<XPCNativeInterface> iface2 = map->Add(iface);
     if (!iface2) {
         NS_ERROR("failed to add our interface!");
-        DestroyInstance(iface);
         iface = nullptr;
     } else if (iface2 != iface) {
-        DestroyInstance(iface);
         iface = iface2;
     }
 
-    return iface;
+    return iface.forget();
 }
 
 // static
-XPCNativeInterface*
+already_AddRefed<XPCNativeInterface>
 XPCNativeInterface::GetNewOrUsed(const char* name)
 {
     nsCOMPtr<nsIInterfaceInfo> info;
     XPTInterfaceInfoManager::GetSingleton()->GetInfoForName(name, getter_AddRefs(info));
     return info ? GetNewOrUsed(info) : nullptr;
 }
 
 // static
-XPCNativeInterface*
+already_AddRefed<XPCNativeInterface>
 XPCNativeInterface::GetISupports()
 {
     // XXX We should optimize this to cache this common XPCNativeInterface.
     return GetNewOrUsed(&NS_GET_IID(nsISupports));
 }
 
 // static
-XPCNativeInterface*
+already_AddRefed<XPCNativeInterface>
 XPCNativeInterface::NewInstance(nsIInterfaceInfo* aInfo)
 {
     AutoJSContext cx;
     static const uint16_t MAX_LOCAL_MEMBER_COUNT = 16;
     XPCNativeMember local_members[MAX_LOCAL_MEMBER_COUNT];
-    XPCNativeInterface* obj = nullptr;
+    RefPtr<XPCNativeInterface> obj;
     XPCNativeMember* members = nullptr;
 
     int i;
     bool failed = false;
     uint16_t constCount;
     uint16_t methodCount;
     uint16_t totalCount;
     uint16_t realTotalCount = 0;
@@ -387,17 +386,17 @@ XPCNativeInterface::NewInstance(nsIInter
                 memcpy(obj->mMembers, members,
                        realTotalCount * sizeof(XPCNativeMember));
         }
     }
 
     if (members && members != local_members)
         delete [] members;
 
-    return obj;
+    return obj.forget();
 }
 
 // static
 void
 XPCNativeInterface::DestroyInstance(XPCNativeInterface* inst)
 {
     inst->~XPCNativeInterface();
     delete [] (char*) inst;
@@ -465,34 +464,34 @@ XPCNativeSetKey::Hash() const
 
 // static
 XPCNativeSet*
 XPCNativeSet::GetNewOrUsed(const nsIID* iid)
 {
     AutoJSContext cx;
     AutoMarkingNativeSetPtr set(cx);
 
-    AutoMarkingNativeInterfacePtr iface(cx);
-    iface = XPCNativeInterface::GetNewOrUsed(iid);
+    RefPtr<XPCNativeInterface> iface =
+        XPCNativeInterface::GetNewOrUsed(iid);
     if (!iface)
         return nullptr;
 
     XPCNativeSetKey key(nullptr, iface, 0);
 
     XPCJSRuntime* rt = XPCJSRuntime::Get();
     NativeSetMap* map = rt->GetNativeSetMap();
     if (!map)
         return nullptr;
 
     set = map->Find(&key);
 
     if (set)
         return set;
 
-    set = NewInstance({iface});
+    set = NewInstance({iface.forget()});
     if (!set)
         return nullptr;
 
     XPCNativeSet* set2 = map->Add(&key, set);
     if (!set2) {
         NS_ERROR("failed to add our set!");
         DestroyInstance(set);
         set = nullptr;
@@ -534,36 +533,35 @@ XPCNativeSet::GetNewOrUsed(nsIClassInfo*
         iidCount = 0;
     }
 
     MOZ_ASSERT((iidCount && iidArray) || !(iidCount || iidArray), "GetInterfaces returned bad array");
 
     // !!! from here on we only exit through the 'out' label !!!
 
     if (iidCount) {
-        nsTArray<XPCNativeInterface*> interfaceArray(iidCount);
-        AutoMarkingNativeInterfacePtrArrayPtr arrayMarker(cx, interfaceArray);
+        nsTArray<RefPtr<XPCNativeInterface>> interfaceArray(iidCount);
         nsIID** currentIID = iidArray;
 
         for (uint32_t i = 0; i < iidCount; i++) {
             nsIID* iid = *(currentIID++);
             if (!iid) {
                 NS_ERROR("Null found in classinfo interface list");
                 continue;
             }
 
-            XPCNativeInterface* iface =
+            RefPtr<XPCNativeInterface> iface =
                 XPCNativeInterface::GetNewOrUsed(iid);
 
             if (!iface) {
                 // XXX warn here
                 continue;
             }
 
-            interfaceArray.AppendElement(iface);
+            interfaceArray.AppendElement(iface.forget());
         }
 
         if (interfaceArray.Length() > 0) {
             set = NewInstance(Move(interfaceArray));
             if (set) {
                 NativeSetMap* map2 = rt->GetNativeSetMap();
                 if (!map2)
                     goto out;
@@ -698,27 +696,27 @@ XPCNativeSet::GetNewOrUsed(XPCNativeSet*
 
     // We've got the union set. Hand it back to the caller.
     MOZ_ASSERT(currentSet->mInterfaceCount == uniqueCount);
     return currentSet;
 }
 
 // static
 XPCNativeSet*
-XPCNativeSet::NewInstance(nsTArray<XPCNativeInterface*>&& array)
+XPCNativeSet::NewInstance(nsTArray<RefPtr<XPCNativeInterface>>&& array)
 {
     if (array.Length() == 0)
         return nullptr;
 
     // We impose the invariant:
     // "All sets have exactly one nsISupports interface and it comes first."
     // This is the place where we impose that rule - even if given inputs
     // that don't exactly follow the rule.
 
-    XPCNativeInterface* isup = XPCNativeInterface::GetISupports();
+    RefPtr<XPCNativeInterface> isup = XPCNativeInterface::GetISupports();
     uint16_t slots = array.Length() + 1;
 
     for (auto key = array.begin(); key != array.end(); key++) {
         if (*key == isup)
             slots--;
     }
 
     // Use placement new to create an object with the right amount of space
@@ -728,24 +726,24 @@ XPCNativeSet::NewInstance(nsTArray<XPCNa
         size += (slots - 1) * sizeof(XPCNativeInterface*);
     void* place = new char[size];
     XPCNativeSet* obj = new(place) XPCNativeSet();
 
     // Stick the nsISupports in front and skip additional nsISupport(s)
     XPCNativeInterface** outp = (XPCNativeInterface**) &obj->mInterfaces;
     uint16_t memberCount = 1;   // for the one member in nsISupports
 
-    *(outp++) = isup;
+    NS_ADDREF(*(outp++) = isup);
 
     for (auto key = array.begin(); key != array.end(); key++) {
-        XPCNativeInterface* cur = *key;
+        RefPtr<XPCNativeInterface> cur = key->forget();
         if (isup == cur)
             continue;
-        *(outp++) = cur;
         memberCount += cur->GetMemberCount();
+        *(outp++) = cur.forget().take();
     }
     obj->mMemberCount = memberCount;
     obj->mInterfaceCount = slots;
 
     return obj;
 }
 
 // static
@@ -770,20 +768,17 @@ XPCNativeSet::NewInstanceMutate(XPCNativ
 
     obj->mMemberCount = otherSet->GetMemberCount() +
         newInterface->GetMemberCount();
     obj->mInterfaceCount = otherSet->mInterfaceCount + 1;
 
     XPCNativeInterface** src = otherSet->mInterfaces;
     XPCNativeInterface** dest = obj->mInterfaces;
     for (uint16_t i = 0; i < obj->mInterfaceCount; i++) {
-        if (i == position)
-            *dest++ = newInterface;
-        else
-            *dest++ = *src++;
+        NS_ADDREF(*dest++ = (i == position) ? newInterface : *src++);
     }
 
     return obj;
 }
 
 // static
 void
 XPCNativeSet::DestroyInstance(XPCNativeSet* inst)
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -217,27 +217,28 @@ XPC_WN_DoubleWrappedGetter(JSContext* cx
  * We *never* set toString or toSource as JS_ENUMERATE.
  */
 
 static bool
 DefinePropertyIfFound(XPCCallContext& ccx,
                       HandleObject obj,
                       HandleId idArg,
                       XPCNativeSet* set,
-                      XPCNativeInterface* iface,
+                      XPCNativeInterface* ifaceArg,
                       XPCNativeMember* member,
                       XPCWrappedNativeScope* scope,
                       bool reflectToStringAndToSource,
                       XPCWrappedNative* wrapperToReflectInterfaceNames,
                       XPCWrappedNative* wrapperToReflectDoubleWrap,
                       XPCNativeScriptableInfo* scriptableInfo,
                       unsigned propFlags,
                       bool* resolved)
 {
     RootedId id(ccx, idArg);
+    RefPtr<XPCNativeInterface> iface = ifaceArg;
     XPCJSRuntime* rt = ccx.GetRuntime();
     bool found;
     const char* name;
 
     propFlags |= JSPROP_RESOLVING;
 
     if (set) {
         if (iface)
@@ -300,17 +301,17 @@ DefinePropertyIfFound(XPCCallContext& cc
         }
         // This *might* be a tearoff name that is not yet part of our
         // set. Let's lookup the name and see if it is the name of an
         // interface. Then we'll see if the object actually *does* this
         // interface and add a tearoff as necessary.
 
         if (wrapperToReflectInterfaceNames) {
             JSAutoByteString name;
-            AutoMarkingNativeInterfacePtr iface2(ccx);
+            RefPtr<XPCNativeInterface> iface2;
             XPCWrappedNativeTearOff* to;
             RootedObject jso(ccx);
             nsresult rv = NS_OK;
 
             if (JSID_IS_STRING(id) &&
                 name.encodeLatin1(ccx, JSID_TO_STRING(id)) &&
                 (iface2 = XPCNativeInterface::GetNewOrUsed(name.ptr()), iface2) &&
                 nullptr != (to = wrapperToReflectInterfaceNames->
@@ -829,17 +830,17 @@ XPC_WN_Helper_Resolve(JSContext* cx, Han
     } else if (wrapper->HasMutatedSet()) {
         // We are here if scriptable did not resolve this property and
         // it *might* be in the instance set but not the proto set.
 
         XPCNativeSet* set = wrapper->GetSet();
         XPCNativeSet* protoSet = wrapper->HasProto() ?
                                     wrapper->GetProto()->GetSet() : nullptr;
         XPCNativeMember* member;
-        XPCNativeInterface* iface;
+        RefPtr<XPCNativeInterface> iface;
         bool IsLocal;
 
         if (set->FindMember(id, &member, &iface, protoSet, &IsLocal) &&
             IsLocal) {
             XPCWrappedNative* oldResolvingWrapper;
 
             XPCNativeScriptableFlags siFlags(0);
             if (si)
@@ -1127,17 +1128,17 @@ XPC_WN_CallMethod(JSContext* cx, unsigne
         return false;
 
     obj = FixUpThisIfBroken(obj, funobj);
     XPCCallContext ccx(cx, obj, funobj, JSID_VOIDHANDLE, args.length(),
                        args.array(), vp);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
 
-    XPCNativeInterface* iface;
+    RefPtr<XPCNativeInterface> iface;
     XPCNativeMember*    member;
 
     if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member))
         return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
     ccx.SetCallInfo(iface, member, false);
     return XPCWrappedNative::CallMethod(ccx);
 }
 
@@ -1153,17 +1154,17 @@ XPC_WN_GetterSetter(JSContext* cx, unsig
         return false;
 
     obj = FixUpThisIfBroken(obj, funobj);
     XPCCallContext ccx(cx, obj, funobj, JSID_VOIDHANDLE, args.length(),
                        args.array(), vp);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
 
-    XPCNativeInterface* iface;
+    RefPtr<XPCNativeInterface> iface;
     XPCNativeMember*    member;
 
     if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member))
         return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx);
 
     if (args.length() != 0 && member->IsWritableAttribute()) {
         ccx.SetCallInfo(iface, member, true);
         bool retval = XPCWrappedNative::SetAttribute(ccx);
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -731,18 +731,18 @@ nsXPConnect::GetWrappedNativeOfNativeObj
     *_retval = nullptr;
 
     RootedObject aScope(aJSContext, aScopeArg);
 
     XPCWrappedNativeScope* scope = ObjectScope(aScope);
     if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
-    AutoMarkingNativeInterfacePtr iface(aJSContext);
-    iface = XPCNativeInterface::GetNewOrUsed(&aIID);
+    RefPtr<XPCNativeInterface> iface =
+        XPCNativeInterface::GetNewOrUsed(&aIID);
     if (!iface)
         return NS_ERROR_FAILURE;
 
     XPCWrappedNative* wrapper;
 
     nsresult rv = XPCWrappedNative::GetUsedOnly(aCOMObj, scope, iface, &wrapper);
     if (NS_FAILED(rv))
         return NS_ERROR_FAILURE;
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -780,17 +780,17 @@ private:
     XPCCallContext*                 mPrevCallContext;
 
     XPCWrappedNative*               mWrapper;
     XPCWrappedNativeTearOff*        mTearOff;
 
     XPCNativeScriptableInfo*        mScriptableInfo;
 
     XPCNativeSet*                   mSet;
-    XPCNativeInterface*             mInterface;
+    RefPtr<XPCNativeInterface>      mInterface;
     XPCNativeMember*                mMember;
 
     JS::RootedId                    mName;
     bool                            mStaticMemberIsLocal;
 
     unsigned                        mArgc;
     JS::Value*                      mArgv;
     JS::Value*                      mRetVal;
@@ -1113,18 +1113,18 @@ private:
 // constant.
 
 // Tight. No virtual methods. Can be bitwise copied (until any resolution done).
 
 class XPCNativeMember final
 {
 public:
     static bool GetCallInfo(JSObject* funobj,
-                            XPCNativeInterface** pInterface,
-                            XPCNativeMember**    pMember);
+                            RefPtr<XPCNativeInterface>* pInterface,
+                            XPCNativeMember** pMember);
 
     jsid   GetName() const {return mName;}
 
     uint16_t GetIndex() const {return mIndex;}
 
     bool GetConstantValue(XPCCallContext& ccx, XPCNativeInterface* iface,
                           JS::Value* pval)
         {MOZ_ASSERT(IsConstant(),
@@ -1209,20 +1209,23 @@ private:
 // XPCNativeInterface represents a single idl declared interface. This is
 // primarily the set of XPCNativeMembers.
 
 // Tight. No virtual methods.
 
 class XPCNativeInterface final
 {
   public:
-    static XPCNativeInterface* GetNewOrUsed(const nsIID* iid);
-    static XPCNativeInterface* GetNewOrUsed(nsIInterfaceInfo* info);
-    static XPCNativeInterface* GetNewOrUsed(const char* name);
-    static XPCNativeInterface* GetISupports();
+    NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(XPCNativeInterface,
+                                            DestroyInstance(this))
+
+    static already_AddRefed<XPCNativeInterface> GetNewOrUsed(const nsIID* iid);
+    static already_AddRefed<XPCNativeInterface> GetNewOrUsed(nsIInterfaceInfo* info);
+    static already_AddRefed<XPCNativeInterface> GetNewOrUsed(const char* name);
+    static already_AddRefed<XPCNativeInterface> GetISupports();
 
     inline nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo.get();}
     inline jsid              GetName()          const {return mName;}
 
     inline const nsIID* GetIID() const;
     inline const char*  GetNameString() const;
     inline XPCNativeMember* FindMember(jsid name) const;
 
@@ -1234,59 +1237,42 @@ class XPCNativeInterface final
     }
     XPCNativeMember* GetMemberAt(uint16_t i) {
         MOZ_ASSERT(i < mMemberCount, "bad index");
         return &mMembers[i];
     }
 
     void DebugDump(int16_t depth);
 
-    void Mark() {
-        mMarked = 1;
-    }
-
-    void Unmark() {
-        mMarked = 0;
-    }
-
-    bool IsMarked() const {
-        return mMarked != 0;
-    }
-
-    // NOP. This is just here to make the AutoMarkingPtr code compile.
-    inline void TraceJS(JSTracer* trc) {}
-    inline void AutoTrace(JSTracer* trc) {}
-
-    static void DestroyInstance(XPCNativeInterface* inst);
+    void Mark() {}
+    void Unmark() {}
+    bool IsMarked() const { return false; }
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
   protected:
-    static XPCNativeInterface* NewInstance(nsIInterfaceInfo* aInfo);
+    static already_AddRefed<XPCNativeInterface> NewInstance(nsIInterfaceInfo* aInfo);
 
     XPCNativeInterface() = delete;
     XPCNativeInterface(nsIInterfaceInfo* aInfo, jsid aName)
-      : mInfo(aInfo), mName(aName), mMemberCount(0), mMarked(0)
-    {
-        MOZ_COUNT_CTOR(XPCNativeInterface);
-    }
-    ~XPCNativeInterface() {
-        MOZ_COUNT_DTOR(XPCNativeInterface);
-    }
+      : mInfo(aInfo), mName(aName), mMemberCount(0)
+    {}
+    ~XPCNativeInterface();
 
     void* operator new(size_t, void* p) CPP_THROW_NEW {return p;}
 
     XPCNativeInterface(const XPCNativeInterface& r) = delete;
     XPCNativeInterface& operator= (const XPCNativeInterface& r) = delete;
 
+    static void DestroyInstance(XPCNativeInterface* inst);
+
 private:
     nsCOMPtr<nsIInterfaceInfo> mInfo;
     jsid                       mName;
-    uint16_t                   mMemberCount : 15;
-    uint16_t                   mMarked : 1;
+    uint16_t                   mMemberCount;
     XPCNativeMember            mMembers[1]; // always last - object sized for array
 };
 
 /***************************************************************************/
 // XPCNativeSetKey is used to key a XPCNativeSet in a NativeSetMap.
 
 class XPCNativeSetKey final
 {
@@ -1332,26 +1318,26 @@ class XPCNativeSet final
     // ordering might differ from |firstSet|.
     static XPCNativeSet* GetNewOrUsed(XPCNativeSet* firstSet,
                                       XPCNativeSet* secondSet,
                                       bool preserveFirstSetOrder);
 
     static void ClearCacheEntryForClassInfo(nsIClassInfo* classInfo);
 
     inline bool FindMember(jsid name, XPCNativeMember** pMember,
-                             uint16_t* pInterfaceIndex) const;
+                           uint16_t* pInterfaceIndex) const;
 
     inline bool FindMember(jsid name, XPCNativeMember** pMember,
-                             XPCNativeInterface** pInterface) const;
+                           RefPtr<XPCNativeInterface>* pInterface) const;
 
     inline bool FindMember(jsid name,
-                             XPCNativeMember** pMember,
-                             XPCNativeInterface** pInterface,
-                             XPCNativeSet* protoSet,
-                             bool* pIsLocal) const;
+                           XPCNativeMember** pMember,
+                           RefPtr<XPCNativeInterface>* pInterface,
+                           XPCNativeSet* protoSet,
+                           bool* pIsLocal) const;
 
     inline bool HasInterface(XPCNativeInterface* aInterface) const;
     inline bool HasInterfaceWithAncestor(XPCNativeInterface* aInterface) const;
     inline bool HasInterfaceWithAncestor(const nsIID* iid) const;
 
     inline XPCNativeInterface* FindInterfaceWithIID(const nsIID& iid) const;
 
     inline XPCNativeInterface* FindNamedInterface(jsid name) const;
@@ -1397,35 +1383,40 @@ class XPCNativeSet final
 
     void DebugDump(int16_t depth);
 
     static void DestroyInstance(XPCNativeSet* inst);
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
   protected:
-    static XPCNativeSet* NewInstance(nsTArray<XPCNativeInterface*>&& array);
+    static XPCNativeSet* NewInstance(nsTArray<RefPtr<XPCNativeInterface>>&& array);
     static XPCNativeSet* NewInstanceMutate(XPCNativeSet*       otherSet,
                                            XPCNativeInterface* newInterface,
                                            uint16_t            position);
     XPCNativeSet()
       : mMemberCount(0), mInterfaceCount(0), mMarked(0)
     {
         MOZ_COUNT_CTOR(XPCNativeSet);
     }
     ~XPCNativeSet() {
+        for (int i = 0; i < mInterfaceCount; i++) {
+            NS_RELEASE(mInterfaces[i]);
+        }
         MOZ_COUNT_DTOR(XPCNativeSet);
     }
     void* operator new(size_t, void* p) CPP_THROW_NEW {return p;}
 
   private:
     uint16_t                mMemberCount;
     uint16_t                mInterfaceCount : 15;
     uint16_t                mMarked : 1;
-    XPCNativeInterface*     mInterfaces[1];  // always last - object sized for array
+    // Always last - object sized for array.
+    // These are strong references.
+    XPCNativeInterface*     mInterfaces[1];
 };
 
 /***************************************************************************/
 // XPCNativeScriptableFlags is a wrapper class that holds the flags returned
 // from calls to nsIXPCScriptable::GetScriptableFlags(). It has convenience
 // methods to check for particular bitflags.
 
 class XPCNativeScriptableFlags final
@@ -2873,55 +2864,21 @@ class TypedAutoMarkingPtr : public AutoM
         if (mPtr)
             mPtr->Mark();
     }
 
   private:
     T* mPtr;
 };
 
-typedef TypedAutoMarkingPtr<XPCNativeInterface> AutoMarkingNativeInterfacePtr;
 typedef TypedAutoMarkingPtr<XPCNativeSet> AutoMarkingNativeSetPtr;
 typedef TypedAutoMarkingPtr<XPCWrappedNative> AutoMarkingWrappedNativePtr;
 typedef TypedAutoMarkingPtr<XPCWrappedNativeTearOff> AutoMarkingWrappedNativeTearOffPtr;
 typedef TypedAutoMarkingPtr<XPCWrappedNativeProto> AutoMarkingWrappedNativeProtoPtr;
 
-template<class T>
-class ArrayAutoMarkingPtr : public AutoMarkingPtr
-{
-  public:
-    ArrayAutoMarkingPtr(JSContext* cx, nsTArray<T*>& ptr)
-      : AutoMarkingPtr(cx), mPtr(ptr)
-    {}
-
-  protected:
-    virtual void TraceJS(JSTracer* trc)
-    {
-        for (uint32_t i = 0; i < mPtr.Length(); i++) {
-            if (mPtr[i]) {
-                mPtr[i]->TraceJS(trc);
-                mPtr[i]->AutoTrace(trc);
-            }
-        }
-    }
-
-    virtual void MarkAfterJSFinalize()
-    {
-        for (uint32_t i = 0; i < mPtr.Length(); i++) {
-            if (mPtr[i])
-                mPtr[i]->Mark();
-        }
-    }
-
-  private:
-    nsTArray<T*>& mPtr;
-};
-
-typedef ArrayAutoMarkingPtr<XPCNativeInterface> AutoMarkingNativeInterfacePtrArrayPtr;
-
 /***************************************************************************/
 namespace xpc {
 // Allocates a string that grants all access ("AllAccess")
 char*
 CloneAllAccess();
 
 // Returns access if wideName is in list
 char*