|
@@ -0,0 +1,902 @@
|
|
|
+# HG changeset patch
|
|
|
+# User Bill Gianopoulos <wgianopoulos@gmail.com>
|
|
|
+# Date 1657108142 0
|
|
|
+Reinstate XPCOM infrastructure removed in bug 1773770 part 12.
|
|
|
+Bug 1773770: Part 12 - Remove XPCOM Module infrastructure.
|
|
|
+
|
|
|
+diff --git a/xpcom/build/nsXPCOM.h b/xpcom/build/nsXPCOM.h
|
|
|
+--- a/xpcom/build/nsXPCOM.h
|
|
|
++++ b/xpcom/build/nsXPCOM.h
|
|
|
+@@ -34,16 +34,19 @@ DECL_CLASS(nsIDebug2);
|
|
|
+ extern bool gXPCOMShuttingDown;
|
|
|
+ extern mozilla::Atomic<bool, mozilla::SequentiallyConsistent>
|
|
|
+ gXPCOMThreadsShutDown;
|
|
|
+ extern bool gXPCOMMainThreadEventsAreDoomed;
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #ifdef __cplusplus
|
|
|
+ # include "nsStringFwd.h"
|
|
|
++namespace mozilla {
|
|
|
++struct Module;
|
|
|
++} // namespace mozilla
|
|
|
+ #endif
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Initialises XPCOM. You must call one of the NS_InitXPCOM methods
|
|
|
+ * before proceeding to use xpcom. The one exception is that you may
|
|
|
+ * call NS_NewLocalFile to create a nsIFile.
|
|
|
+ *
|
|
|
+ * @note Use <CODE>NS_NewLocalFile</CODE> or <CODE>NS_NewNativeLocalFile</CODE>
|
|
|
+diff --git a/xpcom/build/nsXULAppAPI.h b/xpcom/build/nsXULAppAPI.h
|
|
|
+--- a/xpcom/build/nsXULAppAPI.h
|
|
|
++++ b/xpcom/build/nsXULAppAPI.h
|
|
|
+@@ -23,16 +23,17 @@ class nsIFile;
|
|
|
+ class nsISupports;
|
|
|
+ struct JSContext;
|
|
|
+ struct XREChildData;
|
|
|
+ struct XREShellData;
|
|
|
+
|
|
|
+ namespace mozilla {
|
|
|
+ class XREAppData;
|
|
|
+ struct BootstrapConfig;
|
|
|
++struct Module;
|
|
|
+ } // namespace mozilla
|
|
|
+
|
|
|
+ /**
|
|
|
+ * A directory service key which provides the platform-correct "application
|
|
|
+ * data" directory as follows, where $name and $vendor are as defined above and
|
|
|
+ * $vendor is optional:
|
|
|
+ *
|
|
|
+ * Windows:
|
|
|
+@@ -214,16 +215,21 @@ int XRE_main(int argc, char* argv[], con
|
|
|
+ nsresult XRE_GetFileFromPath(const char* aPath, nsIFile** aResult);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get the path of the running application binary and store it in aResult.
|
|
|
+ */
|
|
|
+ nsresult XRE_GetBinaryPath(nsIFile** aResult);
|
|
|
+
|
|
|
+ /**
|
|
|
++ * Get the static module built in to libxul.
|
|
|
++ */
|
|
|
++const mozilla::Module* XRE_GetStaticModule();
|
|
|
++
|
|
|
++/**
|
|
|
+ * Lock a profile directory using platform-specific semantics.
|
|
|
+ *
|
|
|
+ * @param aDirectory The profile directory to lock.
|
|
|
+ * @param aLockObject An opaque lock object. The directory will remain locked
|
|
|
+ * as long as the XPCOM reference is held.
|
|
|
+ */
|
|
|
+ nsresult XRE_LockProfileDirectory(nsIFile* aDirectory,
|
|
|
+ nsISupports** aLockObject);
|
|
|
+@@ -247,16 +253,23 @@ nsresult XRE_LockProfileDirectory(nsIFil
|
|
|
+ * a given process. Use XRE_TermEmbedding to clean up and free
|
|
|
+ * resources allocated by XRE_InitEmbedding.
|
|
|
+ */
|
|
|
+
|
|
|
+ nsresult XRE_InitEmbedding2(nsIFile* aLibXULDirectory, nsIFile* aAppDirectory,
|
|
|
+ nsIDirectoryServiceProvider* aAppDirProvider);
|
|
|
+
|
|
|
+ /**
|
|
|
++ * Register static XPCOM component information.
|
|
|
++ * This method may be called at any time before or after XRE_main or
|
|
|
++ * XRE_InitEmbedding.
|
|
|
++ */
|
|
|
++nsresult XRE_AddStaticComponent(const mozilla::Module* aComponent);
|
|
|
++
|
|
|
++/**
|
|
|
+ * Register XPCOM components found in an array of files/directories.
|
|
|
+ * This method may be called at any time before or after XRE_main or
|
|
|
+ * XRE_InitEmbedding.
|
|
|
+ *
|
|
|
+ * @param aFiles An array of files or directories.
|
|
|
+ * @param aFileCount the number of items in the aFiles array.
|
|
|
+ * @note appdir/components is registered automatically.
|
|
|
+ *
|
|
|
+diff --git a/xpcom/components/GenericFactory.h b/xpcom/components/GenericFactory.h
|
|
|
+--- a/xpcom/components/GenericFactory.h
|
|
|
++++ b/xpcom/components/GenericFactory.h
|
|
|
+@@ -2,30 +2,32 @@
|
|
|
+ /* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
+ /* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
+ * 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/. */
|
|
|
+
|
|
|
+ #ifndef mozilla_GenericFactory_h
|
|
|
+ #define mozilla_GenericFactory_h
|
|
|
+
|
|
|
+-#include "nsIFactory.h"
|
|
|
++#include "mozilla/Attributes.h"
|
|
|
++
|
|
|
++#include "mozilla/Module.h"
|
|
|
+
|
|
|
+ namespace mozilla {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * A generic factory which uses a constructor function to create instances.
|
|
|
+ * This class is intended for use by the component manager and the generic
|
|
|
+ * module.
|
|
|
+ */
|
|
|
+ class GenericFactory final : public nsIFactory {
|
|
|
+- ~GenericFactory() = default;
|
|
|
++ ~GenericFactory() {}
|
|
|
+
|
|
|
+ public:
|
|
|
+- typedef nsresult (*ConstructorProcPtr)(const nsIID& aIID, void** aResult);
|
|
|
++ typedef Module::ConstructorProcPtr ConstructorProcPtr;
|
|
|
+
|
|
|
+ NS_DECL_THREADSAFE_ISUPPORTS
|
|
|
+ NS_DECL_NSIFACTORY
|
|
|
+
|
|
|
+ explicit GenericFactory(ConstructorProcPtr aCtor) : mCtor(aCtor) {
|
|
|
+ NS_ASSERTION(mCtor, "GenericFactory with no constructor");
|
|
|
+ }
|
|
|
+
|
|
|
+diff --git a/xpcom/components/Module.h b/xpcom/components/Module.h
|
|
|
+--- a/xpcom/components/Module.h
|
|
|
++++ b/xpcom/components/Module.h
|
|
|
+@@ -3,22 +3,41 @@
|
|
|
+ /* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
+ * 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/. */
|
|
|
+
|
|
|
+ #ifndef mozilla_Module_h
|
|
|
+ #define mozilla_Module_h
|
|
|
+
|
|
|
+ #include "nscore.h"
|
|
|
++#include "nsID.h"
|
|
|
++#include "nsIFactory.h"
|
|
|
++#include "nsCOMPtr.h" // for already_AddRefed
|
|
|
+
|
|
|
+ namespace mozilla {
|
|
|
+
|
|
|
+-namespace Module {
|
|
|
++/**
|
|
|
++ * A module implements one or more XPCOM components. This structure is used
|
|
|
++ * for binary modules.
|
|
|
++ */
|
|
|
++struct Module {
|
|
|
++ static const unsigned int kVersion = 104;
|
|
|
++
|
|
|
++ struct CIDEntry;
|
|
|
++
|
|
|
++ typedef already_AddRefed<nsIFactory> (*GetFactoryProcPtr)(
|
|
|
++ const Module& module, const CIDEntry& entry);
|
|
|
++
|
|
|
++ typedef nsresult (*ConstructorProcPtr)(const nsIID& aIID, void** aResult);
|
|
|
++
|
|
|
++ typedef nsresult (*LoadFuncPtr)();
|
|
|
++ typedef void (*UnloadFuncPtr)();
|
|
|
++
|
|
|
+ /**
|
|
|
+- * This selector allows components to be marked so that they're only loaded
|
|
|
++ * 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,
|
|
|
+@@ -64,13 +83,83 @@ namespace Module {
|
|
|
+ * not loaded when in backgroundtask mode.
|
|
|
+ */
|
|
|
+ // Note: This must be kept in sync with the selector matching in
|
|
|
+ // StaticComponents.cpp.in.
|
|
|
+ enum BackgroundTasksSelector {
|
|
|
+ NO_TASKS = 0x0,
|
|
|
+ ALL_TASKS = 0xFFFF,
|
|
|
+ };
|
|
|
++
|
|
|
++ /**
|
|
|
++ * 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;
|
|
|
++ ConstructorProcPtr constructorProc;
|
|
|
++ ProcessSelector processSelector;
|
|
|
++ };
|
|
|
++
|
|
|
++ struct ContractIDEntry {
|
|
|
++ const char* contractid;
|
|
|
++ nsID const* cid;
|
|
|
++ ProcessSelector processSelector;
|
|
|
++ };
|
|
|
++
|
|
|
++ struct CategoryEntry {
|
|
|
++ const char* category;
|
|
|
++ const char* entry;
|
|
|
++ const char* value;
|
|
|
++ };
|
|
|
++
|
|
|
++ /**
|
|
|
++ * Binary compatibility check, should be kModuleVersion.
|
|
|
++ */
|
|
|
++ unsigned int mVersion;
|
|
|
++
|
|
|
++ /**
|
|
|
++ * An array of CIDs (class IDs) implemented by this module. The final entry
|
|
|
++ * should be { nullptr }.
|
|
|
++ */
|
|
|
++ const CIDEntry* mCIDs;
|
|
|
++
|
|
|
++ /**
|
|
|
++ * An array of mappings from contractid to CID. The final entry should
|
|
|
++ * be { nullptr }.
|
|
|
++ */
|
|
|
++ const ContractIDEntry* mContractIDs;
|
|
|
++
|
|
|
++ /**
|
|
|
++ * An array of category manager entries. The final entry should be
|
|
|
++ * { nullptr }.
|
|
|
++ */
|
|
|
++ const CategoryEntry* mCategoryEntries;
|
|
|
++
|
|
|
++ /**
|
|
|
++ * When the component manager tries to get the factory for a CID, it first
|
|
|
++ * checks for this module-level getfactory callback. If this function is
|
|
|
++ * not implemented, it checks the CIDEntry getfactory callback. If that is
|
|
|
++ * also nullptr, a generic factory is generated using the CIDEntry
|
|
|
++ * constructor callback which must be non-nullptr.
|
|
|
++ */
|
|
|
++ GetFactoryProcPtr getFactoryProc;
|
|
|
++
|
|
|
++ /**
|
|
|
++ * Optional Function which are called when this module is loaded and
|
|
|
++ * at shutdown. These are not C++ constructor/destructors to avoid
|
|
|
++ * calling them too early in startup or too late in shutdown.
|
|
|
++ */
|
|
|
++ LoadFuncPtr loadProc;
|
|
|
++ UnloadFuncPtr unloadProc;
|
|
|
++
|
|
|
++ /**
|
|
|
++ * Optional flags which control whether the module loads on a process-type
|
|
|
++ * basis.
|
|
|
++ */
|
|
|
++ ProcessSelector selector;
|
|
|
+ };
|
|
|
+
|
|
|
+ } // namespace mozilla
|
|
|
+
|
|
|
+ #endif // mozilla_Module_h
|
|
|
+diff --git a/xpcom/components/ModuleUtils.h b/xpcom/components/ModuleUtils.h
|
|
|
+--- a/xpcom/components/ModuleUtils.h
|
|
|
++++ b/xpcom/components/ModuleUtils.h
|
|
|
+@@ -4,17 +4,16 @@
|
|
|
+ * 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/. */
|
|
|
+
|
|
|
+ #ifndef mozilla_GenericModule_h
|
|
|
+ #define mozilla_GenericModule_h
|
|
|
+
|
|
|
+ #include <type_traits>
|
|
|
+
|
|
|
+-#include "mozilla/AlreadyAddRefed.h"
|
|
|
+ #include "mozilla/Attributes.h"
|
|
|
+ #include "mozilla/Module.h"
|
|
|
+
|
|
|
+ #define NS_GENERIC_FACTORY_CONSTRUCTOR(_InstanceClass) \
|
|
|
+ static nsresult _InstanceClass##Constructor(REFNSIID aIID, void** aResult) { \
|
|
|
+ RefPtr<_InstanceClass> inst; \
|
|
|
+ \
|
|
|
+ *aResult = nullptr; \
|
|
|
+diff --git a/xpcom/components/nsComponentManager.cpp b/xpcom/components/nsComponentManager.cpp
|
|
|
+--- a/xpcom/components/nsComponentManager.cpp
|
|
|
++++ b/xpcom/components/nsComponentManager.cpp
|
|
|
+@@ -158,17 +158,17 @@ class MOZ_STACK_CLASS EntryWrapper final
|
|
|
+ #define MATCH(type, ifFactory, ifStatic) \
|
|
|
+ struct Matcher { \
|
|
|
+ type operator()(nsFactoryEntry* entry) { ifFactory; } \
|
|
|
+ type operator()(const StaticModule* entry) { ifStatic; } \
|
|
|
+ }; \
|
|
|
+ return mEntry.match((Matcher()))
|
|
|
+
|
|
|
+ const nsID& CID() {
|
|
|
+- MATCH(const nsID&, return entry->mCID, return entry->CID());
|
|
|
++ MATCH(const nsID&, return *entry->mCIDEntry->cid, return entry->CID());
|
|
|
+ }
|
|
|
+
|
|
|
+ already_AddRefed<nsIFactory> GetFactory() {
|
|
|
+ MATCH(already_AddRefed<nsIFactory>, return entry->GetFactory(),
|
|
|
+ return entry->GetFactory());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+@@ -197,21 +197,24 @@ class MOZ_STACK_CLASS EntryWrapper final
|
|
|
+ mEntry.as<nsFactoryEntry*>()->mServiceObject = aInst;
|
|
|
+ } else {
|
|
|
+ return mEntry.as<const StaticModule*>()->SetServiceInstance(
|
|
|
+ std::move(aInst));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+- * Returns the description string for the module this entry belongs to.
|
|
|
+- * Currently always returns "<unknown module>".
|
|
|
++ * Returns the description string for the module this entry belongs to. For
|
|
|
++ * static entries, always returns "<unknown module>".
|
|
|
+ */
|
|
|
+ nsCString ModuleDescription() {
|
|
|
+- return "<unknown module>"_ns;
|
|
|
++ MATCH(nsCString,
|
|
|
++ return entry->mModule ? entry->mModule->Description()
|
|
|
++ : "<unknown module>"_ns,
|
|
|
++ return "<unknown module>"_ns);
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ Variant<nsFactoryEntry*, const StaticModule*> mEntry;
|
|
|
+ };
|
|
|
+
|
|
|
+ } // namespace
|
|
|
+
|
|
|
+@@ -263,16 +266,27 @@ nsresult nsComponentManagerImpl::Create(
|
|
|
+ static const int CONTRACTID_HASHTABLE_INITIAL_LENGTH = 8;
|
|
|
+
|
|
|
+ nsComponentManagerImpl::nsComponentManagerImpl()
|
|
|
+ : mFactories(CONTRACTID_HASHTABLE_INITIAL_LENGTH),
|
|
|
+ mContractIDs(CONTRACTID_HASHTABLE_INITIAL_LENGTH),
|
|
|
+ mLock("nsComponentManagerImpl.mLock"),
|
|
|
+ mStatus(NOT_INITIALIZED) {}
|
|
|
+
|
|
|
++static nsTArray<const mozilla::Module*>* sExtraStaticModules;
|
|
|
++
|
|
|
++/* static */
|
|
|
++void nsComponentManagerImpl::InitializeStaticModules() {
|
|
|
++ if (sExtraStaticModules) {
|
|
|
++ return;
|
|
|
++ }
|
|
|
++
|
|
|
++ sExtraStaticModules = new nsTArray<const mozilla::Module*>;
|
|
|
++}
|
|
|
++
|
|
|
+ nsTArray<nsComponentManagerImpl::ComponentLocation>*
|
|
|
+ nsComponentManagerImpl::sModuleLocations;
|
|
|
+
|
|
|
+ /* static */
|
|
|
+ void nsComponentManagerImpl::InitializeModuleLocations() {
|
|
|
+ if (sModuleLocations) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+@@ -331,18 +345,24 @@ nsresult nsComponentManagerImpl::Init()
|
|
|
+ }
|
|
|
+
|
|
|
+ MOZ_ASSERT(NOT_INITIALIZED == mStatus);
|
|
|
+
|
|
|
+ nsCOMPtr<nsIFile> greDir = GetLocationFromDirectoryService(NS_GRE_DIR);
|
|
|
+ nsCOMPtr<nsIFile> appDir =
|
|
|
+ GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR);
|
|
|
+
|
|
|
++ InitializeStaticModules();
|
|
|
++
|
|
|
+ nsCategoryManager::GetSingleton()->SuppressNotifications(true);
|
|
|
+
|
|
|
++ for (uint32_t i = 0; i < sExtraStaticModules->Length(); ++i) {
|
|
|
++ RegisterModule((*sExtraStaticModules)[i]);
|
|
|
++ }
|
|
|
++
|
|
|
+ auto* catMan = nsCategoryManager::GetSingleton();
|
|
|
+ for (const auto& cat : gStaticCategories) {
|
|
|
+ for (const auto& entry : cat) {
|
|
|
+ if (entry.Active()) {
|
|
|
+ catMan->AddCategoryEntry(cat.Name(), entry.Entry(), entry.Value());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+@@ -443,16 +463,18 @@ nsresult nsComponentManagerImpl::Init()
|
|
|
+ MOZ_ASSERT(!XRE_IsContentProcess() ||
|
|
|
+ CONTRACTID_HASHTABLE_INITIAL_LENGTH <= 8 ||
|
|
|
+ mFactories.Count() > CONTRACTID_HASHTABLE_INITIAL_LENGTH / 3,
|
|
|
+ "Initial component hashtable size is too large");
|
|
|
+
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
++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);
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+@@ -483,16 +505,150 @@ static void AssertNotStackAllocated(T* a
|
|
|
+ #ifdef DEBUG
|
|
|
+ static constexpr size_t kFuzz = 2048;
|
|
|
+
|
|
|
+ MOZ_ASSERT(uintptr_t(aPtr) < uintptr_t(&aPtr) ||
|
|
|
+ uintptr_t(aPtr) > uintptr_t(&aPtr) + kFuzz);
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+
|
|
|
++static inline nsCString AsLiteralCString(const char* aStr) {
|
|
|
++ AssertNotMallocAllocated(aStr);
|
|
|
++ AssertNotStackAllocated(aStr);
|
|
|
++
|
|
|
++ nsCString str;
|
|
|
++ str.AssignLiteral(aStr, strlen(aStr));
|
|
|
++ return str;
|
|
|
++}
|
|
|
++
|
|
|
++void nsComponentManagerImpl::RegisterModule(const mozilla::Module* aModule) {
|
|
|
++ mLock.AssertNotCurrentThreadOwns();
|
|
|
++
|
|
|
++ if (aModule->mVersion >= kModuleVersionWithSelector &&
|
|
|
++ !ProcessSelectorMatches(aModule->selector)) {
|
|
|
++ return;
|
|
|
++ }
|
|
|
++
|
|
|
++ {
|
|
|
++ // Scope the monitor so that we don't hold it while calling into the
|
|
|
++ // category manager.
|
|
|
++ MonitorAutoLock lock(mLock);
|
|
|
++
|
|
|
++ KnownModule* m = new KnownModule(aModule);
|
|
|
++ mKnownStaticModules.AppendElement(m);
|
|
|
++
|
|
|
++ if (aModule->mCIDs) {
|
|
|
++ const mozilla::Module::CIDEntry* entry;
|
|
|
++ for (entry = aModule->mCIDs; entry->cid; ++entry) {
|
|
|
++ RegisterCIDEntryLocked(entry, m);
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
++ if (aModule->mContractIDs) {
|
|
|
++ const mozilla::Module::ContractIDEntry* entry;
|
|
|
++ for (entry = aModule->mContractIDs; entry->contractid; ++entry) {
|
|
|
++ RegisterContractIDLocked(entry);
|
|
|
++ }
|
|
|
++ MOZ_ASSERT(!entry->cid, "Incorrectly terminated contract list");
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
++ if (aModule->mCategoryEntries) {
|
|
|
++ const mozilla::Module::CategoryEntry* entry;
|
|
|
++ for (entry = aModule->mCategoryEntries; entry->category; ++entry)
|
|
|
++ nsCategoryManager::GetSingleton()->AddCategoryEntry(
|
|
|
++ AsLiteralCString(entry->category), AsLiteralCString(entry->entry),
|
|
|
++ AsLiteralCString(entry->value));
|
|
|
++ }
|
|
|
++}
|
|
|
++
|
|
|
++void nsComponentManagerImpl::RegisterCIDEntryLocked(
|
|
|
++ const mozilla::Module::CIDEntry* aEntry, KnownModule* aModule) {
|
|
|
++ mLock.AssertCurrentThreadOwns();
|
|
|
++
|
|
|
++ if (!ProcessSelectorMatches(aEntry->processSelector)) {
|
|
|
++ return;
|
|
|
++ }
|
|
|
++
|
|
|
++#ifdef DEBUG
|
|
|
++ // If we're still in the static initialization phase, check that we're not
|
|
|
++ // registering something that was already registered.
|
|
|
++ if (mStatus != NORMAL) {
|
|
|
++ if (StaticComponents::LookupByCID(*aEntry->cid)) {
|
|
|
++ MOZ_CRASH_UNSAFE_PRINTF(
|
|
|
++ "While registering XPCOM module %s, trying to re-register CID '%s' "
|
|
|
++ "already registered by a static component.",
|
|
|
++ aModule->Description().get(), AutoIDString(*aEntry->cid).get());
|
|
|
++ }
|
|
|
++ }
|
|
|
++#endif
|
|
|
++
|
|
|
++ mFactories.WithEntryHandle(aEntry->cid, [&](auto&& entry) {
|
|
|
++ mLock.AssertCurrentThreadOwns();
|
|
|
++ if (entry) {
|
|
|
++ nsFactoryEntry* f = entry.Data();
|
|
|
++ NS_WARNING("Re-registering a CID?");
|
|
|
++
|
|
|
++ nsCString existing;
|
|
|
++ if (f->mModule) {
|
|
|
++ existing = f->mModule->Description();
|
|
|
++ } else {
|
|
|
++ existing = "<unknown module>";
|
|
|
++ }
|
|
|
++ MonitorAutoUnlock unlock(mLock);
|
|
|
++ LogMessage(
|
|
|
++ "While registering XPCOM module %s, trying to re-register CID '%s' "
|
|
|
++ "already registered by %s.",
|
|
|
++ aModule->Description().get(), AutoIDString(*aEntry->cid).get(),
|
|
|
++ existing.get());
|
|
|
++ } else {
|
|
|
++ entry.Insert(new nsFactoryEntry(aEntry, aModule));
|
|
|
++ }
|
|
|
++ });
|
|
|
++}
|
|
|
++
|
|
|
++void nsComponentManagerImpl::RegisterContractIDLocked(
|
|
|
++ const mozilla::Module::ContractIDEntry* aEntry) {
|
|
|
++ mLock.AssertCurrentThreadOwns();
|
|
|
++
|
|
|
++ if (!ProcessSelectorMatches(aEntry->processSelector)) {
|
|
|
++ return;
|
|
|
++ }
|
|
|
++
|
|
|
++#ifdef DEBUG
|
|
|
++ // If we're still in the static initialization phase, check that we're not
|
|
|
++ // registering something that was already registered.
|
|
|
++ if (mStatus != NORMAL) {
|
|
|
++ if (const StaticModule* module = StaticComponents::LookupByContractID(
|
|
|
++ nsAutoCString(aEntry->contractid))) {
|
|
|
++ MOZ_CRASH_UNSAFE_PRINTF(
|
|
|
++ "Could not map contract ID '%s' to CID %s because it is already "
|
|
|
++ "mapped to CID %s.",
|
|
|
++ aEntry->contractid, AutoIDString(*aEntry->cid).get(),
|
|
|
++ AutoIDString(module->CID()).get());
|
|
|
++ }
|
|
|
++ }
|
|
|
++#endif
|
|
|
++
|
|
|
++ nsFactoryEntry* f = mFactories.Get(aEntry->cid);
|
|
|
++ if (!f) {
|
|
|
++ NS_WARNING("No CID found when attempting to map contract ID");
|
|
|
++
|
|
|
++ MonitorAutoUnlock unlock(mLock);
|
|
|
++ LogMessage(
|
|
|
++ "Could not map contract ID '%s' to CID %s because no implementation of "
|
|
|
++ "the CID is registered.",
|
|
|
++ aEntry->contractid, AutoIDString(*aEntry->cid).get());
|
|
|
++
|
|
|
++ return;
|
|
|
++ }
|
|
|
++
|
|
|
++ mContractIDs.InsertOrUpdate(AsLiteralCString(aEntry->contractid), f);
|
|
|
++}
|
|
|
++
|
|
|
+ static void DoRegisterManifest(NSLocationType aType, FileLocation& aFile,
|
|
|
+ bool aChromeOnly) {
|
|
|
+ auto result = URLPreloader::Read(aFile);
|
|
|
+ if (result.isOk()) {
|
|
|
+ nsCString buf(result.unwrap());
|
|
|
+ ParseManifest(aType, aFile, buf.BeginWriting(), aChromeOnly);
|
|
|
+ } else if (NS_BOOTSTRAPPED_LOCATION != aType) {
|
|
|
+ nsCString uri;
|
|
|
+@@ -532,33 +688,57 @@ void nsComponentManagerImpl::RereadChrom
|
|
|
+ }
|
|
|
+
|
|
|
+ nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
|
|
+ if (obs) {
|
|
|
+ obs->NotifyObservers(nullptr, "chrome-manifests-loaded", nullptr);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
++bool nsComponentManagerImpl::KnownModule::Load() {
|
|
|
++ if (mFailed) {
|
|
|
++ return false;
|
|
|
++ }
|
|
|
++ MOZ_ASSERT(mModule);
|
|
|
++ if (!mLoaded) {
|
|
|
++ if (mModule->loadProc) {
|
|
|
++ nsresult rv = mModule->loadProc();
|
|
|
++ if (NS_FAILED(rv)) {
|
|
|
++ mFailed = true;
|
|
|
++ return false;
|
|
|
++ }
|
|
|
++ }
|
|
|
++ mLoaded = true;
|
|
|
++ }
|
|
|
++ return true;
|
|
|
++}
|
|
|
++
|
|
|
++nsCString nsComponentManagerImpl::KnownModule::Description() const {
|
|
|
++ return "<static module>"_ns;
|
|
|
++}
|
|
|
++
|
|
|
+ nsresult nsComponentManagerImpl::Shutdown(void) {
|
|
|
+ MOZ_ASSERT(NORMAL == mStatus);
|
|
|
+
|
|
|
+ mStatus = SHUTDOWN_IN_PROGRESS;
|
|
|
+
|
|
|
+ // Shutdown the component manager
|
|
|
+ MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
|
|
|
+ ("nsComponentManager: Beginning Shutdown."));
|
|
|
+
|
|
|
+ UnregisterWeakMemoryReporter(this);
|
|
|
+
|
|
|
+ // Release all cached factories
|
|
|
+ mContractIDs.Clear();
|
|
|
+ mFactories.Clear(); // XXX release the objects, don't just clear
|
|
|
++ mKnownStaticModules.Clear();
|
|
|
+
|
|
|
+ StaticComponents::Shutdown();
|
|
|
+
|
|
|
++ delete sExtraStaticModules;
|
|
|
+ delete sModuleLocations;
|
|
|
+
|
|
|
+ mStatus = SHUTDOWN_COMPLETE;
|
|
|
+
|
|
|
+ MOZ_LOG(nsComponentManagerLog, LogLevel::Debug,
|
|
|
+ ("nsComponentManager: Shutdown complete."));
|
|
|
+
|
|
|
+ return NS_OK;
|
|
|
+@@ -614,17 +794,17 @@ Maybe<EntryWrapper> nsComponentManagerIm
|
|
|
+ if (const StaticModule* module =
|
|
|
+ StaticComponents::LookupByContractID(aContractID)) {
|
|
|
+ return Some(EntryWrapper(module));
|
|
|
+ }
|
|
|
+ if (nsFactoryEntry* entry = mContractIDs.Get(aContractID)) {
|
|
|
+ // UnregisterFactory might have left a stale nsFactoryEntry in
|
|
|
+ // mContractIDs, so we should check to see whether this entry has
|
|
|
+ // anything useful.
|
|
|
+- if (entry->mFactory || entry->mServiceObject) {
|
|
|
++ if (entry->mModule || entry->mFactory || entry->mServiceObject) {
|
|
|
+ return Some(EntryWrapper(entry));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Nothing();
|
|
|
+ }
|
|
|
+
|
|
|
+ already_AddRefed<nsIFactory> nsComponentManagerImpl::FindFactory(
|
|
|
+ const nsCID& aClass) {
|
|
|
+@@ -1197,21 +1377,21 @@ nsComponentManagerImpl::RegisterFactory(
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return NS_ERROR_FACTORY_NOT_REGISTERED;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto f = MakeUnique<nsFactoryEntry>(aClass, aFactory);
|
|
|
+
|
|
|
+ MonitorAutoLock lock(mLock);
|
|
|
+- return mFactories.WithEntryHandle(&f->mCID, [&](auto&& entry) {
|
|
|
++ return mFactories.WithEntryHandle(f->mCIDEntry->cid, [&](auto&& entry) {
|
|
|
+ if (entry) {
|
|
|
+ return NS_ERROR_FACTORY_EXISTS;
|
|
|
+ }
|
|
|
+- if (StaticComponents::LookupByCID(f->mCID)) {
|
|
|
++ if (StaticComponents::LookupByCID(*f->mCIDEntry->cid)) {
|
|
|
+ return NS_ERROR_FACTORY_EXISTS;
|
|
|
+ }
|
|
|
+ if (aContractID) {
|
|
|
+ nsDependentCString contractID(aContractID);
|
|
|
+ mContractIDs.InsertOrUpdate(contractID, f.get());
|
|
|
+ // We allow dynamically-registered contract IDs to override static
|
|
|
+ // entries, so invalidate any static entry for this contract ID.
|
|
|
+ StaticComponents::InvalidateContractID(contractID);
|
|
|
+@@ -1356,57 +1536,112 @@ size_t nsComponentManagerImpl::SizeOfInc
|
|
|
+
|
|
|
+ n += mContractIDs.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
|
|
+ for (const auto& key : mContractIDs.Keys()) {
|
|
|
+ // We don't measure the nsFactoryEntry data because it's owned by
|
|
|
+ // mFactories (which is measured above).
|
|
|
+ n += key.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
|
|
+ }
|
|
|
+
|
|
|
++ n += sExtraStaticModules->ShallowSizeOfIncludingThis(aMallocSizeOf);
|
|
|
+ if (sModuleLocations) {
|
|
|
+ n += sModuleLocations->ShallowSizeOfIncludingThis(aMallocSizeOf);
|
|
|
+ }
|
|
|
+
|
|
|
++ n += mKnownStaticModules.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
|
|
++
|
|
|
+ n += mPendingServices.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
|
|
+
|
|
|
+ // Measurement of the following members may be added later if DMD finds it is
|
|
|
+ // worthwhile:
|
|
|
+ // - mMon
|
|
|
+ // - sModuleLocations' entries
|
|
|
++ // - mKnownStaticModules' entries?
|
|
|
+
|
|
|
+ return n;
|
|
|
+ }
|
|
|
+
|
|
|
+ ////////////////////////////////////////////////////////////////////////////////
|
|
|
+ // nsFactoryEntry
|
|
|
+ ////////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
++nsFactoryEntry::nsFactoryEntry(const mozilla::Module::CIDEntry* aEntry,
|
|
|
++ nsComponentManagerImpl::KnownModule* aModule)
|
|
|
++ : mCIDEntry(aEntry), mModule(aModule) {}
|
|
|
++
|
|
|
+ nsFactoryEntry::nsFactoryEntry(const nsCID& aCID, nsIFactory* aFactory)
|
|
|
+- : mCID(aCID), mFactory(aFactory) {
|
|
|
++ : mCIDEntry(nullptr), mModule(nullptr), mFactory(aFactory) {
|
|
|
++ auto* e = new mozilla::Module::CIDEntry();
|
|
|
++ auto* cid = new nsCID;
|
|
|
++ *cid = aCID;
|
|
|
++ e->cid = cid;
|
|
|
++ mCIDEntry = e;
|
|
|
++}
|
|
|
++
|
|
|
++nsFactoryEntry::~nsFactoryEntry() {
|
|
|
++ // If this was a RegisterFactory entry, we own the CIDEntry/CID
|
|
|
++ if (!mModule) {
|
|
|
++ delete mCIDEntry->cid;
|
|
|
++ delete mCIDEntry;
|
|
|
++ }
|
|
|
+ }
|
|
|
+
|
|
|
+ already_AddRefed<nsIFactory> nsFactoryEntry::GetFactory() {
|
|
|
+ nsComponentManagerImpl::gComponentManager->mLock.AssertNotCurrentThreadOwns();
|
|
|
+
|
|
|
++ if (!mFactory) {
|
|
|
++ // RegisterFactory then UnregisterFactory can leave an entry in mContractIDs
|
|
|
++ // pointing to an unusable nsFactoryEntry.
|
|
|
++ if (!mModule) {
|
|
|
++ return nullptr;
|
|
|
++ }
|
|
|
++
|
|
|
++ if (!mModule->Load()) {
|
|
|
++ return nullptr;
|
|
|
++ }
|
|
|
++
|
|
|
++ // Don't set mFactory directly, it needs to be locked
|
|
|
++ nsCOMPtr<nsIFactory> factory;
|
|
|
++
|
|
|
++ if (mModule->Module()->getFactoryProc) {
|
|
|
++ factory =
|
|
|
++ mModule->Module()->getFactoryProc(*mModule->Module(), *mCIDEntry);
|
|
|
++ } else if (mCIDEntry->getFactoryProc) {
|
|
|
++ factory = mCIDEntry->getFactoryProc(*mModule->Module(), *mCIDEntry);
|
|
|
++ } else {
|
|
|
++ NS_ASSERTION(mCIDEntry->constructorProc, "no getfactory or constructor");
|
|
|
++ factory = new mozilla::GenericFactory(mCIDEntry->constructorProc);
|
|
|
++ }
|
|
|
++ if (!factory) {
|
|
|
++ return nullptr;
|
|
|
++ }
|
|
|
++
|
|
|
++ MonitorAutoLock lock(nsComponentManagerImpl::gComponentManager->mLock);
|
|
|
++ // Threads can race to set mFactory
|
|
|
++ if (!mFactory) {
|
|
|
++ factory.swap(mFactory);
|
|
|
++ }
|
|
|
++ }
|
|
|
+ nsCOMPtr<nsIFactory> factory = mFactory;
|
|
|
+ return factory.forget();
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult nsFactoryEntry::CreateInstance(const nsIID& aIID, void** aResult) {
|
|
|
+ nsCOMPtr<nsIFactory> factory = GetFactory();
|
|
|
+ NS_ENSURE_TRUE(factory, NS_ERROR_FAILURE);
|
|
|
+ return factory->CreateInstance(aIID, aResult);
|
|
|
+ }
|
|
|
+
|
|
|
+ size_t nsFactoryEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
|
|
|
+ size_t n = aMallocSizeOf(this);
|
|
|
+
|
|
|
+ // Measurement of the following members may be added later if DMD finds it is
|
|
|
+ // worthwhile:
|
|
|
+- // - mCID;
|
|
|
++ // - mCIDEntry;
|
|
|
++ // - mModule;
|
|
|
+ // - mFactory;
|
|
|
+ // - mServiceObject;
|
|
|
+
|
|
|
+ return n;
|
|
|
+ }
|
|
|
+
|
|
|
+ ////////////////////////////////////////////////////////////////////////////////
|
|
|
+ // Static Access Functions
|
|
|
+@@ -1434,16 +1669,30 @@ nsresult NS_GetComponentRegistrar(nsICom
|
|
|
+ if (!nsComponentManagerImpl::gComponentManager) {
|
|
|
+ return NS_ERROR_NOT_INITIALIZED;
|
|
|
+ }
|
|
|
+
|
|
|
+ NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
++EXPORT_XPCOM_API(nsresult)
|
|
|
++XRE_AddStaticComponent(const mozilla::Module* aComponent) {
|
|
|
++ nsComponentManagerImpl::InitializeStaticModules();
|
|
|
++ sExtraStaticModules->AppendElement(aComponent);
|
|
|
++
|
|
|
++ if (nsComponentManagerImpl::gComponentManager &&
|
|
|
++ nsComponentManagerImpl::NORMAL ==
|
|
|
++ nsComponentManagerImpl::gComponentManager->mStatus) {
|
|
|
++ nsComponentManagerImpl::gComponentManager->RegisterModule(aComponent);
|
|
|
++ }
|
|
|
++
|
|
|
++ return NS_OK;
|
|
|
++}
|
|
|
++
|
|
|
+ NS_IMETHODIMP
|
|
|
+ nsComponentManagerImpl::AddBootstrappedManifestLocation(nsIFile* aLocation) {
|
|
|
+ NS_ENSURE_ARG_POINTER(aLocation);
|
|
|
+
|
|
|
+ nsString path;
|
|
|
+ nsresult rv = aLocation->GetPath(path);
|
|
|
+ if (NS_FAILED(rv)) {
|
|
|
+ return rv;
|
|
|
+diff --git a/xpcom/components/nsComponentManager.h b/xpcom/components/nsComponentManager.h
|
|
|
+--- a/xpcom/components/nsComponentManager.h
|
|
|
++++ b/xpcom/components/nsComponentManager.h
|
|
|
+@@ -132,16 +132,58 @@ class nsComponentManagerImpl final : pub
|
|
|
+ bool Equals(const ComponentLocation& aA,
|
|
|
+ const ComponentLocation& aB) const {
|
|
|
+ return (aA.type == aB.type && aA.location.Equals(aB.location));
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ static nsTArray<ComponentLocation>* sModuleLocations;
|
|
|
+
|
|
|
++ class KnownModule {
|
|
|
++ public:
|
|
|
++ /**
|
|
|
++ * Static or binary module.
|
|
|
++ */
|
|
|
++ explicit KnownModule(const mozilla::Module* aModule)
|
|
|
++ : mModule(aModule), mLoaded(false), mFailed(false) {}
|
|
|
++
|
|
|
++ ~KnownModule() {
|
|
|
++ if (mLoaded && mModule->unloadProc) {
|
|
|
++ mModule->unloadProc();
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
++ bool Load();
|
|
|
++
|
|
|
++ const mozilla::Module* Module() const { return mModule; }
|
|
|
++
|
|
|
++ /**
|
|
|
++ * For error logging, get a description of this module, either the
|
|
|
++ * file path, or <static module>.
|
|
|
++ */
|
|
|
++ nsCString Description() const;
|
|
|
++
|
|
|
++ private:
|
|
|
++ const mozilla::Module* mModule;
|
|
|
++ bool mLoaded;
|
|
|
++ bool mFailed;
|
|
|
++ };
|
|
|
++
|
|
|
++ // The KnownModule is kept alive by these members, it is
|
|
|
++ // referenced by pointer from the factory entries.
|
|
|
++ nsTArray<mozilla::UniquePtr<KnownModule>> mKnownStaticModules;
|
|
|
++
|
|
|
++ // Mutex not held
|
|
|
++ void RegisterModule(const mozilla::Module* aModule);
|
|
|
++
|
|
|
++ // Mutex held
|
|
|
++ void RegisterCIDEntryLocked(const mozilla::Module::CIDEntry* aEntry,
|
|
|
++ KnownModule* aModule);
|
|
|
++ void RegisterContractIDLocked(const mozilla::Module::ContractIDEntry* aEntry);
|
|
|
++
|
|
|
+ // Mutex not held
|
|
|
+ void RegisterManifest(NSLocationType aType, mozilla::FileLocation& aFile,
|
|
|
+ bool aChromeOnly);
|
|
|
+
|
|
|
+ struct ManifestProcessingContext {
|
|
|
+ ManifestProcessingContext(NSLocationType aType,
|
|
|
+ mozilla::FileLocation& aFile, bool aChromeOnly)
|
|
|
+ : mType(aType), mFile(aFile), mChromeOnly(aChromeOnly) {}
|
|
|
+@@ -193,26 +235,30 @@ class nsComponentManagerImpl final : pub
|
|
|
+ void** aResult);
|
|
|
+ };
|
|
|
+
|
|
|
+ #define NS_MAX_FILENAME_LEN 1024
|
|
|
+
|
|
|
+ #define NS_ERROR_IS_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 24)
|
|
|
+
|
|
|
+ struct nsFactoryEntry {
|
|
|
++ nsFactoryEntry(const mozilla::Module::CIDEntry* aEntry,
|
|
|
++ nsComponentManagerImpl::KnownModule* aModule);
|
|
|
++
|
|
|
+ // nsIComponentRegistrar.registerFactory support
|
|
|
+ nsFactoryEntry(const nsCID& aClass, nsIFactory* aFactory);
|
|
|
+
|
|
|
+- ~nsFactoryEntry() = default;
|
|
|
++ ~nsFactoryEntry();
|
|
|
+
|
|
|
+ already_AddRefed<nsIFactory> GetFactory();
|
|
|
+
|
|
|
+ nsresult CreateInstance(const nsIID& aIID, void** aResult);
|
|
|
+
|
|
|
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
|
|
|
+
|
|
|
+- const nsCID mCID;
|
|
|
++ const mozilla::Module::CIDEntry* mCIDEntry;
|
|
|
++ nsComponentManagerImpl::KnownModule* mModule;
|
|
|
+
|
|
|
+ nsCOMPtr<nsIFactory> mFactory;
|
|
|
+ nsCOMPtr<nsISupports> mServiceObject;
|
|
|
+ };
|
|
|
+
|
|
|
+ #endif // nsComponentManager_h__
|