What we could do is set panic=abort in the target but provide a binary release of std compiled with panic=unwind then executables would “abort” by default and ‘-C panic=unwind’ would also work. The downside is that whatever’s the equivalent of landing pads for emscripten/wasm would still be present in std and the final executable for either panic profile.
I was playing around with this and js-interop to see how much currently was doable. https://gist.github.com/Thinkofname/17e8369b5fcd1d307f5d98dfda9266a6 This actually works but with a few issues.
- This only works correctly in release mode. I suspect this is because the strings only end up in a format emscripten can find them in release mode due to optimizations
- I’d prefer
js_raw
vsjs
due to the fact not all javascript is valid-enough rust for the macro system to handle but ended up with an issue that emscripten breaks if that string has a new line in it - This relies on an internal symbol
emscripten_asm_const_int
that is only meant to be used by theEM_ASM
macro.
Not a major issue as emscripten_run_script
works but has a performance hit due to using eval
behind the scenes
Edit: Or using EMCC_CFLAGS="--js-library lib.js"
to go via that route to avoid the eval
I don’t know anything about wasm since I’ve not played with it yet, but just to add some additional info for any readers - asm.js cannot contain try/catch, so the round trip takes the form of calling out of asm.js to a normal js function containing the try/catch, and then back in.
This aside, I think there’s an argument to be made for having at least one first-class platform abort-on-panic by default as a general discouragement of using panics as exceptions. That emscripten would be a bad plaform for unwinding as-is and somewhat-less-bad-but-still-not-great if effort was invested to change unwinding seems like a happy coincidence.
There’s a significant setback to landing the emscripten PR. The mingw build is creating some suspicious linker errors. As far as I can tell the symbols it is complaining about exist, so I have no idea what is going on. My best wild guess is some bug in the mingw linker due to the increased binary size from the fastcomp backend.
Unless anybody has other ideas, one thing we might do to attempt to address this is to make the port work without the fastcomp backend. As I mentioned previously it shouldn’t actually be required in order for us to output the correct bitcode for emcc to use.
I’ve started ripping code out of the fastcomp patch to see how small it can be while still generating the correct IR.
thanks for keeping this thread updated on the status. the amount of time and effort that’s gone into this is exceedingly non-trivial, so thanks to brson and everyone else who have been steadily working on this over the past many months
The PR landed and there’s some discussion on reddit: https://www.reddit.com/r/rust/comments/55c9el/working_asmjs_and_wasm_targets_merged_into_master/
Thanks everyone for the help. This is a great milestone but there’s more to do yet.
Here are two more important improvements to emscripten:
- https://github.com/rust-lang/rust/issues/36899. This is about delegating all optimization to emcc. Right now we use do our own optimization on LLVM IR and call emcc with the default arguments. emcc though can do better optimizations than rustc here so we should instead have it do all optimizations. This will involve understanding emcc’s optimization options and hacking the rustc backend to pass the right options.
-
https://github.com/rust-lang/rust/issues/36900. Emscripten can remove unwinding from LLVM IR itself, so we can use this feature to remove landing pads from the standard library, so
-C panic-runtime=abort
will produce optimal code. This will involve modifying the panic_abort crate to pass the appropriate linker options to emcc.
My notes on AsmJs so far:
- Inline
asm!("JavaScript here")
is badly needed. Currently the JS is placed in an additionallib.js
and the path to it is passed in#[link-args]
. This turns from “works” to “ugly” once dependencies are introduced. - Exporting function via
#[link-args]
is already bad for a single binary, and horrible with dependencies. It requires the dependency to publicly export all FFI methods and the final crate to import these into these and declare them in#[link-args]
. I guess an attribute on exported functions would be a clean solution for this:#[export, no_mangle] fn test_function(ptr: *const u8, len: usize)
. - Alternatively a way to turn
Box<FnMut>
into JS objects could be found, eliminating the need to call into AsmJs by exported functions. - All my code contains
fn main() {}
.
What do you need inline Javascript asm for that can’t be solved via a call to emscripten_asm_const_int
(like this)?
This doesn’t look too bad. Definitely need to try this out! Thanks @cramertj.
Glad I could help!
Does it work for you? It makes my llc generate an infinite number of the following line:
var $11 = ;
Nope, doesn’t do that for me. It works fine.
What is the recommended way to integrate cargo and --target=wasm32-unknown-emscripten? I can get it to work as long as I don’t try to export any functions to js land. Once I do I get one kind of erro or another ex:
“”“
cargo rustc --target=wasm32-unknown-emscripten – -Clink-args=”-s EXPORTED_FUNCTIONS=[’_print_hash’]“
error: extra arguments to rustc
can only be passed to one target, consider filtering
”""
or
“”“
error: the link_args
attribute is not portable across platforms, it is recommended to use #[link(name = "foo")]
instead (see issue #29596)
”""
I know that using a #[link_args = …]
should work, see Call from JavaScript
If I use the #[link_args I the error “error: the link_args attribute is not portable across platforms, it is recommended to use #[link(name = “foo”)] instead (see issue #29596)”
If you’re using nightly, you don’t need any kind of link_args tricks anymore, just mark your function with extern and #[no_mangle] as you would for exporting it to C.
nice, is there a way to import/link custom JS functions? -- -Clink_args "--js-library '$path_to_js_file'"
should do it, but how can i set that argument from a cargo/rust dependency? I was trying to set it from the build script and by setting rustflags
from the toml file (but was getting an error: linker arguments only allowed in the main project due to compatibility issues or something)
@chpio No, you can’t use JS functions directly from native code (even compiled to wasm). --js-library is a different thing that needs to be specifically crafted for Emscripten to understand.