Bug 1382076 - Use FramePointerStackWalk() in DMD on Win32. r=erahm.
authorNicholas Nethercote <nnethercote@mozilla.com>
Thu, 20 Jul 2017 11:33:31 +1000
changeset 418638 8b89d684f633977acdd317654d040a86ddef466b
parent 418637 7066bee0381d62764ba8fc55aa4270eb5a241b20
child 418639 027d4346e7fc63fa5120358d60a5d03ed48c94a0
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerserahm
bugs1382076
milestone56.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 1382076 - Use FramePointerStackWalk() in DMD on Win32. r=erahm. The patch also uses a better value for skipFrames on Win64.
memory/replace/dmd/DMD.cpp
--- a/memory/replace/dmd/DMD.cpp
+++ b/memory/replace/dmd/DMD.cpp
@@ -749,18 +749,50 @@ StackTrace::Get(Thread* aT)
   // to MozStackWalk.  For details, see
   // https://bugzilla.mozilla.org/show_bug.cgi?id=374829#c8
   // On Linux, something similar can happen;  see bug 824340.
   // So let's just release it on all platforms.
   StackTrace tmp;
   {
     AutoUnlockState unlock;
     // In each of the following cases, skipFrames is chosen so that the
-    // first frame in each stack trace is a replace_* function.
-#ifdef XP_MACOSX
+    // first frame in each stack trace is a replace_* function (or as close as
+    // possible, given the vagaries of inlining on different platforms).
+#if defined(XP_WIN) && defined(_M_IX86)
+    // This avoids MozStackWalk(), which causes unusably slow startup on Win32
+    // when it is called during static initialization (see bug 1241684).
+    //
+    // This code is cribbed from the Gecko Profiler, which also uses
+    // FramePointerStackWalk() on Win32: Registers::SyncPopulate() for the
+    // frame pointer, and GetStackTop() for the stack end.
+    CONTEXT context;
+    RtlCaptureContext(&context);
+    void* fp = reinterpret_cast<void*>(context.Ebp);
+
+    // Offset 0x18 from the FS segment register gives a pointer to the thread
+    // information block for the current thread.
+#if defined(_MSC_VER)
+    NT_TIB* pTib;
+    __asm {
+      MOV EAX, FS:[18h]
+      MOV pTib, EAX
+    }
+#elif defined(__GNUC__)
+    NT_TIB* pTib;
+    asm ( "movl %%fs:0x18, %0\n"
+         : "=r" (pTib)
+        );
+#else
+#   error "unknown compiler"
+#endif
+    void* stackEnd = static_cast<void*>(pTib->StackBase);
+    bool ok = FramePointerStackWalk(StackWalkCallback, /* skipFrames = */ 0,
+                                    MaxFrames, &tmp,
+                                    reinterpret_cast<void**>(fp), stackEnd);
+#elif defined(XP_MACOSX)
     // This avoids MozStackWalk(), which has become unusably slow on Mac due to
     // changes in libunwind.
     //
     // This code is cribbed from the Gecko Profiler, which also uses
     // FramePointerStackWalk() on Mac: Registers::SyncPopulate() for the frame
     // pointer, and GetStackTop() for the stack end.
     void* fp;
     asm (
@@ -769,18 +801,23 @@ StackTrace::Get(Thread* aT)
         :
         "=r"(fp)
     );
     void* stackEnd = pthread_get_stackaddr_np(pthread_self());
     bool ok = FramePointerStackWalk(StackWalkCallback, /* skipFrames = */ 0,
                                     MaxFrames, &tmp,
                                     reinterpret_cast<void**>(fp), stackEnd);
 #else
-    bool ok = MozStackWalk(StackWalkCallback, /* skipFrames = */ 2,
-                           MaxFrames, &tmp, 0, nullptr);
+#if defined(XP_WIN) && defined(_M_X64)
+    int skipFrames = 1;
+#else
+    int skipFrames = 2;
+#endif
+    bool ok = MozStackWalk(StackWalkCallback, skipFrames, MaxFrames, &tmp, 0,
+                           nullptr);
 #endif
     if (!ok) {
       tmp.mLength = 0; // re-zero in case the stack walk function changed it
     }
   }
 
   StackTraceTable::AddPtr p = gStackTraceTable->lookupForAdd(&tmp);
   if (!p) {