Commit b1c72224 authored by Kris Maglione's avatar Kris Maglione
Browse files

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

--HG--
extra : rebase_source : 33bb395f3eaa6522b18dbdb6e415b5287add86cd
extra : source : dd00365ebb55a06b4d6896bc86dd0fc94482d805
parent cab3cb13
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@ struct Module {
   * 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,
@@ -59,6 +61,9 @@ struct Module {
        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.
+67 −27
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@
#endif

using namespace mozilla;
using namespace mozilla::xpcom;

static LazyLogModule nsComponentManagerLog("nsComponentManager");

@@ -117,6 +118,45 @@ nsresult nsGetServiceFromCategory::operator()(const nsIID& aIID,
  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.
@@ -314,6 +354,27 @@ nsTArray<nsComponentManagerImpl::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);
@@ -437,29 +498,6 @@ nsresult nsComponentManagerImpl::Init() {
  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>
@@ -1157,9 +1195,10 @@ PRThread* nsComponentManagerImpl::GetPendingServiceThread(
  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);
@@ -1228,7 +1267,8 @@ nsComponentManagerImpl::GetServiceLocked(MutexLock& aLock, nsFactoryEntry& aEntr
  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");
+10 −1
Original line number Diff line number Diff line
@@ -56,6 +56,15 @@ namespace {
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