summaryrefslogtreecommitdiff
path: root/js/xpconnect/src/XPCJSContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/xpconnect/src/XPCJSContext.cpp')
-rw-r--r--js/xpconnect/src/XPCJSContext.cpp96
1 files changed, 69 insertions, 27 deletions
diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp
index a02c5e103b..2a32af83bd 100644
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -45,6 +45,7 @@
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
+#include "mozilla/Preferences.h"
#include "mozilla/ProcessHangMonitor.h"
#include "mozilla/Sprintf.h"
#include "mozilla/UniquePtrExtensions.h"
@@ -58,6 +59,7 @@
#include "nsJSPrincipals.h"
#ifdef XP_WIN
+#include <algorithm>
#include <windows.h>
#endif
@@ -3205,47 +3207,87 @@ XPCJSContext::Initialize()
// on 32-bit platforms and 1MB on 64-bit platforms.
const size_t kDefaultStackQuota = 128 * sizeof(size_t) * 1024;
- // Set stack sizes for different configurations. It's probably not great for
- // the web to base this decision primarily on the default stack size that the
- // underlying platform makes available, but that seems to be what we do. :-(
+ // Set maximum stack size for different configurations. This value is then
+ // capped below because huge JS stacks are not web-compatible.
+
+ // ASan requires more script buffer space due to red-zones, so give it more.
+ // We hazard a guess that ASAN builds have roughly thrice the stack
+ // overhead normal builds have, so we reserve 450k (50 frames @ 9k frame size)
#if defined(XP_MACOSX) || defined(DARWIN)
// MacOS has a gargantuan default stack size of 8MB. Go wild with 7MB,
- // and give trusted script 180k extra. The stack is huge on mac anyway.
- const size_t kStackQuota = 7 * 1024 * 1024;
+ // and give trusted script 180k extra.
+ const size_t kUncappedStackQuota = 7 * 1024 * 1024;
const size_t kTrustedScriptBuffer = 180 * 1024;
-#elif defined(MOZ_ASAN)
- // ASan requires more stack space due to red-zones, so give it double the
- // 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;
+
+#elif defined(XP_LINUX) || defined(XP_SOLARIS)
+ // Most Linux distributions set default stack size to 8MB. Use it as the
+ // maximum value.
+ // Solaris uses 8 or 10 MB, depending, so this is a safe max there too.
+ const size_t kStackQuotaMax = 8 * 1024 * 1024;
+#if defined(MOZ_ASAN) || defined(DEBUG)
+ // Bug 803182: account for the 4x difference in the size of js::Interpret
+ // between optimized and debug builds. We use 2x since the JIT part
+ // doesn't increase much.
+ const size_t kStackQuotaMin = 2 * kDefaultStackQuota;
+#else
+ const size_t kStackQuotaMin = kDefaultStackQuota;
+#endif // MOZ_ASAN || DEBUG
+ // Allocate 128kB margin for the safe space.
+ const size_t kStackSafeMargin = 128 * 1024;
+
+ struct rlimit rlim;
+ const size_t kUncappedStackQuota =
+ getrlimit(RLIMIT_STACK, &rlim) == 0 ?
+ std::max(std::min(size_t(rlim.rlim_cur - kStackSafeMargin),
+ kStackQuotaMax - kStackSafeMargin),
+ kStackQuotaMin) :
+ kStackQuotaMin;
+#if defined(MOZ_ASAN)
const size_t kTrustedScriptBuffer = 450 * 1024;
+#else
+ const size_t kTrustedScriptBuffer = 180 * 1024;
+#endif // MOZ_ASAN
+
#elif defined(XP_WIN)
// 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?
- const size_t kStackQuota = 2 * kDefaultStackQuota;
- const size_t kTrustedScriptBuffer = sizeof(size_t) * 12800;
+ // (see WIN32_EXE_LDFLAGS in config/config.mk) to request a larger stack, so
+ // we determine the stack size at runtime.
+ const size_t kUncappedStackQuota = GetWindowsStackSize();
+#if defined(MOZ_ASAN)
+ const size_t kTrustedScriptBuffer = 450 * 1024;
#else
- const size_t kStackQuota = kDefaultStackQuota;
- const size_t kTrustedScriptBuffer = sizeof(size_t) * 12800;
+ const size_t kTrustedScriptBuffer = (sizeof(size_t) == 8) ?
+ 180 * 1024 : // win64
+ 120 * 1024; // win32
+#endif //MOZ_ASAN
+
+#else
+ // We're not on Windows, Linux, Solaris or Mac/Darwin
+ // Catch-all configuration for other environments.
+#if defined(MOZ_ASAN)
+ const size_t kUncappedStackQuota = 2 * kDefaultStackQuota;
+ const size_t kTrustedScriptBuffer = 450 * 1024;
+#else
+#if defined(DEBUG)
+ const size_t kUncappedStackQuota = 2 * kDefaultStackQuota;
+#else
+ const size_t kUncappedStackQuota = kDefaultStackQuota;
#endif
+ // Given the numbers above, we use 50k and 100k trusted buffers on 32-bit
+ // and 64-bit respectively.
+ const size_t kTrustedScriptBuffer = sizeof(size_t) * 12800;
+#endif // MOZ_ASAN
+#endif // OS selection
// Avoid an unused variable warning on platforms where we don't use the
// default.
(void) kDefaultStackQuota;
+ // Large JS stacks are not web-compatible so cap to a smaller value.
+ const size_t kStackQuotaCap = Preferences::GetUint("javascript.options.main_thread_stack_quota_cap", 2 * 1024 * 1024);
+ const size_t kStackQuota = std::min(kUncappedStackQuota, kStackQuotaCap);
+
JS_SetNativeStackQuota(cx,
kStackQuota,
kStackQuota - kSystemCodeBuffer,