Skip to content

Support wasm exception handling for Emscripten target #112195

Closed

Description

@hoodmane

View all comments

Currently the Rust Emscripten target supports js exception handling. I've been trying to get it to support also wasm exception handling. The patch to get it to exclusively use wasm exception handling is quite small. The following suffices:

Patch
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index a0a640473eb..cd88648911a 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -110,7 +110,7 @@ fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
         }
 
         if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
-            add("-enable-emscripten-cxx-exceptions", false);
+            add("-wasm-enable-sjlj", false);
         }
 
         // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 94acdea894b..2909401836d 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2057,12 +2057,11 @@ fn add_order_independent_options(
     }
 
     if sess.target.os == "emscripten" {
-        cmd.arg("-s");
-        cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
-            "DISABLE_EXCEPTION_CATCHING=1"
+        if sess.panic_strategy() == PanicStrategy::Abort {
+            cmd.arg("-sDISABLE_EXCEPTION_CATCHING=1");
         } else {
-            "DISABLE_EXCEPTION_CATCHING=0"
-        });
+            cmd.arg("-fwasm-exceptions");
+        }
     }
 
     if flavor == LinkerFlavor::PtxLinker {

I'm not sure what the best way is to add support for a choice between these two options.

@aheejin Is there any way to turn -enable-emscripten-cxx-exceptions back off by adding another argument? It would be convenient to be able to inject -mllvm -disable-emscripten-cxx-exceptions -mllvm -wasm-enable-sjlj and get wasm exceptions to work...

Activity

  1. hoodmane commented on Jun 2, 2023

    @hoodmane
    ContributorAuthor

    If a target has more than one stack unwinding ABI is there some standard way to switch between them?

  2. hoodmane commented on Jun 2, 2023

    @hoodmane
    ContributorAuthor

    Ah it seems that the following may work to disable js exceptions and enable wasm ones:

    	-C link-arg=-fwasm-exceptions \
    	-C link-arg=-sDISABLE_EXCEPTION_CATCHING=1 \
    	-C llvm-args=-enable-emscripten-cxx-exceptions=0 \
        -C llvm-args=-wasm-enable-sjlj 
  3. Jules-Bertholet commented on Jun 2, 2023

    @Jules-Bertholet
    Contributor

    @rustbot label O-wasm

  4. rustbot commented on Jun 2, 2023

    @rustbot
    Collaborator

    Error: Label o-wasm can only be set by Rust team members

    Please file an issue on GitHub at triagebot if there's a problem with this bot, or reach out on #t-infra on Zulip.

  5. added
    O-wasmTarget: WASM (WebAssembly), http://webassembly.org/
    on Jun 2, 2023
  6. aheejin commented on Jun 3, 2023

    @aheejin

    @aheejin Is there any way to turn -enable-emscripten-cxx-exceptions back off by adding another argument? It would be convenient to be able to inject -mllvm -disable-emscripten-cxx-exceptions -mllvm -wasm-enable-sjlj and get wasm exceptions to work...

    Which tools do you call? clang? And the option you want to use is either -enable-emscripten-cxx-exceptions -mllvm -enable-emscripten-sjlj (for Emscripten (JS) exceptions/SjLj) or -fwasm-exceptions -mllvm -wasm-enable-sjlj (for Wasm exceptions/SjLj). In which case do you need -disable-emscripten-cxx-exceptions? Only specifying -fwasm-exceptions will enable Wasm EH and disable Emscripten EH, and specifying -enable-emscripten-cxx-exceptions will enable Emscripten EH and disable Wasm EH. If you give both -enable-emscripten-cxx-exceptions and -fwasm-exceptions at the same time it will error out.

  7. hoodmane commented on Jun 3, 2023

    @hoodmane
    ContributorAuthor

    The issue is that Rust always adds -enable-emscripten-cxx-exceptions, so if I want to use wasm-exceptions I have to turn it back off somehow. But -enable-emscripten-cxx-exceptions=0 seems to do that... at least some of the time.

  8. added a commit that references this issue on Jun 24, 2023
  9. added
    O-emscriptenTarget: 50% off wasm32-unknown-musl. the savings come out of stdio.h, but hey, you get SDL!
    on Oct 11, 2024
  10. hoodmane commented on Oct 15, 2024

    @hoodmane
    ContributorAuthor

    I made a bit more progress over here:
    emscripten-core/emscripten#19612

    It seems that we need to adjust the ir generated for the try intrinsic and I have a guess of what the IR should be. But I would probably need help from someone who understands rustc_codegen_llvm a bit better.

  11. purplesyringa commented on Jan 17, 2025

    @purplesyringa
    Contributor

    Are there any plans on how wasm vs JS exceptions are going to be configured? (-Z emscripten_wasm_eh is funny, but I suppose there's going to be a -C option?) Would this option be readable via a cfg?

  12. hoodmane commented on Jan 17, 2025

    @hoodmane
    ContributorAuthor

    Well if you look at the MCP and [the PR] (#131830) you'll see in the discussion that we aren't really thinking about stabilizing it to a -C flag but eventually turning it on always and then later removing the option to turn it off. I think we'll need more discussion before each of these changes though. Do you expect to need the legacy exception handling going forward?

    There is a cfg flag for it but you have to enable an internal feature to access it. I'm not sure if you can enable internal features outside the standard library though.

  13. purplesyringa commented on Jan 17, 2025

    @purplesyringa
    Contributor

    I do not necessarily need legacy exception handling myself, but I'm maintaining a crate that needs to use different code for different EH ABIs, hence I'm interested in knowing what the way forward is going to be so that I can update the code preemptively. I understand this whole crate idea is based on thin ice, so I'll just hardcode cfg(emscripten_wasm_eh) for the time being, but if there's a public cfg, I'll happily use it instead.

  14. hoodmane commented on Jan 17, 2025

    @hoodmane
    ContributorAuthor

    Cool! I appreciate that you are making the effort to support emscripten.

  15. added
    A-runtimeArea: std's runtime and "pre-main" init for handling backtraces, unwinds, stack overflows
    on Jan 22, 2025
  16. 58 remaining items

  17. madsmtm commented on Nov 1, 2025

    @madsmtm
    Member

    FWIW, it would be possible to handle this in cc-rs without the extra #[cfg(wasm_eh = "...")] (which needs lang signoff n' everything), something like:

    if target.env == "emscripten" {
        let rustc_version = todo!();
        let default_value = rustc_version >= (1, 93); // Or whenever this will land
        let wasm_exceptions = wasm_exceptions_from_env().unwrap_or(default_value);
        if wasm_exceptions {
            add_flag("-fwasm-exceptions");
        } else {
            add_flag("-fexceptions");
        }
    }

    cc-rs already has a mechanisms in place for parsing CARGO_ENCODED_RUSTFLAGS.

  18. kripken commented on Nov 4, 2025

    @kripken

    @hoodmane are you asking about

    Doesn't binaryen have support for converting the old wasm eh method to exnref?

    ? If so then yes, this is the wasm-opt flag:

      --translate-to-exnref                         translate old Phase 3 EH 
                                                    instructions to new ones with 
                                                    exnref 
    
  19. bjorn3 commented on Nov 4, 2025

    @bjorn3
    Member

    Does that flag also work if the wasm module was linked from two object files where one uses legacy exceptions and one uses exnref? If so that would allow Emscripten and rustc to switch to exnref by default at different times without issues.

  20. kripken commented on Nov 4, 2025

    @kripken

    @bjorn3 Hmm, I can't think of a problem there. But @aheejin would know best.

  21. added a commit that references this issue on Dec 4, 2025
  22. added a commit that references this issue on Dec 5, 2025
  23. curiousdannii commented on Dec 5, 2025

    @curiousdannii

    Don't forget to announce this in the blog please, and explain the steps needed to switch back to JS exceptions.

  24. bjorn3 commented on Dec 5, 2025

    @bjorn3
    Member

    Tagged the PR with the relnotes label. #149674

  25. bjorn3 commented on May 25, 2026

    @bjorn3
    Member

    #156928 will remove -Zemscripten-wasm-eh if it gets accepted. Please leave a comment if you believe we should wait longer.

  26. added a commit that references this issue on Jun 3, 2026
  27. added 3 commits that reference this issue on Jun 3, 2026
  28. added a commit that references this issue on Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-panicArea: Panicking machineryO-emscriptenTarget: 50% off wasm32-unknown-musl. the savings come out of stdio.h, but hey, you get SDL!O-wasmTarget: WASM (WebAssembly), http://webassembly.org/

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions