Bug 1478124: Part 3 - Add a lookup table for ProcessMatchesSelector. r=froydnj
☠☠ backed out by 1e042fc7de3d ☠ ☠
authorKris Maglione <maglione.k@gmail.com>
Tue, 18 Dec 2018 14:48:53 -0800
changeset 455922 dd00365ebb55a06b4d6896bc86dd0fc94482d805
parent 455921 538e40c5ee1336a7ba467f0f4128dcddf97ef75d
child 455923 f500020a273a27c66bf2166505a0e97bbc34a214
push id35463
push usershindli@mozilla.com
push dateTue, 29 Jan 2019 21:38:17 +0000
treeherdermozilla-central@4440fbf71c72 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1478124
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 1478124: Part 3 - Add a lookup table for ProcessMatchesSelector. r=froydnj Currently, when we build the component registry at startup, we exclude any entry with a process selector which doesn't match the current process. When we switch to static lookup tables, however, that check is going to have to happen for every lookup, since we can't alter the table at runtime. That may not matter much, given how expensive the rest of the component lookup code is relative to ProcessMatchesSelector, but it's also easy and cheap enough to generate a lookup table for all possible ProcessSelector values, and do a quick index check instead. Differential Revision: https://phabricator.services.mozilla.com/D15033
xpcom/components/Module.h
xpcom/components/nsComponentManager.cpp
xpcom/components/nsComponentManager.h
--- a/xpcom/components/Module.h
+++ b/xpcom/components/Module.h
@@ -34,16 +34,18 @@ struct Module {
 
   typedef nsresult (*LoadFuncPtr)();
   typedef void (*UnloadFuncPtr)();
 
   /**
    * This selector allows CIDEntrys to be marked so that they're only loaded
    * into certain kinds of processes. Selectors can be combined.
    */
+  // Note: This must be kept in sync with the selector matching in
+  // nsComponentManager.cpp.
   enum ProcessSelector {
     ANY_PROCESS = 0x0,
     MAIN_PROCESS_ONLY = 0x1,
     CONTENT_PROCESS_ONLY = 0x2,
 
     /**
      * By default, modules are not loaded in the GPU process, even if
      * ANY_PROCESS is specified. This flag enables a module in the
@@ -54,16 +56,19 @@ struct Module {
     ALLOW_IN_SOCKET_PROCESS = 0x10,
     ALLOW_IN_GPU_AND_VR_PROCESS = ALLOW_IN_GPU_PROCESS | ALLOW_IN_VR_PROCESS,
     ALLOW_IN_GPU_AND_SOCKET_PROCESS =
         ALLOW_IN_GPU_PROCESS | ALLOW_IN_SOCKET_PROCESS,
     ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS =
         ALLOW_IN_GPU_PROCESS | ALLOW_IN_VR_PROCESS | ALLOW_IN_SOCKET_PROCESS
   };
 
+  static constexpr size_t kMaxProcessSelector =
+      size_t(ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS);
+
   /**
    * The constructor callback is an implementation detail of the default binary
    * loader and may be null.
    */
   struct CIDEntry {
     const nsCID* cid;
     bool service;
     GetFactoryProcPtr getFactoryProc;
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -62,16 +62,17 @@
 #include "mozilla/Logging.h"
 #include "LogModulePrefWatcher.h"
 
 #ifdef MOZ_MEMORY
 #  include "mozmemory.h"
 #endif
 
 using namespace mozilla;
+using namespace mozilla::xpcom;
 
 static LazyLogModule nsComponentManagerLog("nsComponentManager");
 
 #if 0
 #  define SHOW_DENIED_ON_SHUTDOWN
 #  define SHOW_CI_ON_EXISTING_SERVICE
 #endif
 
@@ -112,16 +113,55 @@ nsresult nsGetServiceFromCategory::opera
     *aInstancePtr = 0;
   }
   if (mErrorPtr) {
     *mErrorPtr = rv;
   }
   return rv;
 }
 
+namespace mozilla {
+namespace xpcom {
+
+using ProcessSelector = Module::ProcessSelector;
+
+// Note: These must be kept in sync with the ProcessSelector definition in
+// Module.h.
+bool ProcessSelectorMatches(ProcessSelector aSelector) {
+  GeckoProcessType type = XRE_GetProcessType();
+  if (type == GeckoProcessType_GPU || type == GeckoProcessType_RDD) {
+    return !!(aSelector & Module::ALLOW_IN_GPU_PROCESS);
+  }
+
+  if (type == GeckoProcessType_Socket) {
+    return !!(aSelector & (Module::ALLOW_IN_SOCKET_PROCESS));
+  }
+
+  if (type == GeckoProcessType_VR) {
+    return !!(aSelector & Module::ALLOW_IN_VR_PROCESS);
+  }
+
+  if (aSelector & Module::MAIN_PROCESS_ONLY) {
+    return type == GeckoProcessType_Default;
+  }
+  if (aSelector & Module::CONTENT_PROCESS_ONLY) {
+    return type == GeckoProcessType_Content;
+  }
+  return true;
+}
+
+static bool gProcessMatchTable[Module::kMaxProcessSelector + 1];
+
+bool FastProcessSelectorMatches(ProcessSelector aSelector) {
+  return gProcessMatchTable[size_t(aSelector)];
+}
+
+}  // namespace xpcom
+}  // namespace mozilla
+
 // GetService and a few other functions need to exit their mutex mid-function
 // without reentering it later in the block. This class supports that
 // style of early-exit that MutexAutoUnlock doesn't.
 
 namespace {
 
 class MOZ_STACK_CLASS MutexLock {
  public:
@@ -309,16 +349,37 @@ nsTArray<nsComponentManagerImpl::Compone
   if (sModuleLocations) {
     return;
   }
 
   sModuleLocations = new nsTArray<ComponentLocation>;
 }
 
 nsresult nsComponentManagerImpl::Init() {
+  {
+    gProcessMatchTable[size_t(ProcessSelector::ANY_PROCESS)] =
+        ProcessSelectorMatches(ProcessSelector::ANY_PROCESS);
+    gProcessMatchTable[size_t(ProcessSelector::MAIN_PROCESS_ONLY)] =
+        ProcessSelectorMatches(ProcessSelector::MAIN_PROCESS_ONLY);
+    gProcessMatchTable[size_t(ProcessSelector::CONTENT_PROCESS_ONLY)] =
+        ProcessSelectorMatches(ProcessSelector::CONTENT_PROCESS_ONLY);
+    gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_PROCESS)] =
+        ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_PROCESS);
+    gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_VR_PROCESS)] =
+        ProcessSelectorMatches(ProcessSelector::ALLOW_IN_VR_PROCESS);
+    gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_SOCKET_PROCESS)] =
+        ProcessSelectorMatches(ProcessSelector::ALLOW_IN_SOCKET_PROCESS);
+    gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS)] =
+        ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_VR_PROCESS);
+    gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS)] =
+        ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_AND_SOCKET_PROCESS);
+    gProcessMatchTable[size_t(ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS)] =
+        ProcessSelectorMatches(ProcessSelector::ALLOW_IN_GPU_VR_AND_SOCKET_PROCESS);
+  }
+
   MOZ_ASSERT(NOT_INITIALIZED == mStatus);
 
   nsCOMPtr<nsIFile> greDir = GetLocationFromDirectoryService(NS_GRE_DIR);
   nsCOMPtr<nsIFile> appDir =
       GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR);
 
   InitializeStaticModules();
 
@@ -432,39 +493,16 @@ nsresult nsComponentManagerImpl::Init() 
   MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
           ("nsComponentManager: Initialized."));
 
   mStatus = NORMAL;
 
   return NS_OK;
 }
 
-static bool ProcessSelectorMatches(Module::ProcessSelector aSelector) {
-  GeckoProcessType type = XRE_GetProcessType();
-  if (type == GeckoProcessType_GPU || type == GeckoProcessType_RDD) {
-    return !!(aSelector & Module::ALLOW_IN_GPU_PROCESS);
-  }
-
-  if (type == GeckoProcessType_Socket) {
-    return !!(aSelector & (Module::ALLOW_IN_SOCKET_PROCESS));
-  }
-
-  if (type == GeckoProcessType_VR) {
-    return !!(aSelector & Module::ALLOW_IN_VR_PROCESS);
-  }
-
-  if (aSelector & Module::MAIN_PROCESS_ONLY) {
-    return type == GeckoProcessType_Default;
-  }
-  if (aSelector & Module::CONTENT_PROCESS_ONLY) {
-    return type == GeckoProcessType_Content;
-  }
-  return true;
-}
-
 static const int kModuleVersionWithSelector = 51;
 
 template <typename T>
 static void AssertNotMallocAllocated(T* aPtr) {
 #if defined(DEBUG) && defined(MOZ_MEMORY)
   jemalloc_ptr_info_t info;
   jemalloc_ptr_info((void*)aPtr, &info);
   MOZ_ASSERT(info.tag == TagUnknown);
@@ -1152,19 +1190,20 @@ PRThread* nsComponentManagerImpl::GetPen
     const PendingServiceInfo& info = mPendingServices.ElementAt(index);
     if (info.cid->Equals(aServiceCID)) {
       return info.thread;
     }
   }
   return nullptr;
 }
 
-nsresult
-nsComponentManagerImpl::GetServiceLocked(MutexLock& aLock, nsFactoryEntry& aEntry,
-                                         const nsIID& aIID, void** aResult) {
+nsresult nsComponentManagerImpl::GetServiceLocked(MutexLock& aLock,
+                                                  nsFactoryEntry& aEntry,
+                                                  const nsIID& aIID,
+                                                  void** aResult) {
   if (aEntry.mServiceObject) {
     aLock.Unlock();
     return aEntry.mServiceObject->QueryInterface(aIID, aResult);
   }
 
   PRThread* currentPRThread = PR_GetCurrentThread();
   MOZ_ASSERT(currentPRThread, "This should never be null!");
 
@@ -1223,17 +1262,18 @@ nsComponentManagerImpl::GetServiceLocked
       aLock.Unlock();
       service = nullptr;
     }
   });
 
   nsresult rv;
   {
     SafeMutexAutoUnlock unlock(mLock);
-    rv = CreateInstance(*aEntry.mCIDEntry->cid, nullptr, aIID, getter_AddRefs(service));
+    rv = CreateInstance(*aEntry.mCIDEntry->cid, nullptr, aIID,
+                        getter_AddRefs(service));
   }
   if (NS_SUCCEEDED(rv) && !service) {
     NS_ERROR("Factory did not return an object but returned success");
     return NS_ERROR_SERVICE_NOT_AVAILABLE;
   }
 
 #ifdef DEBUG
   pendingPRThread = GetPendingServiceThread(*aEntry.mCIDEntry->cid);
--- a/xpcom/components/nsComponentManager.h
+++ b/xpcom/components/nsComponentManager.h
@@ -48,19 +48,28 @@ struct PRThread;
     }                                                \
   }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 extern const mozilla::Module kXPCOMModule;
 
 namespace {
-  class MutexLock;
+class MutexLock;
 }
 
+namespace mozilla {
+namespace xpcom {
+
+bool ProcessSelectorMatches(Module::ProcessSelector aSelector);
+bool FastProcessSelectorMatches(Module::ProcessSelector aSelector);
+
+}  // namespace xpcom
+}  // namespace mozilla
+
 /**
  * This is a wrapper around mozilla::Mutex which provides runtime
  * checking for a deadlock where the same thread tries to lock a mutex while
  * it is already locked. This checking is present in both debug and release
  * builds.
  */
 class SafeMutex {
  public: