Processing async exceptions while coming from compiled code has a couple of issues:
1) The exception table might not be valid so there might not be a proper exception handler for it. Solution: Deoptimize the compiled frame.
2) For normal safepoint poll path (is_at_poll_safepoint()) we cannot deoptimize and install the exception at the same time because live registers get clobbered on the exception path before deoptimization is able to retrieve them. Solution: Don't process async exceptions at normal safepoint poll.
3) If we don't deoptimize after setting an async condition for the normal safepoint poll path, then we might never deliver it since we might never hit a path that process asynchronous exceptions. Solution: Same as 1), deoptimize the frame.
The comments and code for the three issues above are mixed and duplicated between methods check_and_handle_async_exceptions(), send_thread_stop(), and handle_polling_page_exception() and it's hard to put everything together to understand what's actually needed for each code path. Furthermore there are some inconsistencies, like we don't deoptimize for all code paths if the async exception happens to be an InternalError. Also the code in check_and_handle_async_exceptions() that tries to identify if we are in the is_at_poll_safepoint() case is never reached since we specifically don't process async exceptions in that path.
All the code and comments could be consolidated in check_and_handle_async_exceptions() in a more clear way.