summaryrefslogtreecommitdiffstats
path: root/xpcom/build/XPCOMInit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/build/XPCOMInit.cpp')
-rw-r--r--xpcom/build/XPCOMInit.cpp790
1 files changed, 790 insertions, 0 deletions
diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp
new file mode 100644
index 0000000000..cd6c7f7052
--- /dev/null
+++ b/xpcom/build/XPCOMInit.cpp
@@ -0,0 +1,790 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "ThreadEventTarget.h"
+#include "XPCOMModule.h"
+
+#include "base/basictypes.h"
+
+#include "mozilla/AbstractThread.h"
+#include "mozilla/AppShutdown.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/Poison.h"
+#include "mozilla/SharedThreadPool.h"
+#include "mozilla/TaskController.h"
+#include "mozilla/Unused.h"
+#include "mozilla/XPCOM.h"
+#include "mozJSModuleLoader.h"
+#include "nsXULAppAPI.h"
+
+#ifndef ANDROID
+# include "nsTerminator.h"
+#endif
+
+#include "nsXPCOMPrivate.h"
+#include "nsXPCOMCIDInternal.h"
+
+#include "mozilla/dom/JSExecutionManager.h"
+#include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
+
+#include "prlink.h"
+
+#include "nsCycleCollector.h"
+#include "nsObserverService.h"
+
+#include "nsDebugImpl.h"
+#include "nsSystemInfo.h"
+
+#include "nsComponentManager.h"
+#include "nsCategoryManagerUtils.h"
+#include "nsIServiceManager.h"
+
+#include "nsThreadManager.h"
+#include "nsThreadPool.h"
+
+#include "nsTimerImpl.h"
+#include "TimerThread.h"
+
+#include "nsThread.h"
+#include "nsVersionComparatorImpl.h"
+
+#include "nsIFile.h"
+#include "nsLocalFile.h"
+#include "nsDirectoryService.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsCategoryManager.h"
+#include "nsMultiplexInputStream.h"
+
+#include "nsAtomTable.h"
+#include "nsISupportsImpl.h"
+
+#include "nsSystemInfo.h"
+#include "nsMemoryReporterManager.h"
+#include "nsMessageLoop.h"
+#include "nss.h"
+#include "nsNSSComponent.h"
+
+#include <locale.h>
+#include "mozilla/Services.h"
+#include "mozilla/Omnijar.h"
+#include "mozilla/ScriptPreloader.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/BackgroundHangMonitor.h"
+
+#include "mozilla/PoisonIOInterposer.h"
+#include "mozilla/LateWriteChecks.h"
+
+#include "mozilla/scache/StartupCache.h"
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/message_loop.h"
+
+#include "mozilla/ipc/BrowserProcessSubThread.h"
+#include "mozilla/AvailableMemoryTracker.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/CountingAllocatorBase.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/ServoStyleConsts.h"
+
+#include "mozilla/ipc/GeckoChildProcessHost.h"
+
+#include "ogg/ogg.h"
+
+#include "GeckoProfiler.h"
+#include "ProfilerControl.h"
+
+#include "jsapi.h"
+#include "js/Initialization.h"
+#include "mozilla/StaticPrefs_javascript.h"
+#include "XPCSelfHostedShmem.h"
+
+#include "gfxPlatform.h"
+
+using base::AtExitManager;
+using mozilla::ipc::BrowserProcessSubThread;
+
+// From toolkit/library/rust/lib.rs
+extern "C" void GkRust_Init();
+extern "C" void GkRust_Shutdown();
+
+namespace {
+
+static AtExitManager* sExitManager;
+static MessageLoop* sMessageLoop;
+static bool sCommandLineWasInitialized;
+static BrowserProcessSubThread* sIOThread;
+static mozilla::BackgroundHangMonitor* sMainHangMonitor;
+
+} /* anonymous namespace */
+
+// Registry Factory creation function defined in nsRegistry.cpp
+// We hook into this function locally to create and register the registry
+// Since noone outside xpcom needs to know about this and nsRegistry.cpp
+// does not have a local include file, we are putting this definition
+// here rather than in nsIRegistry.h
+extern nsresult NS_RegistryGetFactory(nsIFactory** aFactory);
+extern nsresult NS_CategoryManagerGetFactory(nsIFactory**);
+
+#ifdef XP_WIN
+extern nsresult CreateAnonTempFileRemover();
+#endif
+
+nsresult nsThreadManagerGetSingleton(const nsIID& aIID, void** aInstancePtr) {
+ NS_ASSERTION(aInstancePtr, "null outptr");
+ return nsThreadManager::get().QueryInterface(aIID, aInstancePtr);
+}
+
+nsresult nsLocalFileConstructor(const nsIID& aIID, void** aInstancePtr) {
+ return nsLocalFile::nsLocalFileConstructor(aIID, aInstancePtr);
+}
+
+nsComponentManagerImpl* nsComponentManagerImpl::gComponentManager = nullptr;
+bool gXPCOMShuttingDown = false;
+bool gXPCOMMainThreadEventsAreDoomed = false;
+char16_t* gGREBinPath = nullptr;
+
+// gDebug will be freed during shutdown.
+static nsIDebug2* gDebug = nullptr;
+
+EXPORT_XPCOM_API(nsresult)
+NS_GetDebug(nsIDebug2** aResult) {
+ return nsDebugImpl::Create(NS_GET_IID(nsIDebug2), (void**)aResult);
+}
+
+class ICUReporter final : public nsIMemoryReporter,
+ public mozilla::CountingAllocatorBase<ICUReporter> {
+ public:
+ NS_DECL_ISUPPORTS
+
+ static void* Alloc(const void*, size_t aSize) {
+ return CountingMalloc(aSize);
+ }
+
+ static void* Realloc(const void*, void* aPtr, size_t aSize) {
+ return CountingRealloc(aPtr, aSize);
+ }
+
+ static void Free(const void*, void* aPtr) { return CountingFree(aPtr); }
+
+ private:
+ NS_IMETHOD
+ CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
+ bool aAnonymize) override {
+ MOZ_COLLECT_REPORT(
+ "explicit/icu", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
+ "Memory used by ICU, a Unicode and globalization support library.");
+
+ return NS_OK;
+ }
+
+ ~ICUReporter() = default;
+};
+
+NS_IMPL_ISUPPORTS(ICUReporter, nsIMemoryReporter)
+
+class OggReporter final : public nsIMemoryReporter,
+ public mozilla::CountingAllocatorBase<OggReporter> {
+ public:
+ NS_DECL_ISUPPORTS
+
+ private:
+ NS_IMETHOD
+ CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
+ bool aAnonymize) override {
+ MOZ_COLLECT_REPORT(
+ "explicit/media/libogg", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
+ "Memory allocated through libogg for Ogg, Theora, and related media "
+ "files.");
+
+ return NS_OK;
+ }
+
+ ~OggReporter() = default;
+};
+
+NS_IMPL_ISUPPORTS(OggReporter, nsIMemoryReporter)
+
+static bool sInitializedJS = false;
+
+static void InitializeJS() {
+#if defined(ENABLE_WASM_SIMD) && \
+ (defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86))
+ // Update static engine preferences, such as AVX, before
+ // `JS_InitWithFailureDiagnostic` is called.
+ JS::SetAVXEnabled(mozilla::StaticPrefs::javascript_options_wasm_simd_avx());
+#endif
+
+ const char* jsInitFailureReason = JS_InitWithFailureDiagnostic();
+ if (jsInitFailureReason) {
+ MOZ_CRASH_UNSAFE(jsInitFailureReason);
+ }
+}
+
+// Note that on OSX, aBinDirectory will point to .app/Contents/Resources/browser
+EXPORT_XPCOM_API(nsresult)
+NS_InitXPCOM(nsIServiceManager** aResult, nsIFile* aBinDirectory,
+ nsIDirectoryServiceProvider* aAppFileLocationProvider,
+ bool aInitJSContext) {
+ static bool sInitialized = false;
+ if (sInitialized) {
+ return NS_ERROR_FAILURE;
+ }
+
+ sInitialized = true;
+
+ NS_LogInit();
+
+ NS_InitAtomTable();
+
+ // We don't have the arguments by hand here. If logging has already been
+ // initialized by a previous call to LogModule::Init with the arguments
+ // passed, passing (0, nullptr) is alright here.
+ mozilla::LogModule::Init(0, nullptr);
+
+ GkRust_Init();
+
+ nsresult rv = NS_OK;
+
+ // We are not shutting down
+ gXPCOMShuttingDown = false;
+
+#ifdef XP_UNIX
+ // Discover the current value of the umask, and save it where
+ // nsSystemInfo::Init can retrieve it when necessary. There is no way
+ // to read the umask without changing it, and the setting is process-
+ // global, so this must be done while we are still single-threaded; the
+ // nsSystemInfo object is typically created much later, when some piece
+ // of chrome JS wants it. The system call is specified as unable to fail.
+ nsSystemInfo::gUserUmask = ::umask(0777);
+ ::umask(nsSystemInfo::gUserUmask);
+#endif
+
+ // Set up chromium libs
+ NS_ASSERTION(!sExitManager && !sMessageLoop, "Bad logic!");
+
+ if (!AtExitManager::AlreadyRegistered()) {
+ sExitManager = new AtExitManager();
+ }
+
+ MessageLoop* messageLoop = MessageLoop::current();
+ if (!messageLoop) {
+ sMessageLoop = new MessageLoopForUI(MessageLoop::TYPE_MOZILLA_PARENT);
+ sMessageLoop->set_thread_name("Gecko");
+ // Set experimental values for main thread hangs:
+ // 128ms for transient hangs and 8192ms for permanent hangs
+ sMessageLoop->set_hang_timeouts(128, 8192);
+ } else if (messageLoop->type() == MessageLoop::TYPE_MOZILLA_CHILD) {
+ messageLoop->set_thread_name("Gecko_Child");
+ messageLoop->set_hang_timeouts(128, 8192);
+ }
+
+ if (XRE_IsParentProcess() &&
+ !BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO)) {
+ mozilla::UniquePtr<BrowserProcessSubThread> ioThread =
+ mozilla::MakeUnique<BrowserProcessSubThread>(
+ BrowserProcessSubThread::IO);
+
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_IO;
+ if (NS_WARN_IF(!ioThread->StartWithOptions(options))) {
+ return NS_ERROR_FAILURE;
+ }
+
+ sIOThread = ioThread.release();
+ }
+
+ // Establish the main thread here.
+ rv = nsThreadManager::get().Init();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ AUTO_PROFILER_INIT2;
+
+ // Set up the timer globals/timer thread
+ rv = nsTimerImpl::Startup();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+#ifndef ANDROID
+ // If the locale hasn't already been setup by our embedder,
+ // get us out of the "C" locale and into the system
+ if (strcmp(setlocale(LC_ALL, nullptr), "C") == 0) {
+ setlocale(LC_ALL, "");
+ }
+#endif
+
+ nsDirectoryService::RealInit();
+
+ bool value;
+
+ if (aBinDirectory) {
+ rv = aBinDirectory->IsDirectory(&value);
+
+ if (NS_SUCCEEDED(rv) && value) {
+ nsDirectoryService::gService->SetCurrentProcessDirectory(aBinDirectory);
+ }
+ }
+
+ if (aAppFileLocationProvider) {
+ rv = nsDirectoryService::gService->RegisterProvider(
+ aAppFileLocationProvider);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+
+ nsCOMPtr<nsIFile> xpcomLib;
+ nsDirectoryService::gService->Get(NS_GRE_BIN_DIR, NS_GET_IID(nsIFile),
+ getter_AddRefs(xpcomLib));
+ MOZ_ASSERT(xpcomLib);
+
+ // set gGREBinPath
+ nsAutoString path;
+ xpcomLib->GetPath(path);
+ gGREBinPath = ToNewUnicode(path);
+
+ xpcomLib->AppendNative(nsDependentCString(XPCOM_DLL));
+ nsDirectoryService::gService->Set(NS_XPCOM_LIBRARY_FILE, xpcomLib);
+
+ if (!mozilla::Omnijar::IsInitialized()) {
+ mozilla::Omnijar::Init();
+ }
+
+ if ((sCommandLineWasInitialized = !CommandLine::IsInitialized())) {
+#ifdef OS_WIN
+ CommandLine::Init(0, nullptr);
+#else
+ nsCOMPtr<nsIFile> binaryFile;
+ nsDirectoryService::gService->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
+ NS_GET_IID(nsIFile),
+ getter_AddRefs(binaryFile));
+ if (NS_WARN_IF(!binaryFile)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ rv = binaryFile->AppendNative("nonexistent-executable"_ns);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ nsCString binaryPath;
+ rv = binaryFile->GetNativePath(binaryPath);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ static char const* const argv = {strdup(binaryPath.get())};
+ CommandLine::Init(1, &argv);
+#endif
+ }
+
+ NS_ASSERTION(nsComponentManagerImpl::gComponentManager == nullptr,
+ "CompMgr not null at init");
+
+ // Create the Component/Service Manager
+ nsComponentManagerImpl::gComponentManager = new nsComponentManagerImpl();
+ NS_ADDREF(nsComponentManagerImpl::gComponentManager);
+
+ // Global cycle collector initialization.
+ if (!nsCycleCollector_init()) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ // And start it up for this thread too.
+ nsCycleCollector_startup();
+
+ // Register ICU memory functions. This really shouldn't be necessary: the
+ // JS engine should do this on its own inside JS_Init, and memory-reporting
+ // code should call a JSAPI function to observe ICU memory usage. But we
+ // can't define the alloc/free functions in the JS engine, because it can't
+ // depend on the XPCOM-based memory reporting goop. So for now, we have
+ // this oddness.
+ mozilla::SetICUMemoryFunctions();
+
+ // Do the same for libogg.
+ ogg_set_mem_functions(
+ OggReporter::CountingMalloc, OggReporter::CountingCalloc,
+ OggReporter::CountingRealloc, OggReporter::CountingFree);
+
+ // Initialize the JS engine.
+ InitializeJS();
+ sInitializedJS = true;
+
+ rv = nsComponentManagerImpl::gComponentManager->Init();
+ if (NS_FAILED(rv)) {
+ NS_RELEASE(nsComponentManagerImpl::gComponentManager);
+ return rv;
+ }
+
+ if (aResult) {
+ NS_ADDREF(*aResult = nsComponentManagerImpl::gComponentManager);
+ }
+
+ // After autoreg, but before we actually instantiate any components,
+ // add any services listed in the "xpcom-directory-providers" category
+ // to the directory service.
+ nsDirectoryService::gService->RegisterCategoryProviders();
+
+ // Init mozilla::SharedThreadPool (which needs the service manager).
+ mozilla::SharedThreadPool::InitStatics();
+
+ mozilla::scache::StartupCache::GetSingleton();
+ mozilla::AvailableMemoryTracker::Init();
+
+ // Notify observers of xpcom autoregistration start
+ NS_CreateServicesFromCategory(NS_XPCOM_STARTUP_CATEGORY, nullptr,
+ NS_XPCOM_STARTUP_OBSERVER_ID);
+#ifdef XP_WIN
+ CreateAnonTempFileRemover();
+#endif
+
+ // The memory reporter manager is up and running -- register our reporters.
+ RegisterStrongMemoryReporter(new ICUReporter());
+ RegisterStrongMemoryReporter(new OggReporter());
+ xpc::SelfHostedShmem::GetSingleton().InitMemoryReporter();
+
+ mozilla::Telemetry::Init();
+
+ mozilla::BackgroundHangMonitor::Startup();
+
+ const MessageLoop* const loop = MessageLoop::current();
+ sMainHangMonitor = new mozilla::BackgroundHangMonitor(
+ loop->thread_name().c_str(), loop->transient_hang_timeout(),
+ loop->permanent_hang_timeout());
+
+ mozilla::dom::JSExecutionManager::Initialize();
+
+ if (aInitJSContext) {
+ xpc::InitializeJSContext();
+ }
+
+ return NS_OK;
+}
+
+EXPORT_XPCOM_API(nsresult)
+NS_InitMinimalXPCOM() {
+ NS_SetMainThread();
+ mozilla::TimeStamp::Startup();
+ NS_LogInit();
+ NS_InitAtomTable();
+
+ // We don't have the arguments by hand here. If logging has already been
+ // initialized by a previous call to LogModule::Init with the arguments
+ // passed, passing (0, nullptr) is alright here.
+ mozilla::LogModule::Init(0, nullptr);
+
+ GkRust_Init();
+
+ nsresult rv = nsThreadManager::get().Init();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ // Set up the timer globals/timer thread.
+ rv = nsTimerImpl::Startup();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ // Create the Component/Service Manager
+ nsComponentManagerImpl::gComponentManager = new nsComponentManagerImpl();
+ NS_ADDREF(nsComponentManagerImpl::gComponentManager);
+
+ rv = nsComponentManagerImpl::gComponentManager->Init();
+ if (NS_FAILED(rv)) {
+ NS_RELEASE(nsComponentManagerImpl::gComponentManager);
+ return rv;
+ }
+
+ // Global cycle collector initialization.
+ if (!nsCycleCollector_init()) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ mozilla::SharedThreadPool::InitStatics();
+ mozilla::Telemetry::Init();
+ mozilla::BackgroundHangMonitor::Startup();
+
+ return NS_OK;
+}
+
+//
+// NS_ShutdownXPCOM()
+//
+// The shutdown sequence for xpcom would be
+//
+// - Notify "xpcom-shutdown" for modules to release primary (root) references
+// - Shutdown XPCOM timers
+// - Notify "xpcom-shutdown-threads" for thread joins
+// - Shutdown the event queues
+// - Release the Global Service Manager
+// - Release all service instances held by the global service manager
+// - Release the Global Service Manager itself
+// - Release the Component Manager
+// - Release all factories cached by the Component Manager
+// - Notify module loaders to shut down
+// - Unload Libraries
+// - Release Contractid Cache held by Component Manager
+// - Release dll abstraction held by Component Manager
+// - Release the Registry held by Component Manager
+// - Finally, release the component manager itself
+//
+EXPORT_XPCOM_API(nsresult)
+NS_ShutdownXPCOM(nsIServiceManager* aServMgr) {
+ return mozilla::ShutdownXPCOM(aServMgr);
+}
+
+namespace mozilla {
+
+void SetICUMemoryFunctions() {
+ static bool sICUReporterInitialized = false;
+ if (!sICUReporterInitialized) {
+ if (!JS_SetICUMemoryFunctions(ICUReporter::Alloc, ICUReporter::Realloc,
+ ICUReporter::Free)) {
+ MOZ_CRASH("JS_SetICUMemoryFunctions failed.");
+ }
+ sICUReporterInitialized = true;
+ }
+}
+
+nsresult ShutdownXPCOM(nsIServiceManager* aServMgr) {
+ // Make sure the hang monitor is enabled for shutdown.
+ BackgroundHangMonitor().NotifyActivity();
+
+ if (!NS_IsMainThread()) {
+ MOZ_CRASH("Shutdown on wrong thread");
+ }
+
+ // Notify observers of xpcom shutting down
+ {
+ // Block it so that the COMPtr will get deleted before we hit
+ // servicemanager shutdown
+
+ nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
+ if (NS_WARN_IF(!thread)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ mozilla::AppShutdown::AdvanceShutdownPhase(
+ mozilla::ShutdownPhase::XPCOMWillShutdown);
+
+ // We want the service manager to be the subject of notifications
+ nsCOMPtr<nsIServiceManager> mgr;
+ Unused << NS_GetServiceManager(getter_AddRefs(mgr));
+ MOZ_DIAGNOSTIC_ASSERT(mgr != nullptr, "Service manager not present!");
+ mozilla::AppShutdown::AdvanceShutdownPhase(
+ mozilla::ShutdownPhase::XPCOMShutdown, nullptr, do_QueryInterface(mgr));
+
+ // This must happen after the shutdown of media and widgets, which
+ // are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification.
+ gfxPlatform::ShutdownLayersIPC();
+
+ mozilla::AppShutdown::AdvanceShutdownPhase(
+ mozilla::ShutdownPhase::XPCOMShutdownThreads);
+#ifdef DEBUG
+ // Prime an assertion at ThreadEventTarget::Dispatch to avoid late
+ // dispatches to non main-thread threads.
+ ThreadEventTarget::XPCOMShutdownThreadsNotificationFinished();
+#endif
+
+ // Shutdown the timer thread and all timers that might still be alive
+ nsTimerImpl::Shutdown();
+
+ // Have an extra round of processing after the timers went away.
+ NS_ProcessPendingEvents(thread);
+
+ // Shutdown all remaining threads. This method does not return until
+ // all threads created using the thread manager (with the exception of
+ // the main thread) have exited.
+ nsThreadManager::get().ShutdownNonMainThreads();
+
+ RefPtr<nsObserverService> observerService;
+ CallGetService("@mozilla.org/observer-service;1",
+ (nsObserverService**)getter_AddRefs(observerService));
+ if (observerService) {
+ observerService->Shutdown();
+ }
+
+ // XPCOMShutdownFinal is the default phase for ClearOnShutdown.
+ // This AdvanceShutdownPhase will thus free most ClearOnShutdown()'ed
+ // smart pointers. Some destructors may fire extra main thread runnables
+ // that will be processed inside AdvanceShutdownPhase.
+ AppShutdown::AdvanceShutdownPhase(ShutdownPhase::XPCOMShutdownFinal);
+
+ // Shutdown the main thread, processing our very last round of events, and
+ // then mark that we've finished main thread event processing.
+ nsThreadManager::get().ShutdownMainThread();
+ gXPCOMMainThreadEventsAreDoomed = true;
+
+ BackgroundHangMonitor().NotifyActivity();
+
+ mozilla::dom::JSExecutionManager::Shutdown();
+ }
+
+ // XPCOM is officially in shutdown mode NOW
+ // Set this only after the observers have been notified as this
+ // will cause servicemanager to become inaccessible.
+ mozilla::services::Shutdown();
+
+ // We may have AddRef'd for the caller of NS_InitXPCOM, so release it
+ // here again:
+ NS_IF_RELEASE(aServMgr);
+
+ // Shutdown global servicemanager
+ if (nsComponentManagerImpl::gComponentManager) {
+ nsComponentManagerImpl::gComponentManager->FreeServices();
+ }
+
+ // Remove the remaining main thread representations
+ nsThreadManager::get().ReleaseMainThread();
+ AbstractThread::ShutdownMainThread();
+
+ // Release the directory service
+ nsDirectoryService::gService = nullptr;
+
+ free(gGREBinPath);
+ gGREBinPath = nullptr;
+
+ // FIXME: This can cause harmless writes from sqlite committing
+ // log files. We have to ignore them before we can move
+ // the mozilla::PoisonWrite call before this point. See bug
+ // 834945 for the details.
+ mozJSModuleLoader::UnloadLoaders();
+
+ // Clear the profiler's JS context before cycle collection. The profiler will
+ // notify the JS engine that it can let go of any data it's holding on to for
+ // profiling purposes.
+ PROFILER_CLEAR_JS_CONTEXT();
+
+ bool shutdownCollect;
+#ifdef NS_FREE_PERMANENT_DATA
+ shutdownCollect = true;
+#else
+ shutdownCollect = !!PR_GetEnv("MOZ_CC_RUN_DURING_SHUTDOWN");
+#endif
+ nsCycleCollector_shutdown(shutdownCollect);
+
+ // There can be code trying to refer to global objects during the final cc
+ // shutdown. This is the phase for such global objects to correctly release.
+ AppShutdown::AdvanceShutdownPhase(ShutdownPhase::CCPostLastCycleCollection);
+
+ mozilla::scache::StartupCache::DeleteSingleton();
+ mozilla::ScriptPreloader::DeleteSingleton();
+
+ PROFILER_MARKER_UNTYPED("Shutdown xpcom", OTHER);
+
+ // Shutdown xpcom. This will release all loaders and cause others holding
+ // a refcount to the component manager to release it.
+ if (nsComponentManagerImpl::gComponentManager) {
+ DebugOnly<nsresult> rv =
+ (nsComponentManagerImpl::gComponentManager)->Shutdown();
+ NS_ASSERTION(NS_SUCCEEDED(rv.value), "Component Manager shutdown failed.");
+ } else {
+ NS_WARNING("Component Manager was never created ...");
+ }
+
+ if (sInitializedJS) {
+ // Shut down the JS engine.
+ JS_ShutDown();
+ sInitializedJS = false;
+ }
+
+ mozilla::ScriptPreloader::DeleteCacheDataSingleton();
+
+ // Release shared memory which might be borrowed by the JS engine.
+ xpc::SelfHostedShmem::Shutdown();
+
+ // After all threads have been joined and the component manager has been shut
+ // down, any remaining objects that could be holding NSS resources (should)
+ // have been released, so we can safely shut down NSS.
+ if (NSS_IsInitialized()) {
+ nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();
+ if (NSS_Shutdown() != SECSuccess) {
+ // If you're seeing this crash and/or warning, some NSS resources are
+ // still in use (see bugs 1417680 and 1230312). Set the environment
+ // variable 'MOZ_IGNORE_NSS_SHUTDOWN_LEAKS' to some value to ignore this.
+ // Also, if leak checking is enabled, report this as a fake leak instead
+ // of crashing.
+#if defined(DEBUG) && !defined(ANDROID)
+ if (!getenv("MOZ_IGNORE_NSS_SHUTDOWN_LEAKS") &&
+ !getenv("XPCOM_MEM_BLOAT_LOG") && !getenv("XPCOM_MEM_LEAK_LOG") &&
+ !getenv("XPCOM_MEM_REFCNT_LOG") && !getenv("XPCOM_MEM_COMPTR_LOG")) {
+ MOZ_CRASH("NSS_Shutdown failed");
+ } else {
+# ifdef NS_BUILD_REFCNT_LOGGING
+ // Create a fake leak.
+ NS_LogCtor((void*)0x100, "NSSShutdownFailed", 100);
+# endif // NS_BUILD_REFCNT_LOGGING
+ NS_WARNING("NSS_Shutdown failed");
+ }
+#else
+ NS_WARNING("NSS_Shutdown failed");
+#endif // defined(DEBUG) && !defined(ANDROID)
+ }
+ }
+
+ // Finally, release the component manager last because it unloads the
+ // libraries:
+ if (nsComponentManagerImpl::gComponentManager) {
+ nsrefcnt cnt;
+ NS_RELEASE2(nsComponentManagerImpl::gComponentManager, cnt);
+ NS_ASSERTION(cnt == 0, "Component Manager being held past XPCOM shutdown.");
+ }
+ nsComponentManagerImpl::gComponentManager = nullptr;
+ nsCategoryManager::Destroy();
+
+ GkRust_Shutdown();
+
+#ifdef NS_FREE_PERMANENT_DATA
+ // By the time we're shutting down, there may still be async parse tasks going
+ // on in the Servo thread-pool. This is fairly uncommon, though not
+ // impossible. CSS parsing heavily uses the atom table, so obviously it's not
+ // fine to get rid of it.
+ //
+ // In leak-checking / ASAN / etc. builds, shut down the servo thread-pool,
+ // which will wait for all the work to be done. For other builds, we don't
+ // really want to wait on shutdown for possibly slow tasks. So just leak the
+ // atom table in those.
+ Servo_ShutdownThreadPool();
+ NS_ShutdownAtomTable();
+#endif
+
+ NS_IF_RELEASE(gDebug);
+
+ delete sIOThread;
+ sIOThread = nullptr;
+
+ delete sMessageLoop;
+ sMessageLoop = nullptr;
+
+ mozilla::TaskController::Shutdown();
+
+ if (sCommandLineWasInitialized) {
+ CommandLine::Terminate();
+ sCommandLineWasInitialized = false;
+ }
+
+ delete sExitManager;
+ sExitManager = nullptr;
+
+ Omnijar::CleanUp();
+
+ BackgroundHangMonitor::Shutdown();
+
+ delete sMainHangMonitor;
+ sMainHangMonitor = nullptr;
+
+ NS_LogTerm();
+
+ return NS_OK;
+}
+
+} // namespace mozilla