Bug 1526382 - Part 2: Make nsIClassInfo use Array<nsIIDRef> for 'interfaces', r=mccr8
authorNika Layzell <nika@thelayzells.com>
Wed, 13 Feb 2019 21:42:08 +0000
changeset 458963 b4258349e68b
parent 458962 9b2bfb8871c9
child 458964 bf288072dd8a
push id35552
push usershindli@mozilla.com
push dateThu, 14 Feb 2019 04:39:44 +0000
treeherdermozilla-central@c6829642e2d0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1526382
milestone67.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 1526382 - Part 2: Make nsIClassInfo use Array<nsIIDRef> for 'interfaces', r=mccr8 This is a follow-up to the previous part, which actually changes one of these callers to use Array<nsIIDRef> instead of [array] nsIIDPtr. From doing this patch, it seems like we should consider changing the type `nsIIDRef` to instead simply be `nsIID`, and treat it more like the `AString` types from the POV of XPIDL. `nsIIDPtr` would then continue to exist for backwards compatibility, but we can probably remove almost all current consumers over time. Depends on D19175 Differential Revision: https://phabricator.services.mozilla.com/D19176
dom/file/uri/BlobURL.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCRuntimeService.cpp
js/xpconnect/src/XPCWrappedNativeInfo.cpp
js/xpconnect/tests/unit/component-blob.js
js/xpconnect/tests/unit/component-file.js
js/xpconnect/tests/unit/component_import.js
js/xpconnect/tests/unit/test_import.js
modules/libjar/nsJARURI.cpp
netwerk/base/nsSimpleURI.cpp
netwerk/base/nsSocketTransport2.cpp
netwerk/base/nsStandardURL.cpp
security/manager/ssl/TransportSecurityInfo.cpp
security/manager/ssl/nsNSSCertificate.cpp
storage/mozStorageAsyncStatement.cpp
storage/mozStorageStatement.cpp
toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
xpcom/base/nsClassInfoImpl.cpp
xpcom/base/nsIClassInfoImpl.h
xpcom/base/nsISupportsImpl.h
xpcom/components/nsIClassInfo.idl
xpcom/threads/nsThread.cpp
--- a/dom/file/uri/BlobURL.cpp
+++ b/dom/file/uri/BlobURL.cpp
@@ -161,19 +161,18 @@ BlobURL::Mutate(nsIURIMutator** aMutator
     return rv;
   }
   mutator.forget(aMutator);
   return NS_OK;
 }
 
 // nsIClassInfo methods:
 NS_IMETHODIMP
-BlobURL::GetInterfaces(uint32_t* count, nsIID*** array) {
-  *count = 0;
-  *array = nullptr;
+BlobURL::GetInterfaces(nsTArray<nsIID>& array) {
+  array.Clear();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BlobURL::GetScriptableHelper(nsIXPCScriptable** _retval) {
   *_retval = nullptr;
   return NS_OK;
 }
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -113,23 +113,19 @@ class nsXPCComponents_Interfaces final :
  public:
   nsXPCComponents_Interfaces();
 
  private:
   virtual ~nsXPCComponents_Interfaces();
 };
 
 NS_IMETHODIMP
-nsXPCComponents_Interfaces::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
-  *aCount = 2;
-  nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
-  *aArray = array;
-
-  array[0] = NS_GET_IID(nsIXPCComponents_Interfaces).Clone();
-  array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
+nsXPCComponents_Interfaces::GetInterfaces(nsTArray<nsIID>& aArray) {
+  aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Interfaces),
+                           NS_GET_IID(nsIXPCScriptable)};
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Interfaces::GetScriptableHelper(nsIXPCScriptable** retval) {
   *retval = nullptr;
   return NS_OK;
 }
@@ -270,23 +266,19 @@ class nsXPCComponents_Classes final : pu
   nsXPCComponents_Classes();
 
  private:
   virtual ~nsXPCComponents_Classes();
 };
 
 /***************************************************************************/
 NS_IMETHODIMP
-nsXPCComponents_Classes::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
-  *aCount = 2;
-  nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
-  *aArray = array;
-
-  array[0] = NS_GET_IID(nsIXPCComponents_Classes).Clone();
-  array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
+nsXPCComponents_Classes::GetInterfaces(nsTArray<nsIID>& aArray) {
+  aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Classes),
+                           NS_GET_IID(nsIXPCScriptable)};
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Classes::GetScriptableHelper(nsIXPCScriptable** retval) {
   *retval = nullptr;
   return NS_OK;
 }
@@ -427,23 +419,19 @@ class nsXPCComponents_Results final : pu
   nsXPCComponents_Results();
 
  private:
   virtual ~nsXPCComponents_Results();
 };
 
 /***************************************************************************/
 NS_IMETHODIMP
-nsXPCComponents_Results::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
-  *aCount = 2;
-  nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
-  *aArray = array;
-
-  array[0] = NS_GET_IID(nsIXPCComponents_Results).Clone();
-  array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
+nsXPCComponents_Results::GetInterfaces(nsTArray<nsIID>& aArray) {
+  aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Results),
+                           NS_GET_IID(nsIXPCScriptable)};
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Results::GetScriptableHelper(nsIXPCScriptable** retval) {
   *retval = nullptr;
   return NS_OK;
 }
@@ -572,23 +560,19 @@ class nsXPCComponents_ID final : public 
   virtual ~nsXPCComponents_ID();
   static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
                                   JSContext* cx, HandleObject obj,
                                   const CallArgs& args, bool* _retval);
 };
 
 /***************************************************************************/
 NS_IMETHODIMP
-nsXPCComponents_ID::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
-  *aCount = 2;
-  nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
-  *aArray = array;
-
-  array[0] = NS_GET_IID(nsIXPCComponents_ID).Clone();
-  array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
+nsXPCComponents_ID::GetInterfaces(nsTArray<nsIID>& aArray) {
+  aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_ID),
+                           NS_GET_IID(nsIXPCScriptable)};
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_ID::GetScriptableHelper(nsIXPCScriptable** retval) {
   *retval = nullptr;
   return NS_OK;
 }
@@ -727,23 +711,19 @@ class nsXPCComponents_Exception final : 
   virtual ~nsXPCComponents_Exception();
   static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
                                   JSContext* cx, HandleObject obj,
                                   const CallArgs& args, bool* _retval);
 };
 
 /***************************************************************************/
 NS_IMETHODIMP
-nsXPCComponents_Exception::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
-  *aCount = 2;
-  nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
-  *aArray = array;
-
-  array[0] = NS_GET_IID(nsIXPCComponents_Exception).Clone();
-  array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
+nsXPCComponents_Exception::GetInterfaces(nsTArray<nsIID>& aArray) {
+  aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Exception),
+                           NS_GET_IID(nsIXPCScriptable)};
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Exception::GetScriptableHelper(nsIXPCScriptable** retval) {
   *retval = nullptr;
   return NS_OK;
 }
@@ -1022,23 +1002,19 @@ class nsXPCComponents_Constructor final 
   static bool InnerConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
   static nsresult CallOrConstruct(nsIXPConnectWrappedNative* wrapper,
                                   JSContext* cx, HandleObject obj,
                                   const CallArgs& args, bool* _retval);
 };
 
 /***************************************************************************/
 NS_IMETHODIMP
-nsXPCComponents_Constructor::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
-  *aCount = 2;
-  nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
-  *aArray = array;
-
-  array[0] = NS_GET_IID(nsIXPCComponents_Constructor).Clone();
-  array[1] = NS_GET_IID(nsIXPCScriptable).Clone();
+nsXPCComponents_Constructor::GetInterfaces(nsTArray<nsIID>& aArray) {
+  aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCComponents_Constructor),
+                           NS_GET_IID(nsIXPCScriptable)};
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Constructor::GetScriptableHelper(nsIXPCScriptable** retval) {
   *retval = nullptr;
   return NS_OK;
 }
--- a/js/xpconnect/src/XPCRuntimeService.cpp
+++ b/js/xpconnect/src/XPCRuntimeService.cpp
@@ -66,23 +66,19 @@ BackstagePass::NewEnumerate(nsIXPConnect
   JS::RootedObject obj(cx, objArg);
   *_retval = WebIDLGlobalNameHash::NewEnumerateSystemGlobal(cx, obj, properties,
                                                             enumerableOnly);
   return *_retval ? NS_OK : NS_ERROR_FAILURE;
 }
 
 /***************************************************************************/
 NS_IMETHODIMP
-BackstagePass::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
-  *aCount = 2;
-  nsIID** array = static_cast<nsIID**>(moz_xmalloc(2 * sizeof(nsIID*)));
-  *aArray = array;
-
-  array[0] = NS_GET_IID(nsIXPCScriptable).Clone();
-  array[1] = NS_GET_IID(nsIScriptObjectPrincipal).Clone();
+BackstagePass::GetInterfaces(nsTArray<nsIID>& aArray) {
+  aArray = nsTArray<nsIID>{NS_GET_IID(nsIXPCScriptable),
+                           NS_GET_IID(nsIScriptObjectPrincipal)};
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BackstagePass::GetScriptableHelper(nsIXPCScriptable** retval) {
   nsCOMPtr<nsIXPCScriptable> scriptable = this;
   scriptable.forget(retval);
   return NS_OK;
--- a/js/xpconnect/src/XPCWrappedNativeInfo.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeInfo.cpp
@@ -508,96 +508,70 @@ already_AddRefed<XPCNativeSet> XPCNative
   }
 
   RefPtr<XPCNativeSet> set = map->Find(classInfo);
 
   if (set) {
     return set.forget();
   }
 
-  nsIID** iidArray = nullptr;
-  uint32_t iidCount = 0;
-
-  if (NS_FAILED(classInfo->GetInterfaces(&iidCount, &iidArray))) {
+  AutoTArray<nsIID, 4> iids;
+  if (NS_FAILED(classInfo->GetInterfaces(iids))) {
     // Note: I'm making it OK for this call to fail so that one can add
     // nsIClassInfo to classes implemented in script without requiring this
     // method to be implemented.
 
     // Make sure these are set correctly...
-    iidArray = nullptr;
-    iidCount = 0;
+    iids.Clear();
   }
 
-  MOZ_ASSERT((iidCount && iidArray) || !(iidCount || iidArray),
-             "GetInterfaces returned bad array");
-
-  // !!! from here on we only exit through the 'out' label !!!
-
-  if (iidCount) {
-    nsTArray<RefPtr<XPCNativeInterface>> interfaceArray(iidCount);
-    nsIID** currentIID = iidArray;
+  // Try to look up each IID's XPCNativeInterface object.
+  nsTArray<RefPtr<XPCNativeInterface>> interfaces(iids.Length());
+  for (auto& iid : iids) {
+    RefPtr<XPCNativeInterface> iface = XPCNativeInterface::GetNewOrUsed(&iid);
+    if (iface) {
+      interfaces.AppendElement(iface.forget());
+    }
+  }
 
-    for (uint32_t i = 0; i < iidCount; i++) {
-      nsIID* iid = *(currentIID++);
-      if (!iid) {
-        NS_ERROR("Null found in classinfo interface list");
-        continue;
-      }
-
-      RefPtr<XPCNativeInterface> iface = XPCNativeInterface::GetNewOrUsed(iid);
-
-      if (!iface) {
-        // XXX warn here
-        continue;
+  // Build a set from the interfaces specified here.
+  if (interfaces.Length() > 0) {
+    set = NewInstance(std::move(interfaces));
+    if (set) {
+      NativeSetMap* map2 = xpcrt->GetNativeSetMap();
+      if (!map2) {
+        return set.forget();
       }
 
-      interfaceArray.AppendElement(iface.forget());
-    }
-
-    if (interfaceArray.Length() > 0) {
-      set = NewInstance(std::move(interfaceArray));
-      if (set) {
-        NativeSetMap* map2 = xpcrt->GetNativeSetMap();
-        if (!map2) {
-          goto out;
-        }
-
-        XPCNativeSetKey key(set);
+      XPCNativeSetKey key(set);
+      XPCNativeSet* set2 = map2->Add(&key, set);
+      if (!set2) {
+        NS_ERROR("failed to add our set");
+        return nullptr;
+      }
 
-        XPCNativeSet* set2 = map2->Add(&key, set);
-        if (!set2) {
-          NS_ERROR("failed to add our set!");
-          set = nullptr;
-          goto out;
-        }
-        // It is okay to find an existing entry here because
-        // we did not look for one before we called Add().
-        if (set2 != set) {
-          set = set2;
-        }
+      // It is okay to find an existing entry here because
+      // we did not look for one before we called Add().
+      if (set2 != set) {
+        set = set2;
       }
-    } else
-      set = GetNewOrUsed(&NS_GET_IID(nsISupports));
-  } else
+    }
+  } else {
     set = GetNewOrUsed(&NS_GET_IID(nsISupports));
+  }
 
   if (set) {
 #ifdef DEBUG
     XPCNativeSet* set2 =
 #endif
         map->Add(classInfo, set);
     MOZ_ASSERT(set2, "failed to add our set!");
     MOZ_ASSERT(set2 == set, "hashtables inconsistent!");
   }
 
-out:
-  if (iidArray) {
-    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iidCount, iidArray);
-  }
-
   return set.forget();
 }
 
 // static
 void XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo) {
   XPCJSRuntime* xpcrt = nsXPConnect::GetRuntimeInstance();
   ClassInfo2NativeSetMap* map = xpcrt->GetClassInfo2NativeSetMap();
   if (map) {
--- a/js/xpconnect/tests/unit/component-blob.js
+++ b/js/xpconnect/tests/unit/component-blob.js
@@ -54,21 +54,17 @@ BlobComponent.prototype =
   // nsIClassInfo + information for XPCOM registration code in XPCOMUtils.jsm
   classDescription: "Blob in components scope code",
   classID: Components.ID("{06215993-a3c2-41e3-bdfd-0a3a2cc0b65c}"),
   contractID: "@mozilla.org/tests/component-blob;1",
 
   // nsIClassInfo
   flags: 0,
 
-  getInterfaces: function getInterfaces(aCount) {
-    var interfaces = [Ci.nsIClassInfo];
-    aCount.value = interfaces.length;
-    return interfaces;
-  },
+  interfaces: [Ci.nsIClassInfo],
 
   getScriptableHelper: function getScriptableHelper() {
     return null;
   },
 
   // nsISupports
   QueryInterface: ChromeUtils.generateQI([Ci.nsIClassInfo])
 };
--- a/js/xpconnect/tests/unit/component-file.js
+++ b/js/xpconnect/tests/unit/component-file.js
@@ -85,21 +85,17 @@ FileComponent.prototype =
   // nsIClassInfo + information for XPCOM registration code in XPCOMUtils.jsm
   classDescription: "File in components scope code",
   classID: Components.ID("{da332370-91d4-464f-a730-018e14769cab}"),
   contractID: "@mozilla.org/tests/component-file;1",
 
   // nsIClassInfo
   flags: 0,
 
-  getInterfaces: function getInterfaces(aCount) {
-    var interfaces = [Ci.nsIClassInfo];
-    aCount.value = interfaces.length;
-    return interfaces;
-  },
+  interfaces: [Ci.nsIClassInfo],
 
   getScriptableHelper: function getScriptableHelper() {
     return null;
   },
 
   // nsISupports
   QueryInterface: ChromeUtils.generateQI([Ci.nsIClassInfo])
 };
--- a/js/xpconnect/tests/unit/component_import.js
+++ b/js/xpconnect/tests/unit/component_import.js
@@ -12,27 +12,26 @@ FooComponent.prototype =
   // nsIClassInfo + information for XPCOM registration code in XPCOMUtils.jsm
   classDescription:  "Foo Component",
   classID:           Components.ID("{6b933fe6-6eba-4622-ac86-e4f654f1b474}"),
   contractID:       "@mozilla.org/tests/module-importer;1",
 
   // nsIClassInfo
   flags: 0,
 
-  getInterfaces: function getInterfaces(aCount) {
+  get interfaces() {
     var interfaces = [Ci.nsIClassInfo];
-    aCount.value = interfaces.length;
 
     // Guerilla test for line numbers hiding in this method
     var threw = true;
     try {
       thereIsNoSuchIdentifier;
       threw = false;
     } catch (ex) {
-      Assert.ok(ex.lineNumber == 27);
+      Assert.ok(ex.lineNumber == 26);
     }
     Assert.ok(threw);
 
     return interfaces;
   },
 
   getScriptableHelper: function getScriptableHelper() {
     return null;
@@ -55,21 +54,17 @@ BarComponent.prototype =
   // nsIClassInfo + information for XPCOM registration code in XPCOMUtils.jsm
   classDescription: "Module importer test 2",
   classID: Components.ID("{708a896a-b48d-4bff-906e-fc2fd134b296}"),
   contractID: "@mozilla.org/tests/module-importer;2",
 
   // nsIClassInfo
   flags: 0,
 
-  getInterfaces: function getInterfaces(aCount) {
-    var interfaces = [Ci.nsIClassInfo];
-    aCount.value = interfaces.length;
-    return interfaces;
-  },
+  interfaces: [Ci.nsIClassInfo],
 
   getScriptableHelper: function getScriptableHelper() {
     return null;
   },
 
   // nsISupports
   QueryInterface: ChromeUtils.generateQI([Ci.nsIClassInfo])
 };
--- a/js/xpconnect/tests/unit/test_import.js
+++ b/js/xpconnect/tests/unit/test_import.js
@@ -70,20 +70,20 @@ function run_test() {
   Assert.ok(foo.contractID == contractID + "1");
   // XXX the following check succeeds only if the test component wasn't
   //     already registered. Need to figure out a way to force registration
   //     (to manually force it, delete compreg.dat before running the test)
   // do_check_true(foo.wrappedJSObject.postRegisterCalled);
 
   // Call getInterfaces to test line numbers in JS components.  But as long as
   // we're doing that, why not test what it returns too?
-  // Kind of odd that this is not returning an array containing the
-  // number... Or for that matter not returning an array containing an object?
-  var interfaces = foo.getInterfaces({});
-  Assert.equal(interfaces, Ci.nsIClassInfo.number);
+  var interfaces = foo.interfaces;
+  Assert.ok(Array.isArray(interfaces));
+  Assert.equal(interfaces.length, 1);
+  Assert.ok(interfaces[0].equals(Ci.nsIClassInfo))
 
   // try to create another component which doesn't directly implement QI
   Assert.ok((contractID + "2") in Cc);
   var bar = Cc[contractID + "2"]
               .createInstance(Ci.nsIClassInfo);
   Assert.ok(Boolean(bar));
   Assert.ok(bar.contractID == contractID + "2");
 }
--- a/modules/libjar/nsJARURI.cpp
+++ b/modules/libjar/nsJARURI.cpp
@@ -131,19 +131,18 @@ nsJARURI::Write(nsIObjectOutputStream *a
   rv = aOutputStream->WriteStringZ(mCharsetHint.get());
   return rv;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIClassInfo methods:
 
 NS_IMETHODIMP
-nsJARURI::GetInterfaces(uint32_t *count, nsIID ***array) {
-  *count = 0;
-  *array = nullptr;
+nsJARURI::GetInterfaces(nsTArray<nsIID> &array) {
+  array.Clear();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARURI::GetScriptableHelper(nsIXPCScriptable **_retval) {
   *_retval = nullptr;
   return NS_OK;
 }
--- a/netwerk/base/nsSimpleURI.cpp
+++ b/netwerk/base/nsSimpleURI.cpp
@@ -602,19 +602,18 @@ nsSimpleURI::GetAsciiHost(nsACString &re
   return NS_OK;
 }
 
 //----------------------------------------------------------------------------
 // nsSimpleURI::nsIClassInfo
 //----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-nsSimpleURI::GetInterfaces(uint32_t *count, nsIID ***array) {
-  *count = 0;
-  *array = nullptr;
+nsSimpleURI::GetInterfaces(nsTArray<nsIID> &array) {
+  array.Clear();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSimpleURI::GetScriptableHelper(nsIXPCScriptable **_retval) {
   *_retval = nullptr;
   return NS_OK;
 }
--- a/netwerk/base/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -2939,18 +2939,18 @@ nsSocketTransport::GetInterface(const ns
   if (iid.Equals(NS_GET_IID(nsIDNSRecord))) {
     return mDNSRecord ? mDNSRecord->QueryInterface(iid, result)
                       : NS_ERROR_NO_INTERFACE;
   }
   return this->QueryInterface(iid, result);
 }
 
 NS_IMETHODIMP
-nsSocketTransport::GetInterfaces(uint32_t *count, nsIID ***array) {
-  return NS_CI_INTERFACE_GETTER_NAME(nsSocketTransport)(count, array);
+nsSocketTransport::GetInterfaces(nsTArray<nsIID>& array) {
+  return NS_CI_INTERFACE_GETTER_NAME(nsSocketTransport)(array);
 }
 
 NS_IMETHODIMP
 nsSocketTransport::GetScriptableHelper(nsIXPCScriptable **_retval) {
   *_retval = nullptr;
   return NS_OK;
 }
 
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -3442,19 +3442,18 @@ bool nsStandardURL::Deserialize(const UR
   return true;
 }
 
 //----------------------------------------------------------------------------
 // nsStandardURL::nsIClassInfo
 //----------------------------------------------------------------------------
 
 NS_IMETHODIMP
-nsStandardURL::GetInterfaces(uint32_t *count, nsIID ***array) {
-  *count = 0;
-  *array = nullptr;
+nsStandardURL::GetInterfaces(nsTArray<nsIID> &array) {
+  array.Clear();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::GetScriptableHelper(nsIXPCScriptable **_retval) {
   *_retval = nullptr;
   return NS_OK;
 }
--- a/security/manager/ssl/TransportSecurityInfo.cpp
+++ b/security/manager/ssl/TransportSecurityInfo.cpp
@@ -511,19 +511,18 @@ TransportSecurityInfo::Read(nsIObjectInp
     return rv;
   }
   mFailedCertChain = do_QueryInterface(failedCertChainSupports);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TransportSecurityInfo::GetInterfaces(uint32_t* count, nsIID*** array) {
-  *count = 0;
-  *array = nullptr;
+TransportSecurityInfo::GetInterfaces(nsTArray<nsIID>& array) {
+  array.Clear();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TransportSecurityInfo::GetScriptableHelper(nsIXPCScriptable** _retval) {
   *_retval = nullptr;
   return NS_OK;
 }
--- a/security/manager/ssl/nsNSSCertificate.cpp
+++ b/security/manager/ssl/nsNSSCertificate.cpp
@@ -1222,19 +1222,18 @@ nsNSSCertificate::Read(nsIObjectInputStr
   if (!InitFromDER(const_cast<char*>(str.get()), len)) {
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array) {
-  *count = 0;
-  *array = nullptr;
+nsNSSCertificate::GetInterfaces(nsTArray<nsIID>& array) {
+  array.Clear();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNSSCertificate::GetScriptableHelper(nsIXPCScriptable** _retval) {
   *_retval = nullptr;
   return NS_OK;
 }
--- a/storage/mozStorageAsyncStatement.cpp
+++ b/storage/mozStorageAsyncStatement.cpp
@@ -40,18 +40,18 @@ NS_IMPL_CI_INTERFACE_GETTER(AsyncStateme
 
 class AsyncStatementClassInfo : public nsIClassInfo {
  public:
   constexpr AsyncStatementClassInfo() {}
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD
-  GetInterfaces(uint32_t *_count, nsIID ***_array) override {
-    return NS_CI_INTERFACE_GETTER_NAME(AsyncStatement)(_count, _array);
+  GetInterfaces(nsTArray<nsIID> &_array) override {
+    return NS_CI_INTERFACE_GETTER_NAME(AsyncStatement)(_array);
   }
 
   NS_IMETHOD
   GetScriptableHelper(nsIXPCScriptable **_helper) override {
     static AsyncStatementJSHelper sJSHelper;
     *_helper = &sJSHelper;
     return NS_OK;
   }
--- a/storage/mozStorageStatement.cpp
+++ b/storage/mozStorageStatement.cpp
@@ -42,18 +42,18 @@ NS_IMPL_CI_INTERFACE_GETTER(Statement, m
 
 class StatementClassInfo : public nsIClassInfo {
  public:
   constexpr StatementClassInfo() {}
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD
-  GetInterfaces(uint32_t *_count, nsIID ***_array) override {
-    return NS_CI_INTERFACE_GETTER_NAME(Statement)(_count, _array);
+  GetInterfaces(nsTArray<nsIID> &_array) override {
+    return NS_CI_INTERFACE_GETTER_NAME(Statement)(_array);
   }
 
   NS_IMETHOD
   GetScriptableHelper(nsIXPCScriptable **_helper) override {
     static StatementJSHelper sJSHelper;
     *_helper = &sJSHelper;
     return NS_OK;
   }
--- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
+++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
@@ -3557,21 +3557,17 @@ function UpdatePrompt(aCallback) {
                      Array.prototype.slice.call(arguments));
     };
   });
 }
 
 UpdatePrompt.prototype = {
   flags: Ci.nsIClassInfo.SINGLETON,
   getScriptableHelper: () => null,
-  getInterfaces(aCount) {
-    let interfaces = [Ci.nsISupports, Ci.nsIUpdatePrompt];
-    aCount.value = interfaces.length;
-    return interfaces;
-  },
+  interfaces: [Ci.nsISupports, Ci.nsIUpdatePrompt],
   QueryInterface: ChromeUtils.generateQI([Ci.nsIClassInfo, Ci.nsIUpdatePrompt]),
 };
 
 /* Update check listener */
 const updateCheckListener = {
   onProgress: function UCL_onProgress(aRequest, aPosition, aTotalSize) {
   },
 
--- a/xpcom/base/nsClassInfoImpl.cpp
+++ b/xpcom/base/nsClassInfoImpl.cpp
@@ -11,18 +11,18 @@ NS_IMETHODIMP_(MozExternalRefCountType)
 GenericClassInfo::AddRef() { return 2; }
 
 NS_IMETHODIMP_(MozExternalRefCountType)
 GenericClassInfo::Release() { return 1; }
 
 NS_IMPL_QUERY_INTERFACE(GenericClassInfo, nsIClassInfo)
 
 NS_IMETHODIMP
-GenericClassInfo::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
-  return mData->getinterfaces(aCount, aArray);
+GenericClassInfo::GetInterfaces(nsTArray<nsIID>& aArray) {
+  return mData->getinterfaces(aArray);
 }
 
 NS_IMETHODIMP
 GenericClassInfo::GetScriptableHelper(nsIXPCScriptable** aHelper) {
   if (mData->getscriptablehelper) {
     return mData->getscriptablehelper(aHelper);
   }
   return NS_ERROR_NOT_IMPLEMENTED;
--- a/xpcom/base/nsIClassInfoImpl.h
+++ b/xpcom/base/nsIClassInfoImpl.h
@@ -84,18 +84,17 @@
  * as a singleton.
  */
 
 class GenericClassInfo : public nsIClassInfo {
  public:
   struct ClassInfoData {
     // This function pointer uses NS_CALLBACK_ because it's always set to an
     // NS_IMETHOD function, which uses __stdcall on Win32.
-    typedef NS_CALLBACK_(nsresult, GetInterfacesProc)(uint32_t* aCountP,
-                                                      nsIID*** aArray);
+    typedef NS_CALLBACK_(nsresult, GetInterfacesProc)(nsTArray<nsIID>& aArray);
     GetInterfacesProc getinterfaces;
 
     // This function pointer doesn't use NS_CALLBACK_ because it's always set to
     // a vanilla function.
     typedef nsresult (*GetScriptableHelperProc)(nsIXPCScriptable** aHelper);
     GetScriptableHelperProc getscriptablehelper;
 
     uint32_t flags;
@@ -108,18 +107,19 @@ class GenericClassInfo : public nsIClass
   explicit GenericClassInfo(const ClassInfoData* aData) : mData(aData) {}
 
  private:
   const ClassInfoData* mData;
 };
 
 #define NS_CLASSINFO_NAME(_class) g##_class##_classInfoGlobal
 #define NS_CI_INTERFACE_GETTER_NAME(_class) _class##_GetInterfacesHelper
-#define NS_DECL_CI_INTERFACE_GETTER(_class) \
-  extern NS_IMETHODIMP NS_CI_INTERFACE_GETTER_NAME(_class)(uint32_t*, nsIID***);
+#define NS_DECL_CI_INTERFACE_GETTER(_class)                                  \
+  extern NS_IMETHODIMP NS_CI_INTERFACE_GETTER_NAME(_class)(nsTArray<nsIID> & \
+                                                           array);
 
 #define NS_IMPL_CLASSINFO(_class, _getscriptablehelper, _flags, _cid)       \
   NS_DECL_CI_INTERFACE_GETTER(_class)                                       \
   static const GenericClassInfo::ClassInfoData k##_class##ClassInfoData = { \
       NS_CI_INTERFACE_GETTER_NAME(_class),                                  \
       _getscriptablehelper,                                                 \
       _flags | nsIClassInfo::SINGLETON_CLASSINFO,                           \
       _cid,                                                                 \
@@ -130,29 +130,27 @@ class GenericClassInfo : public nsIClass
 #define NS_IMPL_QUERY_CLASSINFO(_class)                                      \
   if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {                               \
     if (!NS_CLASSINFO_NAME(_class))                                          \
       NS_CLASSINFO_NAME(_class) = new (k##_class##ClassInfoDataPlace.addr()) \
           GenericClassInfo(&k##_class##ClassInfoData);                       \
     foundInterface = NS_CLASSINFO_NAME(_class);                              \
   } else
 
-#define NS_CLASSINFO_HELPER_BEGIN(_class, _c)                              \
-  NS_IMETHODIMP                                                            \
-  NS_CI_INTERFACE_GETTER_NAME(_class)(uint32_t * count, nsIID * **array) { \
-    *count = _c;                                                           \
-    *array = (nsIID**)moz_xmalloc(sizeof(nsIID*) * _c);                    \
-    uint32_t i = 0;
+#define NS_CLASSINFO_HELPER_BEGIN(_class, _c)                    \
+  NS_IMETHODIMP                                                  \
+  NS_CI_INTERFACE_GETTER_NAME(_class)(nsTArray<nsIID> & array) { \
+    array.Clear();                                               \
+    array.SetCapacity(_c);
 
 #define NS_CLASSINFO_HELPER_ENTRY(_interface) \
-  (*array)[i++] = NS_GET_IID(_interface).Clone();
+  array.AppendElement(NS_GET_IID(_interface));
 
-#define NS_CLASSINFO_HELPER_END                           \
-  MOZ_ASSERT(i == *count, "Incorrent number of entries"); \
-  return NS_OK;                                           \
+#define NS_CLASSINFO_HELPER_END \
+  return NS_OK;                 \
   }
 
 #define NS_IMPL_CI_INTERFACE_GETTER(aClass, ...)                       \
   static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0,                        \
                 "Need more arguments to NS_IMPL_CI_INTERFACE_GETTER"); \
   NS_CLASSINFO_HELPER_BEGIN(aClass, MOZ_ARG_COUNT(__VA_ARGS__))        \
   MOZ_FOR_EACH(NS_CLASSINFO_HELPER_ENTRY, (), (__VA_ARGS__))           \
   NS_CLASSINFO_HELPER_END
--- a/xpcom/base/nsISupportsImpl.h
+++ b/xpcom/base/nsISupportsImpl.h
@@ -1242,50 +1242,50 @@ class Runnable;
   nsISupports* foundInterface;
 
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
  * Macro to generate nsIClassInfo methods for classes which do not have
  * corresponding nsIFactory implementations.
  */
-#define NS_IMPL_THREADSAFE_CI(_class)                           \
-  NS_IMETHODIMP                                                 \
-  _class::GetInterfaces(uint32_t* _count, nsIID*** _array) {    \
-    return NS_CI_INTERFACE_GETTER_NAME(_class)(_count, _array); \
-  }                                                             \
-                                                                \
-  NS_IMETHODIMP                                                 \
-  _class::GetScriptableHelper(nsIXPCScriptable** _retval) {     \
-    *_retval = nullptr;                                         \
-    return NS_OK;                                               \
-  }                                                             \
-                                                                \
-  NS_IMETHODIMP                                                 \
-  _class::GetContractID(nsACString& _contractID) {              \
-    _contractID.SetIsVoid(true);                                \
-    return NS_OK;                                               \
-  }                                                             \
-                                                                \
-  NS_IMETHODIMP                                                 \
-  _class::GetClassDescription(nsACString& _classDescription) {  \
-    _classDescription.SetIsVoid(true);                          \
-    return NS_OK;                                               \
-  }                                                             \
-                                                                \
-  NS_IMETHODIMP                                                 \
-  _class::GetClassID(nsCID** _classID) {                        \
-    *_classID = nullptr;                                        \
-    return NS_OK;                                               \
-  }                                                             \
-                                                                \
-  NS_IMETHODIMP                                                 \
-  _class::GetFlags(uint32_t* _flags) {                          \
-    *_flags = nsIClassInfo::THREADSAFE;                         \
-    return NS_OK;                                               \
-  }                                                             \
-                                                                \
-  NS_IMETHODIMP                                                 \
-  _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) {           \
-    return NS_ERROR_NOT_AVAILABLE;                              \
+#define NS_IMPL_THREADSAFE_CI(_class)                          \
+  NS_IMETHODIMP                                                \
+  _class::GetInterfaces(nsTArray<nsIID>& _array) {             \
+    return NS_CI_INTERFACE_GETTER_NAME(_class)(_array);        \
+  }                                                            \
+                                                               \
+  NS_IMETHODIMP                                                \
+  _class::GetScriptableHelper(nsIXPCScriptable** _retval) {    \
+    *_retval = nullptr;                                        \
+    return NS_OK;                                              \
+  }                                                            \
+                                                               \
+  NS_IMETHODIMP                                                \
+  _class::GetContractID(nsACString& _contractID) {             \
+    _contractID.SetIsVoid(true);                               \
+    return NS_OK;                                              \
+  }                                                            \
+                                                               \
+  NS_IMETHODIMP                                                \
+  _class::GetClassDescription(nsACString& _classDescription) { \
+    _classDescription.SetIsVoid(true);                         \
+    return NS_OK;                                              \
+  }                                                            \
+                                                               \
+  NS_IMETHODIMP                                                \
+  _class::GetClassID(nsCID** _classID) {                       \
+    *_classID = nullptr;                                       \
+    return NS_OK;                                              \
+  }                                                            \
+                                                               \
+  NS_IMETHODIMP                                                \
+  _class::GetFlags(uint32_t* _flags) {                         \
+    *_flags = nsIClassInfo::THREADSAFE;                        \
+    return NS_OK;                                              \
+  }                                                            \
+                                                               \
+  NS_IMETHODIMP                                                \
+  _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) {          \
+    return NS_ERROR_NOT_AVAILABLE;                             \
   }
 
 #endif
--- a/xpcom/components/nsIClassInfo.idl
+++ b/xpcom/components/nsIClassInfo.idl
@@ -13,25 +13,21 @@ interface nsIXPCScriptable;
  * your class to implement nsIClassInfo, see nsIClassInfoImpl.h for
  * instructions--you most likely do not want to inherit from nsIClassInfo.
  */
 
 [scriptable, uuid(a60569d7-d401-4677-ba63-2aa5971af25d)]
 interface nsIClassInfo : nsISupports
 {
     /**
-     * Get an ordered list of the interface ids that instances of the class 
-     * promise to implement. Note that nsISupports is an implicit member 
-     * of any such list and need not be included. 
-     *
-     * Should set *count = 0 and *array = null and return NS_OK if getting the 
-     * list is not supported.
+     * Returns a list of the interfaces which instances of this class promise
+     * to implement. Note that nsISupports is an implicit member of any such
+     * list, and need not be included.
      */
-    void getInterfaces(out uint32_t count, 
-                       [array, size_is(count), retval] out nsIIDPtr array);
+    readonly attribute Array<nsIIDRef> interfaces;
 
     /**
      * Return an object to assist XPConnect in supplying JavaScript-specific
      * behavior to callers of the instance object, or null if not needed.
      */
     nsIXPCScriptable getScriptableHelper();
 
     /**
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -135,18 +135,18 @@ class nsThreadClassInfo : public nsIClas
 
 NS_IMETHODIMP_(MozExternalRefCountType)
 nsThreadClassInfo::AddRef() { return 2; }
 NS_IMETHODIMP_(MozExternalRefCountType)
 nsThreadClassInfo::Release() { return 1; }
 NS_IMPL_QUERY_INTERFACE(nsThreadClassInfo, nsIClassInfo)
 
 NS_IMETHODIMP
-nsThreadClassInfo::GetInterfaces(uint32_t* aCount, nsIID*** aArray) {
-  return NS_CI_INTERFACE_GETTER_NAME(nsThread)(aCount, aArray);
+nsThreadClassInfo::GetInterfaces(nsTArray<nsIID>& aArray) {
+  return NS_CI_INTERFACE_GETTER_NAME(nsThread)(aArray);
 }
 
 NS_IMETHODIMP
 nsThreadClassInfo::GetScriptableHelper(nsIXPCScriptable** aResult) {
   *aResult = nullptr;
   return NS_OK;
 }