Bug 1492584, part 1 - Eagerly initialize nsLayoutModule in the component manager. r=froydnj
authorAndrew McCreight <continuation@gmail.com>
Wed, 24 Oct 2018 16:10:29 +0000
changeset 491183 70984251b17425dc35f140dbca8097064184afc5
parent 491182 306bbd5916452a6151ec4bcfc128cd119134430e
child 491184 2df4dcfce65f9a9a0e41d3f65390c614d147cc1b
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersfroydnj
bugs1492584
milestone65.0a1
Bug 1492584, part 1 - Eagerly initialize nsLayoutModule in the component manager. r=froydnj nsLayoutModule must be initialized in order to call into JS, but I don't want to have to rely on calling a service in that module. Instead, always initialize the module very early in component manager initialization. This also makes initialization more consistent, so things like errors in manifests won't affect when it happens, which can result in different behavior in different builds. I also made nsLayoutModule initialization infallible, because I can't imagine that we can do much that is useful without it. Another change I made is that gInitialized is set to true even in a GPU process. This simplifies checking whether initialization has happened already when we start up the layout module. Differential Revision: https://phabricator.services.mozilla.com/D9583
layout/build/nsLayoutModule.cpp
layout/build/nsLayoutModule.h
xpcom/components/moz.build
xpcom/components/nsComponentManager.cpp
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -205,49 +205,45 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(Noti
 NS_GENERIC_FACTORY_CONSTRUCTOR(PushNotifier)
 
 //-----------------------------------------------------------------------------
 
 static bool gInitialized = false;
 
 // Perform our one-time intialization for this module
 
-static nsresult
-Initialize()
+void
+nsLayoutModuleInitialize()
 {
   if (gInitialized) {
     MOZ_CRASH("Recursive layout module initialization");
-    return NS_ERROR_FAILURE;
-  }
-  if (XRE_GetProcessType() == GeckoProcessType_GPU) {
-    // We mark the layout module as being available in the GPU process so that
-    // XPCOM's component manager initializes the power manager service, which
-    // is needed for nsAppShell. However, we don't actually need anything in
-    // the layout module itself.
-    return NS_OK;
   }
 
   static_assert(sizeof(uintptr_t) == sizeof(void*),
                 "Eeek! You'll need to adjust the size of uintptr_t to the "
                 "size of a pointer on your platform.");
 
   gInitialized = true;
 
-  nsresult rv;
-  rv = xpcModuleCtor();
-  if (NS_FAILED(rv))
-    return rv;
-
-  rv = nsLayoutStatics::Initialize();
-  if (NS_FAILED(rv)) {
-    Shutdown();
-    return rv;
+  if (XRE_GetProcessType() == GeckoProcessType_GPU) {
+    // We mark the layout module as being available in the GPU process so that
+    // XPCOM's component manager initializes the power manager service, which
+    // is needed for nsAppShell. However, we don't actually need anything in
+    // the layout module itself.
+    return;
   }
 
-  return NS_OK;
+  if (NS_FAILED(xpcModuleCtor())) {
+    MOZ_CRASH("xpcModuleCtor failed");
+  }
+
+  if (NS_FAILED(nsLayoutStatics::Initialize())) {
+    Shutdown();
+    MOZ_CRASH("nsLayoutStatics::Initialize failed");
+  }
 }
 
 // Shutdown this module, releasing all of the module resources
 
 // static
 void
 Shutdown()
 {
@@ -681,16 +677,24 @@ static const mozilla::Module::CategoryEn
   CONTENTDLF_CATEGORIES
   { "profile-after-change", "PresentationDeviceManager", PRESENTATION_DEVICE_MANAGER_CONTRACTID },
   { "profile-after-change", "PresentationService", PRESENTATION_SERVICE_CONTRACTID },
   { "profile-after-change", "Notification Telemetry Service", NOTIFICATIONTELEMETRYSERVICE_CONTRACTID },
   { nullptr }
   // clang-format on
 };
 
+static nsresult
+Initialize()
+{
+  // nsLayoutModuleInitialize should be called first.
+  MOZ_RELEASE_ASSERT(gInitialized);
+  return NS_OK;
+}
+
 static void
 LayoutModuleDtor()
 {
   if (XRE_GetProcessType() == GeckoProcessType_GPU) {
     return;
   }
 
   Shutdown();
new file mode 100644
--- /dev/null
+++ b/layout/build/nsLayoutModule.h
@@ -0,0 +1,17 @@
+/* -*- 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/. */
+
+#ifndef nsLayoutModule_h
+#define nsLayoutModule_h
+
+#include "nscore.h"
+
+// This function initializes various layout statics, as well as XPConnect.
+// It should be called only once, and before the first time any XPCOM module in
+// nsLayoutModule is used.
+void nsLayoutModuleInitialize();
+
+#endif // nsLayoutModule_h
--- a/xpcom/components/moz.build
+++ b/xpcom/components/moz.build
@@ -42,13 +42,14 @@ FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
     '!..',
     '../base',
     '../build',
     '../ds',
     '/chrome',
     '/js/xpconnect/loader',
+    '/layout/build',
     '/modules/libjar',
 ]
 
 if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
     CXXFLAGS += CONFIG['TK_CFLAGS']
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -12,16 +12,17 @@
 
 #include "nsCategoryManager.h"
 #include "nsCOMPtr.h"
 #include "nsComponentManager.h"
 #include "nsDirectoryService.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsCategoryManager.h"
 #include "nsCategoryManagerUtils.h"
+#include "nsLayoutModule.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsIConsoleService.h"
 #include "nsIObserverService.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIStringEnumerator.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
 #include "nsISupportsPrimitives.h"
@@ -349,16 +350,20 @@ nsComponentManagerImpl::Init()
       RegisterModule(module);
     }
   }
 
   for (uint32_t i = 0; i < sExtraStaticModules->Length(); ++i) {
     RegisterModule((*sExtraStaticModules)[i]);
   }
 
+  // This needs to be called very early, before anything in nsLayoutModule is
+  // used, and before any calls are made into the JS engine.
+  nsLayoutModuleInitialize();
+
   bool loadChromeManifests = (XRE_GetProcessType() != GeckoProcessType_GPU);
   if (loadChromeManifests) {
     // The overall order in which chrome.manifests are expected to be treated
     // is the following:
     // - greDir
     // - greDir's omni.ja
     // - appDir
     // - appDir's omni.ja