Bug 1540301, part 5 - Replace instances of nsXPCWrappedJSClass with nsXPTInterfaceInfo. r=bzbarsky
authorAndrew McCreight <continuation@gmail.com>
Sat, 06 Apr 2019 12:57:02 +0000
changeset 468276 66d2447c66fa4f56a77beaa7d505898421f6f1c7
parent 468275 7f52f402ed0bb476fbe12823dfd33217eca32390
child 468277 57c5d5e19c71138889753f5e96c9e198f814cc90
push id35826
push usernerli@mozilla.com
push dateSat, 06 Apr 2019 21:48:00 +0000
treeherdermozilla-central@dc53fe5c9ced [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs1540301
milestone68.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 1540301, part 5 - Replace instances of nsXPCWrappedJSClass with nsXPTInterfaceInfo. r=bzbarsky nsXPCWrappedJSClass now only adds indirections and dynamic allocations, so eliminate it. The class is kept around as a collection of static helper functions to avoid needing to move around all of this code and messing with history. In total, these patches save around 2kb of dynamic allocations per process. The major parts of this patch are: * Dropping indirection for accessing things on nsXPTInterfaceInfo and renaming things from class to info. * Removing the stuff related to instances of nsXPCWrappedJSClass existing (ctor, dtor, field, ISupports implementation, getter methods). * Removing IID2WrappedJSClassMap, because we only need the map from IIDs to info. I dropped the null check in TraverseNative because mInfo is never cleared, while mClass was. I dropped the forward declaration of nsXPCWrappedJSClass because no instances of that class exist, so no function will take or return a pointer to one. Differential Revision: https://phabricator.services.mozilla.com/D26218
js/xpconnect/src/XPCForwards.h
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCMaps.cpp
js/xpconnect/src/XPCMaps.h
js/xpconnect/src/XPCWrappedJS.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/xpcprivate.h
--- a/js/xpconnect/src/XPCForwards.h
+++ b/js/xpconnect/src/XPCForwards.h
@@ -4,42 +4,40 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Private forward declarations. */
 
 #ifndef xpcforwards_h___
 #define xpcforwards_h___
 
-// forward declarations of interally used classes...
+// forward declarations of internally used classes...
 
 class nsXPConnect;
 class XPCJSContext;
 class XPCJSRuntime;
 class XPCContext;
 class XPCCallContext;
 
 class XPCJSThrower;
 
 class nsXPCWrappedJS;
-class nsXPCWrappedJSClass;
 
 class XPCNativeMember;
 class XPCNativeInterface;
 class XPCNativeSet;
 
 class XPCWrappedNative;
 class XPCWrappedNativeProto;
 class XPCWrappedNativeTearOff;
 
 class XPCTraceableVariant;
 
 class JSObject2WrappedJSMap;
 class Native2WrappedNativeMap;
-class IID2WrappedJSClassMap;
 class IID2NativeInterfaceMap;
 class ClassInfo2NativeSetMap;
 class ClassInfo2WrappedNativeProtoMap;
 class NativeSetMap;
 class XPCWrappedNativeProtoMap;
 class JSObject2JSObjectMap;
 
 class nsXPCComponents;
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1133,19 +1133,16 @@ void XPCJSRuntime::Shutdown(JSContext* c
 
   JS::SetGCSliceCallback(cx, mPrevGCSliceCallback);
 
   // clean up and destroy maps...
   mWrappedJSMap->ShutdownMarker();
   delete mWrappedJSMap;
   mWrappedJSMap = nullptr;
 
-  delete mWrappedJSClassMap;
-  mWrappedJSClassMap = nullptr;
-
   delete mIID2NativeInterfaceMap;
   mIID2NativeInterfaceMap = nullptr;
 
   delete mClassInfo2NativeSetMap;
   mClassInfo2NativeSetMap = nullptr;
 
   delete mNativeSetMap;
   mNativeSetMap = nullptr;
@@ -2919,18 +2916,16 @@ class XPCJSSourceHook : public js::Sourc
 };
 
 static const JSWrapObjectCallbacks WrapObjectCallbacks = {
     xpc::WrapperFactory::Rewrap, xpc::WrapperFactory::PrepareForWrapping};
 
 XPCJSRuntime::XPCJSRuntime(JSContext* aCx)
     : CycleCollectedJSRuntime(aCx),
       mWrappedJSMap(JSObject2WrappedJSMap::newMap(XPC_JS_MAP_LENGTH)),
-      mWrappedJSClassMap(
-          IID2WrappedJSClassMap::newMap(XPC_JS_CLASS_MAP_LENGTH)),
       mIID2NativeInterfaceMap(
           IID2NativeInterfaceMap::newMap(XPC_NATIVE_INTERFACE_MAP_LENGTH)),
       mClassInfo2NativeSetMap(
           ClassInfo2NativeSetMap::newMap(XPC_NATIVE_SET_MAP_LENGTH)),
       mNativeSetMap(NativeSetMap::newMap(XPC_NATIVE_SET_MAP_LENGTH)),
       mWrappedNativeScopes(),
       mDyingWrappedNativeProtoMap(
           XPCWrappedNativeProtoMap::newMap(XPC_DYING_NATIVE_PROTO_MAP_LENGTH)),
@@ -3143,28 +3138,16 @@ bool XPCJSRuntime::NoteCustomGCThingXPCO
 /***************************************************************************/
 
 void XPCJSRuntime::DebugDump(int16_t depth) {
 #ifdef DEBUG
   depth--;
   XPC_LOG_ALWAYS(("XPCJSRuntime @ %p", this));
   XPC_LOG_INDENT();
 
-  XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %p with %d wrapperclasses(s)",
-                  mWrappedJSClassMap, mWrappedJSClassMap->Count()));
-  // iterate wrappersclasses...
-  if (depth && mWrappedJSClassMap->Count()) {
-    XPC_LOG_INDENT();
-    for (auto i = mWrappedJSClassMap->Iter(); !i.Done(); i.Next()) {
-      auto entry = static_cast<IID2WrappedJSClassMap::Entry*>(i.Get());
-      nsXPCWrappedJSClass::DebugDump(entry->value->GetInterfaceInfo(), depth);
-    }
-    XPC_LOG_OUTDENT();
-  }
-
   // iterate wrappers...
   XPC_LOG_ALWAYS(("mWrappedJSMap @ %p with %d wrappers(s)", mWrappedJSMap,
                   mWrappedJSMap->Count()));
   if (depth && mWrappedJSMap->Count()) {
     XPC_LOG_INDENT();
     mWrappedJSMap->Dump(depth);
     XPC_LOG_OUTDENT();
   }
--- a/js/xpconnect/src/XPCMaps.cpp
+++ b/js/xpconnect/src/XPCMaps.cpp
@@ -112,31 +112,16 @@ size_t Native2WrappedNativeMap::SizeOfIn
   for (auto iter = mTable.ConstIter(); !iter.Done(); iter.Next()) {
     auto entry = static_cast<Native2WrappedNativeMap::Entry*>(iter.Get());
     n += mallocSizeOf(entry->value);
   }
   return n;
 }
 
 /***************************************************************************/
-// implement IID2WrappedJSClassMap...
-
-const struct PLDHashTableOps IID2WrappedJSClassMap::Entry::sOps = {
-    HashIIDPtrKey, MatchIIDPtrKey, PLDHashTable::MoveEntryStub,
-    PLDHashTable::ClearEntryStub};
-
-// static
-IID2WrappedJSClassMap* IID2WrappedJSClassMap::newMap(int length) {
-  return new IID2WrappedJSClassMap(length);
-}
-
-IID2WrappedJSClassMap::IID2WrappedJSClassMap(int length)
-    : mTable(&Entry::sOps, sizeof(Entry), length) {}
-
-/***************************************************************************/
 // implement IID2NativeInterfaceMap...
 
 const struct PLDHashTableOps IID2NativeInterfaceMap::Entry::sOps = {
     HashIIDPtrKey, MatchIIDPtrKey, PLDHashTable::MoveEntryStub,
     PLDHashTable::ClearEntryStub};
 
 // static
 IID2NativeInterfaceMap* IID2NativeInterfaceMap::newMap(int length) {
--- a/js/xpconnect/src/XPCMaps.h
+++ b/js/xpconnect/src/XPCMaps.h
@@ -152,68 +152,16 @@ class Native2WrappedNativeMap {
   explicit Native2WrappedNativeMap(int size);
 
  private:
   PLDHashTable mTable;
 };
 
 /*************************/
 
-class IID2WrappedJSClassMap {
- public:
-  struct Entry : public PLDHashEntryHdr {
-    const nsIID* key;
-    nsXPCWrappedJSClass* value;
-
-    static const struct PLDHashTableOps sOps;
-  };
-
-  static IID2WrappedJSClassMap* newMap(int length);
-
-  inline nsXPCWrappedJSClass* Find(REFNSIID iid) const {
-    auto entry = static_cast<Entry*>(mTable.Search(&iid));
-    return entry ? entry->value : nullptr;
-  }
-
-  inline nsXPCWrappedJSClass* Add(nsXPCWrappedJSClass* clazz) {
-    MOZ_ASSERT(clazz, "bad param");
-    const nsIID* iid = &clazz->GetIID();
-    auto entry = static_cast<Entry*>(mTable.Add(iid, mozilla::fallible));
-    if (!entry) {
-      return nullptr;
-    }
-    if (entry->key) {
-      return entry->value;
-    }
-    entry->key = iid;
-    entry->value = clazz;
-    return clazz;
-  }
-
-  inline void Remove(nsXPCWrappedJSClass* clazz) {
-    MOZ_ASSERT(clazz, "bad param");
-    mTable.Remove(&clazz->GetIID());
-  }
-
-  inline uint32_t Count() { return mTable.EntryCount(); }
-
-#ifdef DEBUG
-  PLDHashTable::Iterator Iter() { return mTable.Iter(); }
-#endif
-
- private:
-  IID2WrappedJSClassMap();  // no implementation
-  explicit IID2WrappedJSClassMap(int size);
-
- private:
-  PLDHashTable mTable;
-};
-
-/*************************/
-
 class IID2NativeInterfaceMap {
  public:
   struct Entry : public PLDHashEntryHdr {
     const nsIID* key;
     XPCNativeInterface* value;
 
     static const struct PLDHashTableOps sOps;
   };
--- a/js/xpconnect/src/XPCWrappedJS.cpp
+++ b/js/xpconnect/src/XPCWrappedJS.cpp
@@ -98,22 +98,17 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrapp
   nsISupports* s = static_cast<nsISupports*>(p);
   MOZ_ASSERT(CheckForRightISupports(s),
              "not the nsISupports pointer we expect");
   nsXPCWrappedJS* tmp = Downcast(s);
 
   nsrefcnt refcnt = tmp->mRefCnt.get();
   if (cb.WantDebugInfo()) {
     char name[72];
-    if (tmp->GetClass()) {
-      SprintfLiteral(name, "nsXPCWrappedJS (%s)",
-                     tmp->GetClass()->GetInterfaceName());
-    } else {
-      SprintfLiteral(name, "nsXPCWrappedJS");
-    }
+    SprintfLiteral(name, "nsXPCWrappedJS (%s)", tmp->mInfo->Name());
     cb.DescribeRefCountedNode(refcnt, name);
   } else {
     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsXPCWrappedJS, refcnt)
   }
 
   // A wrapper that is subject to finalization will only die when its JS object
   // dies.
   if (tmp->IsSubjectToFinalization()) {
@@ -329,18 +324,18 @@ nsresult nsXPCWrappedJS::GetNewOrUsed(JS
                                       nsXPCWrappedJS** wrapperResult) {
   // Do a release-mode assert against accessing nsXPCWrappedJS off-main-thread.
   MOZ_RELEASE_ASSERT(NS_IsMainThread(),
                      "nsXPCWrappedJS::GetNewOrUsed called off main thread");
 
   MOZ_RELEASE_ASSERT(js::GetContextCompartment(cx) ==
                      js::GetObjectCompartment(jsObj));
 
-  RefPtr<nsXPCWrappedJSClass> clasp = nsXPCWrappedJSClass::GetNewOrUsed(aIID);
-  if (!clasp) {
+  const nsXPTInterfaceInfo* info = nsXPCWrappedJSClass::GetInterfaceInfo(aIID);
+  if (!info) {
     return NS_ERROR_FAILURE;
   }
 
   JS::RootedObject rootJSObj(cx,
                              nsXPCWrappedJSClass::GetRootJSObject(cx, jsObj));
   if (!rootJSObj) {
     return NS_ERROR_FAILURE;
   }
@@ -365,45 +360,45 @@ nsresult nsXPCWrappedJS::GetNewOrUsed(JS
     if (wrapper) {
       wrapper.forget(wrapperResult);
       return NS_OK;
     }
   } else if (rootJSObj != jsObj) {
     // Make a new root wrapper, because there is no existing
     // root wrapper, and the wrapper we are trying to make isn't
     // a root.
-    RefPtr<nsXPCWrappedJSClass> rootClasp =
-        nsXPCWrappedJSClass::GetNewOrUsed(NS_GET_IID(nsISupports));
-    if (!rootClasp) {
+    const nsXPTInterfaceInfo* rootInfo =
+        nsXPCWrappedJSClass::GetInterfaceInfo(NS_GET_IID(nsISupports));
+    if (!rootInfo) {
       return NS_ERROR_FAILURE;
     }
 
-    root = new nsXPCWrappedJS(cx, rootJSObj, rootClasp, nullptr, &rv);
+    root = new nsXPCWrappedJS(cx, rootJSObj, rootInfo, nullptr, &rv);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
   RefPtr<nsXPCWrappedJS> wrapper =
-      new nsXPCWrappedJS(cx, jsObj, clasp, root, &rv);
+      new nsXPCWrappedJS(cx, jsObj, info, root, &rv);
   if (NS_FAILED(rv)) {
     return rv;
   }
   wrapper.forget(wrapperResult);
   return NS_OK;
 }
 
 nsXPCWrappedJS::nsXPCWrappedJS(JSContext* cx, JSObject* aJSObj,
-                               nsXPCWrappedJSClass* aClass,
+                               const nsXPTInterfaceInfo* aInfo,
                                nsXPCWrappedJS* root, nsresult* rv)
     : mJSObj(aJSObj),
-      mClass(aClass),
+      mInfo(aInfo),
       mRoot(root ? root : this),
       mNext(nullptr) {
-  *rv = InitStub(GetClass()->GetIID());
+  *rv = InitStub(mInfo->IID());
   // Continue even in the failure case, so that our refcounting/Destroy
   // behavior works correctly.
 
   // There is an extra AddRef to support weak references to wrappers
   // that are subject to finalization. See the top of the file for more
   // details.
   NS_ADDREF_THIS();
 
@@ -530,17 +525,16 @@ void nsXPCWrappedJS::Unlink() {
     // leave the wrapper in the multi-compartment table as it is likely to
     // need to be multi-compartment again in the future and, moreover, we
     // cannot get a JSContext here.
 
     // let the root go
     NS_RELEASE(mRoot);
   }
 
-  mClass = nullptr;
   if (mOuter) {
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     if (rt->GCIsRunning()) {
       DeferredFinalize(mOuter.forget().take());
     } else {
       mOuter = nullptr;
     }
   }
@@ -573,17 +567,17 @@ nsXPCWrappedJS* nsXPCWrappedJS::Find(REF
   return nullptr;
 }
 
 // check if asking for an interface that some wrapper in the chain inherits from
 nsXPCWrappedJS* nsXPCWrappedJS::FindInherited(REFNSIID aIID) {
   MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsISupports)), "bad call sequence");
 
   for (nsXPCWrappedJS* cur = mRoot; cur; cur = cur->mNext) {
-    if (cur->GetClass()->GetInterfaceInfo()->HasAncestor(aIID)) {
+    if (cur->mInfo->HasAncestor(aIID)) {
       return cur;
     }
   }
 
   return nullptr;
 }
 
 NS_IMETHODIMP
@@ -611,39 +605,35 @@ void nsXPCWrappedJS::SystemIsBeingShutDo
   // XXX It turns out that it is better to leak here then to do any Releases
   // and have them propagate into all sorts of mischief as the system is being
   // shutdown. This was learned the hard way :(
 
   // mJSObj == nullptr is used to indicate that the wrapper is no longer valid
   // and that calls should fail without trying to use any of the
   // xpconnect mechanisms. 'IsValid' is implemented by checking this pointer.
 
-  // NOTE: that mClass is retained so that GetInterfaceInfo can continue to
-  // work (and avoid crashing some platforms).
-
   // Clear the contents of the pointer using unsafeGet() to avoid
   // triggering post barriers in shutdown, as this will access the chunk
   // containing mJSObj, which may have been freed at this point. This is safe
   // if we are not currently running an incremental GC.
   MOZ_ASSERT(!IsIncrementalGCInProgress(xpc_GetSafeJSContext()));
   *mJSObj.unsafeGet() = nullptr;
 
   // Notify other wrappers in the chain.
   if (mNext) {
     mNext->SystemIsBeingShutDown();
   }
 }
 
 size_t nsXPCWrappedJS::SizeOfIncludingThis(
     mozilla::MallocSizeOf mallocSizeOf) const {
-  // mJSObject is a JS pointer, so don't measure the object.
-  // mClass is not uniquely owned by this WrappedJS. Measure it in
-  // IID2WrappedJSClassMap. mRoot is not measured because it is either |this| or
-  // we have already measured it. mOuter is rare and probably not uniquely owned
-  // by this.
+  // mJSObject is a JS pointer, so don't measure the object.  mInfo is
+  // not dynamically allocated. mRoot is not measured because it is
+  // either |this| or we have already measured it. mOuter is rare and
+  // probably not uniquely owned by this.
   size_t n = mallocSizeOf(this);
   n += nsAutoXPTCStub::SizeOfExcludingThis(mallocSizeOf);
 
   // Wrappers form a linked list via the mNext field, so include them all
   // in the measurement. Only root wrappers are stored in the map, so
   // everything will be measured exactly once.
   if (mNext) {
     n += mNext->SizeOfIncludingThis(mallocSizeOf);
@@ -658,24 +648,24 @@ NS_IMETHODIMP
 nsXPCWrappedJS::DebugDump(int16_t depth) {
 #ifdef DEBUG
   XPC_LOG_ALWAYS(
       ("nsXPCWrappedJS @ %p with mRefCnt = %" PRIuPTR, this, mRefCnt.get()));
   XPC_LOG_INDENT();
 
   XPC_LOG_ALWAYS(("%s wrapper around JSObject @ %p",
                   IsRootWrapper() ? "ROOT" : "non-root", mJSObj.get()));
-  const char* name = GetClass()->GetInterfaceInfo()->Name();
+  const char* name = mInfo->Name();
   XPC_LOG_ALWAYS(("interface name is %s", name));
-  char* iid = GetClass()->GetIID().ToString();
+  char* iid = mInfo->IID().ToString();
   XPC_LOG_ALWAYS(("IID number is %s", iid ? iid : "invalid"));
   if (iid) {
     free(iid);
   }
-  XPC_LOG_ALWAYS(("nsXPCWrappedJSClass @ %p", mClass.get()));
+  XPC_LOG_ALWAYS(("nsXPTInterfaceInfo @ %p", mInfo));
 
   if (!IsRootWrapper()) {
     XPC_LOG_OUTDENT();
   }
   if (mNext) {
     if (IsRootWrapper()) {
       XPC_LOG_ALWAYS(("Additional wrappers for this object..."));
       XPC_LOG_INDENT();
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -26,18 +26,16 @@
 #include "jsapi.h"
 #include "jsfriendapi.h"
 
 using namespace xpc;
 using namespace JS;
 using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_ISUPPORTS(nsXPCWrappedJSClass, nsISupports)
-
 bool AutoScriptEvaluate::StartEvaluating(HandleObject scope) {
   MOZ_ASSERT(!mEvaluated,
              "AutoScriptEvaluate::Evaluate should only be called once");
 
   if (!mJSContext) {
     return true;
   }
 
@@ -93,40 +91,28 @@ class MOZ_STACK_CLASS AutoSavePendingRes
   ~AutoSavePendingResult() { mXPCContext->SetPendingResult(mSavedResult); }
 
  private:
   XPCJSContext* mXPCContext;
   nsresult mSavedResult;
 };
 
 // static
-already_AddRefed<nsXPCWrappedJSClass> nsXPCWrappedJSClass::GetNewOrUsed(
-    REFNSIID aIID) {
-  XPCJSRuntime* xpcrt = nsXPConnect::GetRuntimeInstance();
-  IID2WrappedJSClassMap* map = xpcrt->GetWrappedJSClassMap();
-  RefPtr<nsXPCWrappedJSClass> clasp = map->Find(aIID);
+const nsXPTInterfaceInfo*
+nsXPCWrappedJSClass::GetInterfaceInfo(REFNSIID aIID) {
+  const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByIID(aIID);
+  if (!info) {
+    return nullptr;
+  }
 
-  if (!clasp) {
-    const nsXPTInterfaceInfo* info = nsXPTInterfaceInfo::ByIID(aIID);
-    if (info) {
-      if (!info->IsBuiltinClass() && nsXPConnect::IsISupportsDescendant(info)) {
-        clasp = new nsXPCWrappedJSClass(info);
-      }
-    }
+  if (info->IsBuiltinClass() || !nsXPConnect::IsISupportsDescendant(info)) {
+    return nullptr;
   }
-  return clasp.forget();
-}
 
-nsXPCWrappedJSClass::nsXPCWrappedJSClass(const nsXPTInterfaceInfo* aInfo)
-    : mInfo(aInfo) {
-  XPCJSRuntime::Get()->GetWrappedJSClassMap()->Add(this);
-}
-
-nsXPCWrappedJSClass::~nsXPCWrappedJSClass() {
-  XPCJSRuntime::Get()->GetWrappedJSClassMap()->Remove(this);
+  return info;
 }
 
 // static
 JSObject* nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(JSContext* cx,
                                                             JSObject* jsobjArg,
                                                             HandleObject scope,
                                                             REFNSIID aIID) {
   js::AssertSameCompartment(scope, jsobjArg);
@@ -775,18 +761,17 @@ nsresult nsXPCWrappedJSClass::CallMethod
   }
 
   JSContext* cx = ccx.GetJSContext();
 
   if (!cx || !info->IsReflectable()) {
     return NS_ERROR_FAILURE;
   }
 
-  const nsXPTInterfaceInfo* interfaceInfo =
-      wrapper->GetClass()->GetInterfaceInfo();
+  const nsXPTInterfaceInfo* interfaceInfo = wrapper->GetInfo();
   JS::RootedId id(cx);
   const char* name;
   nsAutoCString symbolName;
   if (info->IsSymbol()) {
     info->GetSymbolDescription(cx, symbolName);
     name = symbolName.get();
     id = SYMBOL_TO_JSID(info->GetSymbol(cx));
   } else {
@@ -1089,18 +1074,16 @@ pre_call_clean_up:
   } else {
     // set to whatever the JS code might have set as the result
     retval = xpccx->GetPendingResult();
   }
 
   return retval;
 }
 
-const char* nsXPCWrappedJSClass::GetInterfaceName() { return mInfo->Name(); }
-
 static const JSClass XPCOutParamClass = {"XPCOutParam", 0, JS_NULL_CLASS_OPS};
 
 bool xpc::IsOutObject(JSContext* cx, JSObject* obj) {
   return js::GetObjectJSClass(obj) == &XPCOutParamClass;
 }
 
 JSObject* xpc::NewOutObject(JSContext* cx) {
   return JS_NewObject(cx, &XPCOutParamClass);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -166,17 +166,16 @@ namespace dom {
 class Exception;
 }  // namespace dom
 }  // namespace mozilla
 
 /***************************************************************************/
 // default initial sizes for maps (hashtables)
 
 #define XPC_JS_MAP_LENGTH 32
-#define XPC_JS_CLASS_MAP_LENGTH 32
 
 #define XPC_NATIVE_MAP_LENGTH 8
 #define XPC_NATIVE_PROTO_MAP_LENGTH 8
 #define XPC_DYING_NATIVE_PROTO_MAP_LENGTH 8
 #define XPC_NATIVE_INTERFACE_MAP_LENGTH 32
 #define XPC_NATIVE_SET_MAP_LENGTH 32
 #define XPC_WRAPPER_MAP_LENGTH 8
 
@@ -483,20 +482,16 @@ class XPCJSRuntime final : public mozill
 
   void RemoveWrappedJS(nsXPCWrappedJS* wrapper);
   void AssertInvalidWrappedJSNotInTable(nsXPCWrappedJS* wrapper) const;
 
   JSObject2WrappedJSMap* GetMultiCompartmentWrappedJSMap() const {
     return mWrappedJSMap;
   }
 
-  IID2WrappedJSClassMap* GetWrappedJSClassMap() const {
-    return mWrappedJSClassMap;
-  }
-
   IID2NativeInterfaceMap* GetIID2NativeInterfaceMap() const {
     return mIID2NativeInterfaceMap;
   }
 
   ClassInfo2NativeSetMap* GetClassInfo2NativeSetMap() const {
     return mClassInfo2NativeSetMap;
   }
 
@@ -620,17 +615,16 @@ class XPCJSRuntime final : public mozill
     }
   };
 
   typedef JS::GCHashMap<RefPtr<mozilla::BasePrincipal>, JS::Heap<JSObject*>,
                         Hasher, js::SystemAllocPolicy, SweepPolicy>
       Principal2JSObjectMap;
 
   JSObject2WrappedJSMap* mWrappedJSMap;
-  IID2WrappedJSClassMap* mWrappedJSClassMap;
   IID2NativeInterfaceMap* mIID2NativeInterfaceMap;
   ClassInfo2NativeSetMap* mClassInfo2NativeSetMap;
   NativeSetMap* mNativeSetMap;
   Principal2JSObjectMap mUAWidgetScopeMap;
   XPCWrappedNativeScopeList mWrappedNativeScopes;
   XPCWrappedNativeProtoMap* mDyingWrappedNativeProtoMap;
   bool mGCIsRunning;
   nsTArray<nsISupports*> mNativesToReleaseArray;
@@ -1591,32 +1585,25 @@ class XPCWrappedNative final : public ns
 ****************************************************************************
 *
 * Core classes for wrapped JSObject for use from native code...
 *
 ****************************************************************************
 ***************************************************************************/
 
 /*************************/
-// nsXPCWrappedJSClass represents the sharable factored out common code and
-// data for nsXPCWrappedJS instances for the same interface type.
-
-class nsXPCWrappedJSClass final : public nsISupports {
-  // all the interface method declarations...
-  NS_DECL_ISUPPORTS
+// nsXPCWrappedJSClass contains a number of helper methods for using
+// nsXPTInterfaceInfo and nsXPCWrappedJS.
+
+class nsXPCWrappedJSClass final {
+ public:
+  static const nsXPTInterfaceInfo* GetInterfaceInfo(REFNSIID aIID);
 
   static void DebugDump(const nsXPTInterfaceInfo* aInfo, int16_t depth);
 
- public:
-  static already_AddRefed<nsXPCWrappedJSClass> GetNewOrUsed(REFNSIID aIID);
-
-  REFNSIID GetIID() const { return mInfo->IID(); }
-  const nsXPTInterfaceInfo* GetInterfaceInfo() const { return mInfo; }
-  const char* GetInterfaceName();
-
   static nsresult DelegatedQueryInterface(nsXPCWrappedJS* self, REFNSIID aIID,
                                           void** aInstancePtr);
 
   static JSObject* GetRootJSObject(JSContext* cx, JSObject* aJSObj);
 
   static nsresult CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
                              const nsXPTMethodInfo* info,
                              nsXPTCMiniVariant* params);
@@ -1631,37 +1618,32 @@ class nsXPCWrappedJSClass final : public
   // aSyntheticException, if not null, is the exception we should be using.
   // If null, look for an exception on the JSContext hanging off the
   // XPCCallContext.
   static nsresult CheckForException(
       XPCCallContext& ccx, mozilla::dom::AutoEntryScript& aes,
       JS::HandleObject aObj, const char* aPropertyName,
       const char* anInterfaceName,
       mozilla::dom::Exception* aSyntheticException = nullptr);
-  virtual ~nsXPCWrappedJSClass();
-
   nsXPCWrappedJSClass() = delete;
-  explicit nsXPCWrappedJSClass(const nsXPTInterfaceInfo* aInfo);
+  ~nsXPCWrappedJSClass() = delete;
 
   static bool GetArraySizeFromParam(const nsXPTMethodInfo* method,
                                     const nsXPTType& type,
                                     nsXPTCMiniVariant* params,
                                     uint32_t* result);
 
   static bool GetInterfaceTypeFromParam(const nsXPTMethodInfo* method,
                                         const nsXPTType& type,
                                         nsXPTCMiniVariant* params,
                                         nsID* result);
 
   static void CleanupOutparams(const nsXPTMethodInfo* info,
                                nsXPTCMiniVariant* nativeParams, bool inOutOnly,
                                uint8_t count);
-
- private:
-  const nsXPTInterfaceInfo* mInfo;
 };
 
 /*************************/
 // nsXPCWrappedJS is a wrapper for a single JSObject for use from native code.
 // nsXPCWrappedJS objects are chained together to represent the various
 // interface on the single underlying (possibly aggregate) JSObject.
 
 class nsXPCWrappedJS final : protected nsAutoXPTCStub,
@@ -1705,18 +1687,18 @@ class nsXPCWrappedJS final : protected n
   // Returns true if the wrapper chain contains references to multiple
   // compartments. If the wrapper chain contains references to multiple
   // compartments, then it must be registered on the XPCJSContext. Otherwise,
   // it should be registered in the CompartmentPrivate for the compartment of
   // the root's JS object. This will only return correct results when called
   // on the root wrapper and will assert if not called on a root wrapper.
   bool IsMultiCompartment() const;
 
-  nsXPCWrappedJSClass* GetClass() const { return mClass; }
-  REFNSIID GetIID() const { return GetClass()->GetIID(); }
+  const nsXPTInterfaceInfo* GetInfo() const { return mInfo; }
+  REFNSIID GetIID() const { return mInfo->IID(); }
   nsXPCWrappedJS* GetRootWrapper() const { return mRoot; }
   nsXPCWrappedJS* GetNextWrapper() const { return mNext; }
 
   nsXPCWrappedJS* Find(REFNSIID aIID);
   nsXPCWrappedJS* FindInherited(REFNSIID aIID);
   nsXPCWrappedJS* FindOrFindInherited(REFNSIID aIID) {
     nsXPCWrappedJS* wrapper = Find(aIID);
     if (wrapper) {
@@ -1754,30 +1736,30 @@ class nsXPCWrappedJS final : protected n
   void TraceJS(JSTracer* trc);
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
   virtual ~nsXPCWrappedJS();
 
  protected:
   nsXPCWrappedJS() = delete;
-  nsXPCWrappedJS(JSContext* cx, JSObject* aJSObj, nsXPCWrappedJSClass* aClass,
+  nsXPCWrappedJS(JSContext* cx, JSObject* aJSObj, const nsXPTInterfaceInfo* aInfo,
                  nsXPCWrappedJS* root, nsresult* rv);
 
   bool CanSkip();
   void Destroy();
   void Unlink();
 
  private:
   JS::Compartment* Compartment() const {
     return js::GetObjectCompartment(mJSObj.unbarrieredGet());
   }
 
   JS::Heap<JSObject*> mJSObj;
-  RefPtr<nsXPCWrappedJSClass> mClass;
+  const nsXPTInterfaceInfo* const mInfo;
   nsXPCWrappedJS* mRoot;  // If mRoot != this, it is an owning pointer.
   nsXPCWrappedJS* mNext;
   nsCOMPtr<nsISupports> mOuter;  // only set in root
 };
 
 /***************************************************************************
 ****************************************************************************
 *