Bug 1262731 - Add JS_InitWithFailureDiagnostic(). r=sfink.
authorNicholas Nethercote <nnethercote@mozilla.com>
Fri, 08 Apr 2016 09:08:49 +1000
changeset 348817 8ea65a181e4b63568eb30a82629beb27cdf1f2cb
parent 348816 111872969899c82e1ccd27d63e8d67faa8f66af5
child 348818 1129184ec2dd240ff8084b2a51ef55afd2245bd8
push id14928
push userbmo:mh+mozilla@glandium.org
push dateFri, 08 Apr 2016 05:15:03 +0000
reviewerssfink
bugs1262731
milestone48.0a1
Bug 1262731 - Add JS_InitWithFailureDiagnostic(). r=sfink. This will help identify the cause of some Firefox start-up crashes when JS initialization fails.
js/public/Initialization.h
js/src/vm/DateTime.h
js/src/vm/Initialization.cpp
xpcom/build/XPCOMInit.cpp
--- a/js/public/Initialization.h
+++ b/js/public/Initialization.h
@@ -57,16 +57,24 @@ JS_SetICUMemoryFunctions(JS_ICUAllocFn a
  * It is currently not possible to initialize SpiderMonkey multiple times (that
  * is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so
  * again).  This restriction may eventually be lifted.
  */
 extern JS_PUBLIC_API(bool)
 JS_Init(void);
 
 /**
+ * A variant of JS_Init. On success it returns nullptr. On failure it returns a
+ * pointer to a string literal that describes how initialization failed, which
+ * can be useful for debugging purposes.
+ */
+extern JS_PUBLIC_API(const char*)
+JS_InitWithFailureDiagnostic(void);
+
+/**
  * Destroy free-standing resources allocated by SpiderMonkey, not associated
  * with any runtime, context, or other structure.
  *
  * This method should be called after all other JSAPI data has been properly
  * cleaned up: every new runtime must have been destroyed, every new context
  * must have been destroyed, and so on.  Calling this method before all other
  * resources have been destroyed has undefined behavior.
  *
--- a/js/src/vm/DateTime.h
+++ b/js/src/vm/DateTime.h
@@ -114,17 +114,17 @@ class DateTimeInfo
                 continue;
         }
         ~AcquireLock() {
             MOZ_ASSERT(spinLock, "spinlock should have been acquired");
             spinLock = false;
         }
     };
 
-    friend bool ::JS_Init();
+    friend const char* ::JS_InitWithFailureDiagnostic();
 
     // Initialize global date/time tracking state.  This operation occurs
     // during, and is restricted to, SpiderMonkey initialization.
     static void init();
 
   public:
     /*
      * Get the DST offset in milliseconds at a UTC time.  This is usually
--- a/js/src/vm/Initialization.cpp
+++ b/js/src/vm/Initialization.cpp
@@ -54,66 +54,73 @@ CheckMessageParameterCounts()
     // parameters.
 # define MSG_DEF(name, count, exception, format)           \
         MOZ_ASSERT(MessageParameterCount(format) == count);
 # include "js.msg"
 # undef MSG_DEF
 }
 #endif /* DEBUG */
 
-JS_PUBLIC_API(bool)
-JS_Init(void)
+JS_PUBLIC_API(const char*)
+JS_InitWithFailureDiagnostic(void)
 {
     MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
                "must call JS_Init once before any JSAPI operation except "
                "JS_SetICUMemoryFunctions");
     MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
                "how do we have live runtimes before JS_Init?");
 
     PRMJ_NowInit();
 
 #ifdef DEBUG
     CheckMessageParameterCounts();
 #endif
 
     using js::TlsPerThreadData;
     if (!TlsPerThreadData.init())
-        return false;
+        return "JS_InitWithFailureDiagnostic: TlsPerThreadData.init() failed";
 
 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
     if (!js::oom::InitThreadType())
-        return false;
+        return "JS_InitWithFailureDiagnostic: js::oom::InitThreadType() failed";
     js::oom::SetThreadType(js::oom::THREAD_TYPE_MAIN);
 #endif
 
     js::jit::ExecutableAllocator::initStatic();
 
     if (!js::jit::InitializeIon())
-        return false;
+        return "JS_InitWithFailureDiagnostic: js::jit::InitializeIon() failed";
 
     js::DateTimeInfo::init();
 
 #if EXPOSE_INTL_API
     UErrorCode err = U_ZERO_ERROR;
     u_init(&err);
     if (U_FAILURE(err))
-        return false;
+        return "JS_InitWithFailureDiagnostic: u_init() failed";
 #endif // EXPOSE_INTL_API
 
     if (!js::CreateHelperThreadsState())
-        return false;
+        return "JS_InitWithFailureDiagnostic: js::CreateHelperThreadState() failed";
 
     if (!FutexRuntime::initialize())
-        return false;
+        return "JS_InitWithFailureDiagnostic: FutexRuntime::initialize() failed";
 
     if (!js::gcstats::Statistics::initialize())
-        return false;
+        return "JS_InitWithFailureDiagnostic: js::gcstats::Statistics::initialize() failed";
 
     libraryInitState = InitState::Running;
-    return true;
+    return nullptr;
+}
+
+JS_PUBLIC_API(bool)
+JS_Init(void)
+{
+    const char* failure = JS_InitWithFailureDiagnostic();
+    return !failure;
 }
 
 JS_PUBLIC_API(void)
 JS_ShutDown(void)
 {
     MOZ_ASSERT(libraryInitState == InitState::Running,
                "JS_ShutDown must only be called after JS_Init and can't race with it");
 #ifdef DEBUG
--- a/xpcom/build/XPCOMInit.cpp
+++ b/xpcom/build/XPCOMInit.cpp
@@ -699,18 +699,19 @@ NS_InitXPCOM2(nsIServiceManager** aResul
                                     getter_AddRefs(greDir));
   MOZ_ASSERT(greDir);
   nsAutoCString nativeGREPath;
   greDir->GetNativePath(nativeGREPath);
   u_setDataDirectory(nativeGREPath.get());
 #endif
 
   // Initialize the JS engine.
-  if (!JS_Init()) {
-    NS_RUNTIMEABORT("JS_Init failed");
+  const char* jsInitFailureReason = JS_InitWithFailureDiagnostic();
+  if (jsInitFailureReason) {
+    NS_RUNTIMEABORT(jsInitFailureReason);
   }
 
   rv = nsComponentManagerImpl::gComponentManager->Init();
   if (NS_FAILED(rv)) {
     NS_RELEASE(nsComponentManagerImpl::gComponentManager);
     return rv;
   }