Bug 765065 - Annotation for crash reports: "Are we GCing?" (r=bsmedberg)
authorBill McCloskey <wmccloskey@mozilla.com>
Wed, 15 Aug 2012 10:47:51 -0700
changeset 102452 dad98b444955403051e637035da4be14af3b7b41
parent 102451 fc50fe61fd712ca0b62bddc04e3136a08a70066b
child 102453 62bb2e74fe6726f354ad6e0f2614ec8d393786f3
push id23287
push userryanvm@gmail.com
push dateThu, 16 Aug 2012 01:37:50 +0000
treeherdermozilla-central@50e4ff05741e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs765065
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 765065 - Annotation for crash reports: "Are we GCing?" (r=bsmedberg)
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/xpcprivate.h
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.h
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -658,16 +658,34 @@ XPCJSRuntime::ReleaseIncrementally(nsTAr
     mReleaseRunnable = new XPCIncrementalReleaseRunnable(this, array);
 
     nsresult rv = NS_DispatchToMainThread(mReleaseRunnable);
     if (NS_FAILED(rv))
         mReleaseRunnable->ReleaseNow(false);
 }
 
 /* static */ void
+XPCJSRuntime::GCSliceCallback(JSRuntime *rt,
+                              js::GCProgress progress,
+                              const js::GCDescription &desc)
+{
+    XPCJSRuntime *self = nsXPConnect::GetRuntimeInstance();
+    if (!self)
+        return;
+
+#ifdef MOZ_CRASHREPORTER
+    CrashReporter::SetGarbageCollecting(progress == js::GC_CYCLE_BEGIN ||
+                                        progress == js::GC_SLICE_BEGIN);
+#endif
+
+    if (self->mPrevGCSliceCallback)
+        (*self->mPrevGCSliceCallback)(rt, progress, desc);
+}
+
+/* static */ void
 XPCJSRuntime::GCCallback(JSRuntime *rt, JSGCStatus status)
 {
     XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     if (!self)
         return;
 
     switch (status) {
         case JSGC_BEGIN:
@@ -1065,16 +1083,18 @@ XPCJSRuntime::GetJSCycleCollectionContex
     }
     return mJSCycleCollectionContext;
 }
 
 XPCJSRuntime::~XPCJSRuntime()
 {
     MOZ_ASSERT(!mReleaseRunnable);
 
+    js::SetGCSliceCallback(mJSRuntime, mPrevGCSliceCallback);
+
     if (mWatchdogWakeup) {
         // If the watchdog thread is running, tell it to terminate waking it
         // up if necessary and wait until it signals that it finished. As we
         // must release the lock before calling PR_DestroyCondVar, we use an
         // extra block here.
         {
             AutoLockWatchdog lock(this);
             if (mWatchdogThread) {
@@ -2152,16 +2172,17 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
     JS_SetNativeStackQuota(mJSRuntime, 2 * 128 * sizeof(size_t) * 1024);
 #else  
     JS_SetNativeStackQuota(mJSRuntime, 128 * sizeof(size_t) * 1024);
 #endif
     JS_SetContextCallback(mJSRuntime, ContextCallback);
     JS_SetDestroyCompartmentCallback(mJSRuntime, CompartmentDestroyedCallback);
     JS_SetCompartmentNameCallback(mJSRuntime, CompartmentNameCallback);
     JS_SetGCCallback(mJSRuntime, GCCallback);
+    mPrevGCSliceCallback = js::SetGCSliceCallback(mJSRuntime, GCSliceCallback);
     JS_SetFinalizeCallback(mJSRuntime, FinalizeCallback);
     JS_SetExtraGCRootsTracer(mJSRuntime, TraceBlackJS, this);
     JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this);
     JS_SetWrapObjectCallbacks(mJSRuntime,
                               xpc::WrapperFactory::Rewrap,
                               xpc::WrapperFactory::WrapForSameCompartment,
                               xpc::WrapperFactory::PrepareForWrapping);
     js::SetPreserveWrapperCallback(mJSRuntime, PreserveWrapper);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -751,16 +751,19 @@ public:
 
     static void TraceBlackJS(JSTracer* trc, void* data);
     static void TraceGrayJS(JSTracer* trc, void* data);
     void TraceXPConnectRoots(JSTracer *trc);
     void AddXPConnectRoots(nsCycleCollectionTraversalCallback& cb);
     void UnmarkSkippableJSHolders();
 
     static void GCCallback(JSRuntime *rt, JSGCStatus status);
+    static void GCSliceCallback(JSRuntime *rt,
+                                js::GCProgress progress,
+                                const js::GCDescription &desc);
     static void FinalizeCallback(JSFreeOp *fop, JSFinalizeStatus status, JSBool isCompartmentGC);
 
     inline void AddVariantRoot(XPCTraceableVariant* variant);
     inline void AddWrappedJSRoot(nsXPCWrappedJS* wrappedJS);
     inline void AddObjectHolderRoot(XPCJSObjectHolder* holder);
 
     nsresult AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer);
     nsresult RemoveJSHolder(void* aHolder);
@@ -905,16 +908,17 @@ private:
     JSDHashTable mJSHolders;
     PRLock *mWatchdogLock;
     PRCondVar *mWatchdogWakeup;
     PRThread *mWatchdogThread;
     nsTArray<JSGCCallback> extraGCCallbacks;
     bool mWatchdogHibernating;
     PRTime mLastActiveTime; // -1 if active NOW
     XPCIncrementalReleaseRunnable *mReleaseRunnable;
+    js::GCSliceCallback mPrevGCSliceCallback;
 
     nsCOMPtr<nsIException>   mPendingException;
     nsCOMPtr<nsIExceptionManager> mExceptionManager;
     bool mExceptionManagerNotAvailable;
 
     friend class AutoLockWatchdog;
     friend class XPCIncrementalReleaseRunnable;
 };
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -204,22 +204,27 @@ static const int kOOMAllocationSizeParam
 static const char kAvailablePageFileParameter[] = "AvailablePageFile=";
 static const int kAvailablePageFileParameterLen =
   sizeof(kAvailablePageFileParameter)-1;
 
 static const char kAvailablePhysicalMemoryParameter[] = "AvailablePhysicalMemory=";
 static const int kAvailablePhysicalMemoryParameterLen =
   sizeof(kAvailablePhysicalMemoryParameter)-1;
 
+static const char kIsGarbageCollectingParameter[] = "IsGarbageCollecting=";
+static const int kIsGarbageCollectingParameterLen =
+  sizeof(kIsGarbageCollectingParameter)-1;
+
 // this holds additional data sent via the API
 static Mutex* crashReporterAPILock;
 static Mutex* notesFieldLock;
 static AnnotationTable* crashReporterAPIData_Hash;
 static nsCString* crashReporterAPIData = nullptr;
 static nsCString* notesField = nullptr;
+static bool isGarbageCollecting;
 
 // OOP crash reporting
 static CrashGenerationServer* crashServer; // chrome process has this
 
 #  if defined(XP_WIN) || defined(XP_MACOSX)
 // If crash reporting is disabled, we hand out this "null" pipe to the
 // child process and don't attempt to connect to a parent server.
 static const char kNullNotifyPipe[] = "-";
@@ -521,16 +526,22 @@ bool MinidumpCallback(const XP_CHAR* dum
       WriteFile(hFile, "\n", 1, &nBytes, NULL);
       if (timeSinceLastCrash != 0) {
         WriteFile(hFile, kTimeSinceLastCrashParameter,
                   kTimeSinceLastCrashParameterLen, &nBytes, NULL);
         WriteFile(hFile, timeSinceLastCrashString, timeSinceLastCrashStringLen,
                   &nBytes, NULL);
         WriteFile(hFile, "\n", 1, &nBytes, NULL);
       }
+      if (isGarbageCollecting) {
+        WriteFile(hFile, kIsGarbageCollectingParameter, kIsGarbageCollectingParameterLen,
+                  &nBytes, NULL);
+        WriteFile(hFile, isGarbageCollecting ? "1" : "0", 1, &nBytes, NULL);
+        WriteFile(hFile, "\n", 1, &nBytes, NULL);
+      }
 
       // Try to get some information about memory.
       MEMORYSTATUSEX statex;
       statex.dwLength = sizeof(statex);
       if (GlobalMemoryStatusEx(&statex)) {
         char buffer[128];
         int bufferLen;
 
@@ -606,16 +617,21 @@ bool MinidumpCallback(const XP_CHAR* dum
       ignored = sys_write(fd, "\n", 1);
       if (timeSinceLastCrash != 0) {
         ignored = sys_write(fd, kTimeSinceLastCrashParameter,
                         kTimeSinceLastCrashParameterLen);
         ignored = sys_write(fd, timeSinceLastCrashString,
                         timeSinceLastCrashStringLen);
         ignored = sys_write(fd, "\n", 1);
       }
+      if (isGarbageCollecting) {
+        ignored = sys_write(fd, kIsGarbageCollectingParameter, kIsGarbageCollectingParameterLen);
+        ignored = sys_write(fd, isGarbageCollecting ? "1" : "0", 1);
+        ignored = sys_write(fd, "\n", 1);
+      }
       if (oomAllocationSizeBufferLen) {
         sys_write(fd, kOOMAllocationSizeParameter,
                   kOOMAllocationSizeParameterLen);
         sys_write(fd, oomAllocationSizeBuffer, oomAllocationSizeBufferLen);
         sys_write(fd, "\n", 1);
       }        
       sys_close(fd);
     }
@@ -1381,16 +1397,26 @@ nsresult AnnotateCrashReport(const nsACS
   // now rebuild the file contents
   crashReporterAPIData->Truncate(0);
   crashReporterAPIData_Hash->EnumerateRead(EnumerateEntries,
                                            crashReporterAPIData);
 
   return NS_OK;
 }
 
+nsresult SetGarbageCollecting(bool collecting)
+{
+  if (!GetEnabled())
+    return NS_ERROR_NOT_INITIALIZED;
+
+  isGarbageCollecting = collecting;
+
+  return NS_OK;
+}
+
 nsresult AppendAppNotesToCrashReport(const nsACString& data)
 {
   if (!GetEnabled())
     return NS_ERROR_NOT_INITIALIZED;
 
   if (DoFindInReadable(data, NS_LITERAL_CSTRING("\0")))
     return NS_ERROR_INVALID_ARG;
 
--- a/toolkit/crashreporter/nsExceptionHandler.h
+++ b/toolkit/crashreporter/nsExceptionHandler.h
@@ -35,16 +35,18 @@ nsresult SetMinidumpPath(const nsAString
 
 
 // AnnotateCrashReport and AppendAppNotesToCrashReport may be called from any
 // thread in a chrome process, but may only be called from the main thread in
 // a content process.
 nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data);
 nsresult AppendAppNotesToCrashReport(const nsACString& data);
 
+nsresult SetGarbageCollecting(bool collecting);
+
 nsresult SetRestartArgs(int argc, char** argv);
 nsresult SetupExtraData(nsIFile* aAppDataDirectory,
                         const nsACString& aBuildID);
 bool GetLastRunCrashID(nsAString& id);
 
 // Registers an additional memory region to be included in the minidump
 nsresult RegisterAppMemory(void* ptr, size_t length);
 nsresult UnregisterAppMemory(void* ptr);