Closed sergei-kucher closed 2 years ago
A design document from the Go core developers are available here: https://docs.google.com/document/d/131vjr4DH6JFnb-blm_uRdaC0_Nv3OUwjEY5qVCxCup4/edit
Looks like their implementation is under review and possibly being merged soon: https://go-review.googlesource.com/c/go/+/102835
Posting it in case anyone wants to take a bite at this in the future. It covers some of the questions already asked here.
And as we can see from that document, go's port to wasm is a bunch of hacks to work around missing features in wasm. If someone wants to make a PR hacking those in, go for it, but until then I'll be waiting for proper GC and coroutine support.
Hi everyone,
I'm a big fan of crystal and also happen to be a blockchain developer so i'd just like to know if there is any news about this issue and if i could help in any way ... ?
Thanks!
I guess you could target "javascript" (not wasm) via emscriptem and go single threaded. Though that's not what the title of this issue is about :) I assume that's how mruby in the browser works [?] http://qiezi.me/projects/mruby-web-irb/mruby.html (just uses the javascript built-in GC I presume?). Watch also https://github.com/WebAssembly/gc/ (WIP gc proposal). Other options: Add a "new gc" option ("reference counting with cycle checking" https://github.com/JetBrains/kotlin-native/issues/1170#issuecomment-353328876 or the "double copy stack to the heap" trick RX14 mentions). Or manage stack manually if you want to keep fibers. Doesn't sound trivial...
This provides some very useful and up-to-date high-level information on the web assembly feature set and roadmap:
https://hacks.mozilla.org/2018/10/webassemblys-post-mvp-future/
@straight-shoota @RX14
Interesting read about threading implementation for wasm: https://rustwasm.github.io/2018/10/24/multithreading-rust-and-wasm.html There might be some useful things for us ;)
I just stumbled upon this issue. I’ve been thinking about adding Opal support to FaaStRuby, and if we could compile Crystal to Wasm... Full stack Crystal development in a serverless platform. Think about the possibilities!
I wish I could contribute to this effort, but I don’t know enough about Wasm or LLVM. But you guys can be sure I would contribute to make it popular by pushing the support to the platform as soon as you guys release it!
Thanks for the hard work.
Yeah, I imagine this is going to be one of the first big pushes after 1.0, and by then other languages will have figured out some of the do's and dont's of web assembly support, so it will be that much easier
FYI: I just put a discussion topic around this general topic: https://forum.crystal-lang.org/t/crystal-js-transpiler/903
WASM will soon be very important on the server as Envoy is testing support for dynamic filters via WASM and Istio will be fully supporting that soon. That should surely add some heat to this discussion.
LLVM WebAssembly target is production ready since LLVM 8.0.0. See http://releases.llvm.org/8.0.0/docs/ReleaseNotes.html#changes-to-the-webassembly-target .
Just keeping the talk going, this article was just released https://www.w3.org/blog/news/archives/8123. I think why this is important is because just like HTML, CSS, and JavaScript, WASM will be a web standard with the W3C backing it. I know with all the stuff this language still needs, this may be a little lower priority, but I think getting a "rough" start merged, that would allow us to really hash out how things should work. We could start with a preview or something like how the MT stuff is going, or just get some initial things like the windows support is doing.
Edit: Here's a spec link https://webassembly.github.io/spec/core/index.html
A "Hello world" for this feature would be 90% of the work :)
Keep your expectations low, this is about as hard as asking for the compiler to compile to JS directly.
Any updates on this? A lot of these comments sound like people are hoping for too much to be done at once. Just figure out how to talk with imported and exported functions, don't worry about supporting a standard library, or figuring out magical ways to talk to the dom (libraries can figure this out).
I was able to get a "hello" world from crystal done. Though, not in the way you'd want it. I basically just hand wrote bytes 😂 I did come across this gist showing how to compile LLVM with wasm support. I tried to see if I could get crystal compiled this way, but my eyes glossed over. It's a bit beyond my knowledge. Maybe someone else here can point out some stuff? My assumption is that if you can compile crystal with the latest LLVM, and add the right flags, maybe it'll just work™
Here's what I did https://gist.github.com/jwoertink/b8fb8430ed819dd4041a56ff6ed3ef64 if anyone is interested in expanding on that, or whatever.
@jwaldrip why?
Well heres one example, Crystal should be the language of choice for blockchain but isn't. The fastest way to build secure blockchain base anything right now is via Substrate/Polkadot and pretty much any language that can compile to wasm can easily leverage Substrate/Polkadot to get started. Among many things it's Wasm that allows Polkadot to have forkless upgrades -- that's significant. Instead of using Crystal, folks are just deciding to pick up Rust. Crystal would be far better.
That's one example.
WASM will soon be very important on the server as Envoy is testing support for dynamic filters via WASM and Istio will be fully supporting that soon. That should surely add some heat to this discussion.
Another example of a great use-case - transforming data on streaming platforms: https://thenewstack.io/webassembly-brings-easy-inline-data-transformations-to-redpanda-kafka-streaming-platform/
<< Adding functionality to an existing system is exactly the kind of place where WebAssembly is going to be useful, the Cloud Native Computing Foundation‘s Chief Technology Officer Chris Aniszczyk agreed. “I think we’ll see any project that has an extension-type mechanism will probably take advantage of WASM to go about doing that.” >>
Here is a summary of what needs to happen for a WebAssembly target:
new Error().stack
there, which will include the WebAssembly stack (this isn't an option from WASI outside a browser). Another solution involves modifying every function to push its own name in a heap stack and pop it on exit. Again, involves codegen changes and will cost performance. For unwind, it needs to be implemented "by hand", having every function return a special value then it raises an exception, and having each caller check it. Pretty much like Go exceptions.There are some WebAssembly proposals that would help a lot here:
What Go managed to do is just impressive, but it has quite a few performance issues. I don't think it is viable for us to go the same route just yet.
Wow! That's some great information @lbguilherme. Thanks for putting that together. It's much easier to see where we're at and where we need to get to.
There are plans for including a GC into WebAssembly. It would probably be better to use such a native GC instead of hacking bdwgc into WASM.
There are plans for including a GC into WebAssembly. It would probably be better to use such a native GC instead of hacking bdwgc into WASM.
Whichever of stack walking or GC is available first would be good targets.
There are some WebAssembly proposals that would help a lot here
The "arbitrary labels and gotos" isn't important here, since LLVM takes care of relooping. Stack walking and stack switching are important to support fibers, but it'd be neat to support basic crystal without the stdlib before then.
Basic basic Crystal (no stdlib, no exceptions) should already be feasible, right?
Basic Crystal is indeed feasible.
After some research, I concluded there are viable ways to implement the missing features with the current WebAssembly spec thanks to Binaryen. In particular, it has a pass called "Asyncify" that will take WebAssembly as input and apply a series of static transformations to it, generating WebAssembly out. The transformations modify the control flow of each function so that they can unwind the stack by pushing every local to a heap array, together with some information about where exactly execution was. And it adds a "rewind" strategy as well, consuming data from this heap array and refilling the stack to go back to the same place as before. This method is similar to what Go implemented for itself.
Sources with a documentation comment: https://github.com/WebAssembly/binaryen/blob/main/src/passes/Asyncify.cpp A nice blog post about it: https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html
GC_set_on_collection_event
to notify us before each GC collect (GC_EVENT_MARK_START
..GC_EVENT_MARK_END
). We can unwind the current stack and let the GC run without anything at all on the stack currently. After it finishes marking we can rewind the same Fiber back in place.After some research, I concluded there are viable ways to implement the missing features with the current WebAssembly spec thanks to Binaryen. In particular, it has a pass called "Asyncify" that will take WebAssembly as input and apply a series of static transformations to it, generating WebAssembly out. The transformations modify the control flow of each function so that they can unwind the stack by pushing every local to a heap array, together with some information about where exactly execution was. And it adds a "rewind" strategy as well, consuming data from this heap array and refilling the stack to go back to the same place as before. This method is similar to what Go implemented for itself.
Sources with a documentation comment: https://github.com/WebAssembly/binaryen/blob/main/src/passes/Asyncify.cpp A nice blog post about it: https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html
* Fibers: This is exactly what we need for stack switching. Unwind the current stack and then rewind a previous stack, with each paused fiber keeping its own stack saved for later. This has a performance penalty since the switch isn't constant time like every other platform, instead, it depends on the stack size (that should be small anyway). * GC: We can use bdwgc's `GC_set_on_collection_event` to notify us before each GC collect (`GC_EVENT_MARK_START`..`GC_EVENT_MARK_END`). We can unwind the current stack and let the GC run without anything at all on the stack currently. After it finishes marking we can rewind the same Fiber back in place. * Stack trace (for exceptions): We can unwind the current stack and then rewind it again. Then read and interpret data from the heap array generated in this process. The exact format needs to be well understood for that, but it should provide enough information. Debug information about function names, files, and lines can be included as auxiliary data later on. * Exceptions: Maybe we can unwind until a suitable begin..rescue..ensure..end is found? This part is still unclear.
I have a few WIP branches in various stages from my previous WASM porting attempts that may be of interest:
Most recent attempt: https://github.com/maxfierke/crystal/commits/mf-spike_wasm_take_two w/ full wasi-libc bindings for further diving, if anyone is interested.
Various notes here: https://github.com/maxfierke/crystal-wasm-tools
These have drifted from upstream a bit, but I think there might be some things still useful there for your work @lbguilherme. If #10870 gets merged, I would be happy to jump back in on WASM support given the good basis (much more organized than my spike branches 😅 )
Looks like https://github.com/crystal-lang/crystal/pull/10870 was merged, maybe WASM integration can proceed?
I believe this issue is superseded by #12002. Keep in mind that progress on this will most likely move slowly until there is more community adoption/interest.
Do you have any plans about WebAssembly support?