Bug 1257234 - Detect main thread's stack size at runtime, on Windows. r=ted
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 18 Mar 2016 09:38:57 +0100
changeset 342038 9e117944cd9f81c01f9950acf0d33b619e95d656
parent 342037 af8f2955805c64fb6990262e8eba8165e185a0e5
child 342039 39d566b6138ebc9b46ce0d890f9cba5e90e24f7b
push id13342
push userbmo:james@hoppipolla.co.uk
push dateFri, 18 Mar 2016 09:55:58 +0000
reviewersted
bugs1257234
milestone48.0a1
Bug 1257234 - Detect main thread's stack size at runtime, on Windows. r=ted
js/xpconnect/src/XPCJSRuntime.cpp
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -58,16 +58,20 @@
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 #if defined(MOZ_JEMALLOC4)
 #include "mozmemory.h"
 #endif
 
+#ifdef XP_WIN
+#include <windows.h>
+#endif
+
 using namespace mozilla;
 using namespace xpc;
 using namespace JS;
 using mozilla::dom::PerThreadAtomCache;
 using mozilla::dom::AutoEntryScript;
 
 /***************************************************************************/
 
@@ -3357,16 +3361,50 @@ XPCJSRuntime::XPCJSRuntime()
    mWrappedJSRoots(nullptr),
    mObjectHolderRoots(nullptr),
    mWatchdogManager(new WatchdogManager(this)),
    mAsyncSnowWhiteFreer(new AsyncFreeSnowWhite()),
    mSlowScriptSecondHalf(false)
 {
 }
 
+#ifdef XP_WIN
+static size_t
+GetWindowsStackSize()
+{
+    // First, get the stack base. Because the stack grows down, this is the top
+    // of the stack.
+    const uint8_t* stackTop;
+#ifdef _WIN64
+    PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
+    stackTop = reinterpret_cast<const uint8_t*>(pTib->StackBase);
+#else
+    PNT_TIB pTib = reinterpret_cast<PNT_TIB>(NtCurrentTeb());
+    stackTop = reinterpret_cast<const uint8_t*>(pTib->StackBase);
+#endif
+
+    // Now determine the stack bottom. Note that we can't use tib->StackLimit,
+    // because that's the size of the committed area and we're also interested
+    // in the reserved pages below that.
+    MEMORY_BASIC_INFORMATION mbi;
+    if (!VirtualQuery(&mbi, &mbi, sizeof(mbi)))
+        MOZ_CRASH("VirtualQuery failed");
+
+    const uint8_t* stackBottom = reinterpret_cast<const uint8_t*>(mbi.AllocationBase);
+
+    // Do some sanity checks.
+    size_t stackSize = size_t(stackTop - stackBottom);
+    MOZ_RELEASE_ASSERT(stackSize >= 1 * 1024 * 1024);
+    MOZ_RELEASE_ASSERT(stackSize <= 32 * 1024 * 1024);
+
+    // Subtract 20 KB to account for things like the guard page.
+    return stackSize - 20 * 1024;
+}
+#endif
+
 nsresult
 XPCJSRuntime::Initialize()
 {
     nsresult rv = CycleCollectedJSRuntime::Initialize(nullptr,
                                                       JS::DefaultHeapMaxBytes,
                                                       JS::DefaultNurseryBytes);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
@@ -3439,19 +3477,19 @@ XPCJSRuntime::Initialize()
     // default (1MB on 32-bit, 2MB on 64-bit). ASAN stack frame measurements
     // were not taken at the time of this writing, so we hazard a guess that
     // ASAN builds have roughly thrice the stack overhead as normal builds.
     // On normal builds, the largest stack frame size we might encounter is
     // 9.0k (see above), so let's use a buffer of 9.0 * 5 * 10 = 450k.
     const size_t kStackQuota =  2 * kDefaultStackQuota;
     const size_t kTrustedScriptBuffer = 450 * 1024;
 #elif defined(XP_WIN)
-    // 1MB is the default stack size on Windows, so use 980k.
-    // Windows PGO stack frames have unfortunately gotten pretty large lately. :-(
-    const size_t kStackQuota = 980 * 1024;
+    // 1MB is the default stack size on Windows. We use the /STACK linker flag
+    // to request a larger stack, so we determine the stack size at runtime.
+    const size_t kStackQuota = GetWindowsStackSize();
     const size_t kTrustedScriptBuffer = (sizeof(size_t) == 8) ? 180 * 1024   //win64
                                                               : 120 * 1024;  //win32
     // The following two configurations are linux-only. Given the numbers above,
     // we use 50k and 100k trusted buffers on 32-bit and 64-bit respectively.
 #elif defined(DEBUG)
     // Bug 803182: account for the 4x difference in the size of js::Interpret
     // between optimized and debug builds.
     // XXXbholley - Then why do we only account for 2x of difference?