Bug 1341326 - Set stack limit and stack size properly for helper threads, r=jandem.
☠☠ backed out by 0bdfccec471f ☠ ☠
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 22 Feb 2017 05:11:09 -0700
changeset 344289 f2019fbd6f8c41163eb540d798558d44fcf176f4
parent 344288 95c81a2ecf7317ba77007c57f397177537e06239
child 344290 c6a89afa0c6b9c26cdba08a5d8e4115bc699d8d7
push id31406
push userkwierso@gmail.com
push dateWed, 22 Feb 2017 23:01:18 +0000
treeherdermozilla-central@32dcdde1fc64 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1341326
milestone54.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 1341326 - Set stack limit and stack size properly for helper threads, r=jandem.
js/src/jit-test/tests/basic/bug1341326.js
js/src/threading/posix/Thread.cpp
js/src/threading/windows/Thread.cpp
js/src/vm/HelperThreads.cpp
js/src/vm/HelperThreads.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1341326.js
@@ -0,0 +1,15 @@
+if (helperThreadCount() == 0)
+    quit();
+function eval(source) {
+    offThreadCompileModule(source);
+}
+var N = 10000;
+var left = repeat_str('(1&', N);
+var right = repeat_str(')', N);
+var str = 'actual = '.concat(left, '1', right, ';');
+eval(str);
+function repeat_str(str, repeat_count) {
+    var arr = new Array(--repeat_count);
+    while (repeat_count != 0) arr[--repeat_count] = str;
+    return str.concat.apply(str, arr);
+}
--- a/js/src/threading/posix/Thread.cpp
+++ b/js/src/threading/posix/Thread.cpp
@@ -73,24 +73,26 @@ js::Thread::Id::operator==(const Id& aOt
          (self.hasThread == other.hasThread &&
           pthread_equal(self.ptThread, other.ptThread));
 }
 
 js::Thread::Thread(Thread&& aOther)
 {
   id_ = aOther.id_;
   aOther.id_ = Id();
+  options_ = aOther.options_;
 }
 
 js::Thread&
 js::Thread::operator=(Thread&& aOther)
 {
   MOZ_RELEASE_ASSERT(!joinable());
   id_ = aOther.id_;
   aOther.id_ = Id();
+  options_ = aOther.options_;
   return *this;
 }
 
 bool
 js::Thread::create(void* (*aMain)(void*), void* aArg)
 {
   pthread_attr_t attrs;
   int r = pthread_attr_init(&attrs);
--- a/js/src/threading/windows/Thread.cpp
+++ b/js/src/threading/windows/Thread.cpp
@@ -54,24 +54,26 @@ js::Thread::Id::operator==(const Id& aOt
 {
   return platformData()->id == aOther.platformData()->id;
 }
 
 js::Thread::Thread(Thread&& aOther)
 {
   id_ = aOther.id_;
   aOther.id_ = Id();
+  options_ = aOther.options_;
 }
 
 js::Thread&
 js::Thread::operator=(Thread&& aOther)
 {
   MOZ_RELEASE_ASSERT(!joinable());
   id_ = aOther.id_;
   aOther.id_ = Id();
+  options_ = aOther.options_;
   return *this;
 }
 
 bool
 js::Thread::create(unsigned int (__stdcall* aMain)(void*), void* aArg)
 {
   // Use _beginthreadex and not CreateThread, because threads that are
   // created with the latter leak a small amount of memory when they use
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -1658,17 +1658,17 @@ void
 JSContext::addPendingOutOfMemory()
 {
     // Keep in sync with recoverFromOutOfMemory.
     if (helperThread()->parseTask())
         helperThread()->parseTask()->outOfMemory = true;
 }
 
 void
-HelperThread::handleParseWorkload(AutoLockHelperThreadState& locked, uintptr_t stackLimit)
+HelperThread::handleParseWorkload(AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().canStartParseTask(locked));
     MOZ_ASSERT(idle());
 
     currentTask.emplace(HelperThreadState().parseWorklist(locked).popCopy());
     ParseTask* task = parseTask();
 
     {
@@ -1898,24 +1898,17 @@ HelperThread::threadLoop()
 
     JSContext cx(nullptr, JS::ContextOptions());
     {
         AutoEnterOOMUnsafeRegion oomUnsafe;
         if (!cx.init(ContextKind::Background))
             oomUnsafe.crash("HelperThread cx.init()");
     }
     cx.setHelperThread(this);
-
-    // Compute the thread's stack limit, for over-recursed checks.
-    uintptr_t stackLimit = GetNativeStackBase();
-#if JS_STACK_GROWTH_DIRECTION > 0
-    stackLimit += HELPER_STACK_QUOTA;
-#else
-    stackLimit -= HELPER_STACK_QUOTA;
-#endif
+    JS_SetNativeStackQuota(&cx, HELPER_STACK_QUOTA);
 
     while (true) {
         MOZ_ASSERT(idle());
 
         // Block until a task is available. Save the value of whether we are
         // going to do an Ion compile, in case the value returned by the method
         // changes.
         bool ionCompile = false;
@@ -1941,17 +1934,17 @@ HelperThread::threadLoop()
         } else if (HelperThreadState().canStartWasmCompile(lock)) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_WASM);
             handleWasmWorkload(lock);
         } else if (HelperThreadState().canStartPromiseTask(lock)) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_PROMISE_TASK);
             handlePromiseTaskWorkload(lock);
         } else if (HelperThreadState().canStartParseTask(lock)) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_PARSE);
-            handleParseWorkload(lock, stackLimit);
+            handleParseWorkload(lock);
         } else if (HelperThreadState().canStartCompressionTask(lock)) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_COMPRESS);
             handleCompressionWorkload(lock);
         } else if (HelperThreadState().canStartGCHelperTask(lock)) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_GCHELPER);
             handleGCHelperWorkload(lock);
         } else if (HelperThreadState().canStartGCParallelTask(lock)) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_GCPARALLEL);
--- a/js/src/vm/HelperThreads.h
+++ b/js/src/vm/HelperThreads.h
@@ -379,17 +379,17 @@ struct HelperThread
             return currentTask->as<T>();
 
         return nullptr;
     }
 
     void handleWasmWorkload(AutoLockHelperThreadState& locked);
     void handlePromiseTaskWorkload(AutoLockHelperThreadState& locked);
     void handleIonWorkload(AutoLockHelperThreadState& locked);
-    void handleParseWorkload(AutoLockHelperThreadState& locked, uintptr_t stackLimit);
+    void handleParseWorkload(AutoLockHelperThreadState& locked);
     void handleCompressionWorkload(AutoLockHelperThreadState& locked);
     void handleGCHelperWorkload(AutoLockHelperThreadState& locked);
     void handleGCParallelWorkload(AutoLockHelperThreadState& locked);
 };
 
 /* Methods for interacting with helper threads. */
 
 // Create data structures used by helper threads.