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

co_yield #10991

Open
unicomp21 opened this issue Apr 24, 2020 · 20 comments
Open

co_yield #10991

unicomp21 opened this issue Apr 24, 2020 · 20 comments

Comments

@unicomp21
Copy link

With emscripten using clang, should co_yield and generators "just work"?

@tlively
Copy link
Member

tlively commented Apr 24, 2020

Yes, they should. C++ generators are stackless, so all the interesting transformations should happen in the target-independent compiler frontend and we shoudn't need to change anything in the backend or on the Emscripten side. That being said, I don't think we've done any testing with generators. If you run into issues, please file an issue.

@unicomp21
Copy link
Author

Awesome, thanks Thomas!

@unicomp21
Copy link
Author

@tlively I'm a beginner on this topic, but I'm wondering. If co_yield currently works within webassembly "as is", could it be used to implement co_await? Wondering if it would be simpler than the binaryen implementation.

@unicomp21
Copy link
Author

@kripken ^

@tlively
Copy link
Member

tlively commented Apr 26, 2020

co_await should also "just work" for the same reason as co_yield. Making C++ coroutines interoperate with JS async/await might be a little trickier, though. IIUC, we would need to implement some custom executor that coordinates with JS, but I'm a little fuzzy on the details of what that would look like.

Wondering if it would be simpler than the binaryen implementation.

I assume you're thinking about whether Asyncify could be reimplemented with C++ coroutines somehow. It sounds attractive, but unfortunately it would not be a great idea. This is because Asyncify and coroutines are working at different layers of abstraction. In Asyncify, the language is not aware that execution is being paused so it needs to work on unmodified C and C++ code. C++ coroutines, on the other hand, are a language feature that programs have to opt into using via the new keywords in C++20. So in order to implement Asyncify in terms of coroutines, we would have to rewrite the code at some level to use the coroutine features. But even that wouldn't be quite enough because C++ coroutines only save the locals of the current function when it is suspended, but Asyncify needs to save the locals of every function on the stack. So in the end it's actually much simpler to just implement Asyncify as a transformation on the WebAssembly code in Binaryen.

@unicomp21
Copy link
Author

unicomp21 commented Apr 26, 2020 via email

@unicomp21
Copy link
Author

#9316

@tlively @kripken

Starting to realize I may have been confused earlier, see above link. Please correct me if I'm wrong. The binaren coroutine support is more akin to boost fibers? Whereas co_await is really a compiler supported concept? If this is true, I should be able to create a promise implementation, using emscripten, which will support co_await? Like has been done below?

https://devblogs.microsoft.com/cppblog/using-ibuv-with-c-resumable-functions/

https://github.com/jimspr/awaituv/blob/master/inc/awaituv.h#L300

@unicomp21 unicomp21 reopened this Apr 27, 2020
@tlively
Copy link
Member

tlively commented Apr 27, 2020

Yes, that should work just fine, as long as it is not trying to interact with the JS event loop. That kind of integration would be more involved. For the particular example you shared, you would have to port libuv to WebAssembly, too. I'm not sure whether anyone has done that yet.

@unicomp21
Copy link
Author

I don't need integration w/ JS event loop.

This is great! I'll have to start play around with the compiler supported promise/future pattern in libuv, and see if I can get something working in webassembly.

@unicomp21
Copy link
Author

@tlively @kripken what is @GorNishanov talking about here? I don't understand the tail call part.

GorNishanov/await#5

@GorNishanov
Copy link

GorNishanov commented Nov 18, 2021 via email

@tlively
Copy link
Member

tlively commented Nov 18, 2021

Clang and Emscripten support WebAssembly tail calls with -mtail-call, but tail calls are not supported by any production WebAssembly engine that I know of.

@unicomp21
Copy link
Author

unicomp21 commented Nov 19, 2021

@tlively co_await/webassembly, i don't understand, we're saying it will work? or won't work? Or are we just saying it will be inefficient?

@tlively
Copy link
Member

tlively commented Nov 19, 2021

I guess it should work but be inefficient.

@GorNishanov
Copy link

GorNishanov commented Nov 19, 2021

If a compiler, implements symmetric coroutine control transfer using tail calls, not honoring the tail call is a correctness issue. Since without tail calls, a thread stack could be easily exhausted.

It a platform does not support tail calls, a different codegen strategy has to be employed. Coroutine parts need to be no longer void, but, return the handle of the next coroutine to be executed and any resumption of the coroutine should be coded as:

// in some pseudocode form
void resume(coro$frame* coro)
{
  do
  {
      coro = call actual resume of coro
  }
  while (coro);
}

Clang/llvm relies on musttail to implement symmetric transfer. It will require non-trivial amount of work to implement symmetric transfer without relying on tail calls.

@unicomp21
Copy link
Author

unicomp21 commented Nov 20, 2021

@kripken @tlively @sbc100 is this a binaryen thing?

@findmet
Copy link

findmet commented Nov 21, 2021

Need help

@tlively
Copy link
Member

tlively commented Nov 22, 2021

@kripken @tlively @sbc100 is this a binaryen thing?

No, what's at issue here is how Clang lowers coroutines and whether or not it tries to use mandatory tail calls. Since WebAssembly tail calls are not enabled by default, my guess is that Clang does not try to use them to lower coroutines. (If it did, that would be a bug). So coroutines should work fine but be slower than they would be if tail calls were enabled. It would be interesting to measure what the performance difference actually is for WebAssembly; it will probably be different than the difference would be on native architectures.

@unicomp21
Copy link
Author

Has anyone tried using co_await on a chrome canary containing tail call support?

@unicomp21 unicomp21 reopened this Feb 22, 2023
@unicomp21
Copy link
Author

unicomp21 commented Feb 22, 2023

@GorNishanov could someone at MS test co_await on an Edge browser canary build which supports wasm tail calls?

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

No branches or pull requests

4 participants