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 373316 f2019fbd6f8c41163eb540d798558d44fcf176f4
parent 373315 95c81a2ecf7317ba77007c57f397177537e06239
child 373317 c6a89afa0c6b9c26cdba08a5d8e4115bc699d8d7
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1341326
milestone54.0a1
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.