Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support added for exceptions with ASYNCIFY #2772

Closed
wants to merge 14 commits into from

Conversation

NWilson
Copy link
Contributor

@NWilson NWilson commented Sep 8, 2014

The general scheme is not very complicated. Changes:

  1. Rather than doing dynCall_vi on the _foo___asnc_cb function, we use invoke_vi. This is essential if the callback functions are to throw exceptions.
  2. If a callback did throw an exception, then we should reenter the parent callback function only if it checks for exceptions at the resume point. Otherwise, the exception should propagate up. We check for this using an extra boolean in the async context: emscripten_alloc_async_context now has an extra argument which the C++ code uses to indicate whether the async function is called with "invoke" or "call". (So the invoke argument to emscripten_alloc_async_context is set when __THREW__ is checked immediately after the async call. We also update the invoke flag in emscripten_realloc_context.)
  3. If the exception isn't caught anywhere, we rethrow it finally so that an error message is provided (admittedly not a very clear one, but it's no worse than when an exception is throw out of a synchronous main).

This pull request works in conjunction with the pull request to the fastcomp compiler.

if (!___async_cur_frame) {
// print ugly integer in console, same as if an exception is thrown out of main()
if (activeException) _emscripten_async_abort_with_exception();
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emscripten_async_resume is also used used by coroutine functions, if coroutine A creates and runs B, and there's an exception threw in B, I wonder how should A respond.

I've noticed that asyncify fails if you call alloca during an async callback, we should at least catch this and abort before corrupting the stack. Also added support for a third argument to realloc_ctx to refresh the invoke flag.
…ard against corruption when alloca is in use
This is a very helpful feature for asyncify! Using 'noExitRuntime' is a very blunt solution that means that the runtime is never shut down, but with this tweak, we clean up main normally when its async_cb exits.
@@ -87,7 +87,10 @@ Module['callMain'] = Module.callMain = function callMain(args) {
#endif

// if we're not running an evented main loop, it's time to exit
exit(ret);
#if ASYNCIFY
if (asm['getAsync'] === undefined || !asm['getAsync']())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enough to do the second part. undefined is falsey.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, nevermind, i misread that

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how could it be undefined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, it probably can't. I was thinking that it wouldn't get linked in if there were no async functions (emscripten_async_resume for example can get discarded), but getAsync is part of the Runtime interface so I think you're right, it's guaranteed not to be trimmed by any optimisation phase if ASYNCIFY is turned on.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, then let's remove the unnecessary check here.

otherwise this looks ok to me, what do you think @coolwanglu ?

@NWilson
Copy link
Contributor Author

NWilson commented Sep 12, 2014

Wait, actually it's not OK! While writing some unittests, I've caught another problem with the stack unwinding when exceptions interact with ASYNCIFY. Some calls to emscripten_async_free_ctx can get skipped over if there isn't a convenient try-block, and we don't take that into account properly.

I'm starting to think that explicitly restoring the stack in catch blocks (as I mused on the emscripten-discuss group) is going to be the only way to make the asyncify unwinding safe with exceptions...

I need to thoroughly unittest this all before we can merge this pull request, sorry.

It's not as straightforward as I thought! Pretty close though.

@kripken
Copy link
Member

kripken commented Sep 12, 2014

Ok. As mentioned on the mailing list, explicitly restoring the stack in landingpads does sound like something we should do here.

(tests commit 59e10a383f385edeedca1e01a2755d179058cbc1 in emscripten-fastcomp)
From inspecting the code through to creating the testcase took a while,
but passing structs by val is the key to breaking asyncify this time.
@kripken kripken force-pushed the incoming branch 2 times, most recently from 92ca007 to c4f0934 Compare October 28, 2014 22:45
@NWilson
Copy link
Contributor Author

NWilson commented Nov 16, 2017

Closing; ASYNCIFY is ancient and won't ever come back. We no longer use the code in this PR.

@NWilson NWilson closed this Nov 16, 2017
@kripken
Copy link
Member

kripken commented Nov 16, 2017

Yeah, we should probably remove the option at this point, it's been deprecated for quite a while. Opened #5801 for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants