WorkerThread::stop() should call scheduleExecutionTermination() last.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 May 2017 23:22:33 +0000 (23:22 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 May 2017 23:22:33 +0000 (23:22 +0000)
commitd5804f8495c60f56a275391dac87678b5a9c2892
treef7a4e5d9deadfb31bfede241f767500855797294
parenta86db692f2d4c52a555b18304c0af1dc62c9c01b
WorkerThread::stop() should call scheduleExecutionTermination() last.
https://bugs.webkit.org/show_bug.cgi?id=171775
<rdar://problem/30975761>

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Increased the number of frames captured in VM::nativeStackTraceOfLastThrow()
from 25 to 100.  From experience, I found that 25 is sometimes not sufficient
for our debugging needs.

Also added VM::throwingThread() to track which thread an exception was thrown in.
This may be useful if the client is entering the VM from different threads.

* runtime/ExceptionScope.cpp:
(JSC::ExceptionScope::unexpectedExceptionMessage):
(JSC::ExceptionScope::releaseAssertIsTerminatedExecutionException):
* runtime/ExceptionScope.h:
(JSC::ExceptionScope::exception):
(JSC::ExceptionScope::unexpectedExceptionMessage):
* runtime/VM.cpp:
(JSC::VM::throwException):
* runtime/VM.h:
(JSC::VM::throwingThread):
(JSC::VM::clearException):

Source/WebCore:

Currently, WorkerThread::stop() calls scheduleExecutionTermination() to terminate
JS execution first, followed by posting a cleanup task to the worker, and lastly,
it invokes terminate() on the WorkerRunLoop.

As a result, before run loop is terminate, the worker thread may observe the
TerminatedExecutionException in JS code, bail out, see another JS task to run,
re-enters the VM to run said JS code, and fails with an assertion due to the
TerminatedExecutionException still being pending on VM entry.

WorkerRunLoop::Task::performTask() already has a check to only allow a task to
run if and only if !runLoop.terminated() and the task is not a clean up task.
We'll fix the above race by ensuring that having WorkerThread::stop() terminate
the run loop before it scheduleExecutionTermination() which throws the
TerminatedExecutionException.  This way, by the time JS code unwinds out of the
VM due to the TerminatedExecutionException, runLoop.terminated() is guaranteed
to be true and thereby prevents re-entry into the VM.

This issue is covered by an existing test that I just unskipped in TestExpectations.

* bindings/js/JSDOMPromiseDeferred.cpp:
(WebCore::DeferredPromise::callFunction):
* workers/WorkerThread.cpp:
(WebCore::WorkerThread::stop):

LayoutTests:

* TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@216635 268f45cc-cd09-0410-ab3c-d52691b4dbfc
LayoutTests/ChangeLog
LayoutTests/TestExpectations
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/ExceptionScope.cpp
Source/JavaScriptCore/runtime/ExceptionScope.h
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMPromiseDeferred.cpp
Source/WebCore/workers/WorkerThread.cpp