Bug 1341749 - Drain job queue even after error (r=bbouvier)
authorLuke Wagner <luke@mozilla.com>
Fri, 24 Feb 2017 09:30:38 -0600
changeset 373816 fe85f9809f82e9d52c2e7438f445b57a30628da7
parent 373815 dd8d6b4f30548a524ae89a19ab01544204441d0a
child 373817 a172fbd302fad2985912b11b72aaf46eb0a5532c
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)
reviewersbbouvier
bugs1341749
milestone54.0a1
Bug 1341749 - Drain job queue even after error (r=bbouvier) MozReview-Commit-ID: D7rjnADZ5if
js/src/jit-test/tests/wasm/regress/shell-promise-error.js
js/src/shell/js.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/shell-promise-error.js
@@ -0,0 +1,15 @@
+// |jit-test| error:done
+
+// Make a biggish module that will take a bit of time to compile.
+var code = '(module ';
+for (var i = 0; i < 1000; i++) {
+    code += '(func (local $i i32) ';
+    for (var j = 0; j < 100; j++)
+        code += '(set_local $i (i32.const 42))';
+    code += ')';
+}
+code += ')';
+
+WebAssembly.compile(wasmTextToBinary(code));
+
+throw "done";
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -814,22 +814,22 @@ ShellFinishAsyncTaskCallback(JS::AsyncTa
     ShellContext* sc = (ShellContext*)task->user;
 
     ExclusiveData<ShellAsyncTasks>::Guard asyncTasks = sc->asyncTasks.lock();
     MOZ_ASSERT(asyncTasks->outstanding > 0);
     asyncTasks->outstanding--;
     return asyncTasks->finished.append(task);
 }
 
-static bool
+static void
 DrainJobQueue(JSContext* cx)
 {
     ShellContext* sc = GetShellContext(cx);
     if (sc->quitting || sc->drainingJobQueue)
-        return true;
+        return;
 
     while (true) {
         // Wait for any outstanding async tasks to finish so that the
         // finishedAsyncTasks list is fixed.
         while (true) {
             AutoLockHelperThreadState lock;
             if (!sc->asyncTasks.lock()->outstanding)
                 break;
@@ -878,27 +878,25 @@ DrainJobQueue(JSContext* cx)
         // It's possible a job added an async task, and it's also possible
         // that task has already finished.
         {
             ExclusiveData<ShellAsyncTasks>::Guard asyncTasks = sc->asyncTasks.lock();
             if (asyncTasks->outstanding == 0 && asyncTasks->finished.length() == 0)
                 break;
         }
     }
-
-    return true;
 }
 
 static bool
 DrainJobQueue(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (!DrainJobQueue(cx))
-        return false;
+    DrainJobQueue(cx);
+
     args.rval().setUndefined();
     return true;
 }
 
 static void
 ForwardingPromiseRejectionTrackerCallback(JSContext* cx, JS::HandleObject promise,
                                           PromiseRejectionHandlingState state, void* data)
 {
@@ -7617,18 +7615,16 @@ ProcessArgs(JSContext* cx, OptionParser*
         return false;
 
     /* The |script| argument is processed after all options. */
     if (const char* path = op->getStringArg("script")) {
         if (!Process(cx, path, false))
             return false;
     }
 
-    DrainJobQueue(cx);
-
     if (op->getBoolOption('i')) {
         if (!Process(cx, nullptr, true))
             return false;
     }
 
     return true;
 }
 
@@ -7979,16 +7975,23 @@ Shell(JSContext* cx, OptionParser* op, c
     ShellContext* sc = GetShellContext(cx);
     int result = EXIT_SUCCESS;
     {
         AutoReportException are(cx);
         if (!ProcessArgs(cx, op) && !sc->quitting)
             result = EXITCODE_RUNTIME_ERROR;
     }
 
+    /*
+     * The job queue must be drained even on error to finish outstanding async
+     * tasks before the main thread JSRuntime is torn down. Drain after
+     * uncaught exceptions have been reported since draining runs callbacks.
+     */
+    DrainJobQueue(cx);
+
     if (sc->exitCode)
         result = sc->exitCode;
 
     if (enableDisassemblyDumps) {
         AutoReportException are(cx);
         if (!js::DumpCompartmentPCCounts(cx))
             result = EXITCODE_OUT_OF_MEMORY;
     }