Can we have either a new target wasm32v1-unknown-unknown or a set of new targets wasm32(v1)?-web-bindgen?

Hey, just for the record, we had similar conversation regarding Ruffle in Add wasm32v1-none target (compiler-team/#791) by graydon · Pull Request #131487 · rust-lang/rust · GitHub .

Very similar story: we want to keep support for Safari, which forces us to either switch to nightly to use build-std, or freeze at 1.81 until we decide to drop these browsers; we can live with any of these choices, we just consider it unfortunate to be required to do this kind of choice in the first place.

And also similar regarding -unknown-unknown and no_std: even if we wanted to go no_std, we're both blocked by missing some core APIs like Read, and by a decent chunk of our dependencies not being marked no_std.

(And... we kinda prefer not to - there are more things in std than Read that are not direct OS abstractions that we like to have. And some things that are "hacky", like std::sync::Mutex implemented as noops (and rest of std::sync), we honestly see as an advantage; without it the code reuse between web and desktop would be much harder. I understand the "relying on "std" which panics or returns errors on each non-trivial sneeze" issue - though as far as we know, it has never significantly bit out project, since the solution of "be careful not to write OS-abstraction-dependent code in the shared crate" we already happened to be following by design)

6 Likes

Chiming in to second @stephanemagnenat : while I agree with the long-term goal of making wasm a nostd target until WASI/browser is ready, I feel rather uncomfortable with the attitude I'm seeing in this thread about not providing a clear migration/upgrade path for those of us whose codebases rely on std compiling with wasm32-unknown-unknown.

wasm32-unknown-unknown continues to compile, it hasn't been deprecated. It is only when you add the additional requirement of supporting older browsers that you need something different. IIRC the v1-none target was motivated by things like minimal wasm interpreters or sandboxes, in contrast to browsers which follow the evolving wasm target specification.

Note that wasm targets are mostly tier-2 and maintained by interested parties and less managed by the general Rust teams. So to get progress someone either has to convince the target maintainers to add better support for browsers specifically or put in the work themselves, it's unlikely to happen on its own.

CC @alexcrichton @graydon

Note that wasm targets are mostly tier-2 and maintained by interested parties and less managed by the general Rust teams.

A comment about that: First of all, I fully understand and appreciate that a lot of Rust development is a volunteer-based effort and I'm deeply thankful to all the people who spent countless hours to make such a great product. Fortunately, there is now a foundation with significant money to support the core of the project, and hopefully, the parts that are necessary but less fun to do on a hobby basis.

Wasm, in the form of wasm32-unknown-unknown + web-sys + wasm-bindgen, is prominently presented on the language front page, and as such it is very strange to me that it is only a tier-2 target. This feels like a mismatch of priorities between the marketing and the development teams. From a business point of view, isn't it inconsistent to promote a product that does not receive first-class support? Imagine how users feel when, after having invested into WebAssembly Rust based on the promises from the language page, they are told that they need to solve a very common platform issue by themselves?

So my call is not a complain to the hard working contributors to do even more, but rather to the project leadership. Maybe it is possible to dedicate some of the foundation resources to better support core advertised targets?

1 Like

We are generally really conservative when it comes to platform support. Our x86-64 targets still use v1, even if many very old CPUs have v2 already. We still support very old versions of glibc as well. Given this, it is surprising to me that we updated our WebAssembly target, which is commonly used with browsers, to break 3% of the web on old Safari. That's a lot and I agree with everyone who complained about this here that that's a mistake and is going to hurt users. We are going to need to untangle the Wasm target to better support the different use cases, but that will take a long time. Given that, as the blog post mentioned, multivalue doesn't make much of a difference to Rust, I we should seriously consider disabling this feature if possible.

Safari 16.4 was released in March 2023. Baseline, which is an attempt to define what features should be used by Websites, defines "Widely Available" (which I think Rust should target at least) to take 30 months of support in all major browsers, which will happen only in September 2025.

2 Likes

The relentless drumbeat of progress for the wasm target is inherited from llvm which in turn is inherited from the webassembly project itself, which is a bit more aggressive than what the baseline page lists.

Perhaps Rust's specific issue is that it makes it harder to relax the default features because one needs nightly to use build-std. That's being worked on.

2 Likes

Just my two cents (as another contributor to the Ruffle project; like, and in agreement with, @adrian17 above): Making build-std stable soon could perhaps be the best outcome, so everyone could choose what kind of std (with stubbed bits or not), using which WASM extensions, to use. This goes both ways: Enabling beneficial ones for modern browsers (bulk-memory could help a lot in some use cases), and disabling the default ones for legacy browser support.

I think this should follow from the wish to have "fearless upgrades" for rustc.

Every now and again there's a discussion of whether rustc should have LTS releases. The conclusion is always that it shouldn't, and that that's OK because nobody should find they have to run an older version.

Dropping support for targetting browsers that Rust users want to have on their "supported browsers" list goes against that.

1 Like

I'd also note that arguably Safari support targets should be more conservative than those of other browsers, since unlike other browsers, the version of Safari an iOS or macOS user can use is limited by the OS itself.

It is worth noting that apparently, at least for Ruffle, the upgrade to wasm-bindgen 0.2.97 fixed compilation of the WASM target on Safari 15 - 16.3 when using Rust 1.82+. Compilation for Safari 14.1, however, was still broken. However, in Reconsider usage of bigint in generated JS code · Issue #4246 · rustwasm/wasm-bindgen · GitHub, daxpedda did say "Safari's v15 implementation of the reference type proposal was faulty (don't remember the details), we should pretend that support was added in Safari v16." So your mileage may vary.

I can confirm that 1.82 broke our wasm code in Safari 15. There is a hacky workaround (for now, might stop working in a future version) — setting strip = true (maybe in combination with wasm-opt, unclear to me) somehow makes Safari 15 work again. After applying the hack, a massive amount of Safari 15+ crashes coming in through Sentry were fixed.

See WebAssembly with Reference Types cannot be parsed · Issue #15566 · webpack/webpack · GitHub

Edit: about 10% of our Safari users are below v16.4.

For me there's a lot going on in this thread but I think there's a lot of good points to call out too. The tl;dr; is that I don't think we're in a great position right now (sort of self-evident given the discussion) but there's no easy way out of this. There are a number of competing concerns and desires here, but I can try to offer my 2c on thoughts on ways forward on this.

Guidelines for enabling wasm extensions

As far as I know there's no currently written down policy of "here's when it's decided to turn a wasm feature on". The WebAssembly specification has been evolving for years and will continue to do so. Whether or not it makes sense to turn a feature on-by-default will continuously come up. Personally I don't think either extreme of "never turn anything on" or "turn everything on after 6 months" is feasible.

Right now Rust's default set of extensions enabled is inherited from LLVM. For discussion of the various policies there the internals forum here isn't the best place since the wasm backend LLVM maintainers (mostly Googlers working with Emscripten) likely don't frequent here. Instead I'd recommend raising a discussion in the tool-conventions repository.

I'll specifically call out here though that I at least personally think it's important to keep C/C++/Rust/etc in sync. While it's certainly possible to have different defaults in Rust than in LLVM I believe that will cause confusion in the long run. I understand it's more work to engage with external folks, but I think it'll result in a better result in the long run.

I was not personally part of the discussion to turn these proposal on-by-default in LLVM, so I don't know if Safari was ignored, forgotten, explicitly chosen against, or something else. I did raise an issue on the tool-conventions repository which has some discussion which interested folks may wish to engage with as well.

Adding more Rust targets

While on the surface adding a wasm32v1-unknown-unknown target might seem like the most straightforward path here I agree with the arguments against this, and I think once the complete picture is seen it's clear that this is no longer an "obvious path forward". Both the benefits and downsides of std on wasm32-unknown-unknown are real and I don't think there's an obvious decision of "it's worth it" vs "it's not". We already have a lot of wasm targets and it'd be unfortunate to keep adding more for various combinations, it's a pretty heavy hammer for what should be a relatively localized solution.

If someone is interested to champion this cause though I'd recommend following the MCP process for adding a new target to the compiler. It's pretty clear what this target would be if it were added, but there should also be dedicated discussion exclusively for that in Zulip. (although this thread is a bit of a precursor to that as well of course)

Using -Zbuild-std

Sort of like wasm32v1-unknown-unknown this is a possible candidate for "most obvious solution". That being said the pain of using nightly Rust and possibly resulting in breakage is also very real. Integrating -Zbuild-std into wrapper tools like wasm-pack is not always obvious and can be difficult to figure out. Ideally -Zbuild-std would be stable but that's a whole separate thorny set of questions.

I'm not aware how best to push on this in terms of helping making it stable. My guess is that it would require a lot more context and implementation effort outside of the interests of this thread. I also suspect Cargo folks are well-aware of the use case of recompiling libstd with/without CPU features so I at least personally reach the (unfortunate for this thread) conclusion that there may not be much to help the -Zbuild-std stabilization effort at this time (I'd be happy to be wrong though!)

Adding a *-bindgen Rust target

I personally intentionally never advocated for this when I was maintaining wasm-bindgen, and I would have advocated against it had it been proposed at the time. I'm not currently maintaining wasm-bindgen though so things can always shift, though.

The wasm-bindgen crate was never designed for stability of compiler artifacts in mind and it has quite a lot of hacks which if anyone were to try to replicate they'd (reasonably) run away screaming. For example did you know that wasm-bindgen has an interpreter for wasm which it executes to figure out types in your program? I always felt this was an appropriate hack for a crates.io-based crate but wildly inappropriate for something like the Rust standard library.

In that sense, at least if foundational parts haven't changed in the meantime, my opinion is that *-bindgen targets in Rust is a dead end. It shouldn't happen and problems need to be solved via some other means. The "easiest" alternative solution here is to probably improve integration with Emscripten which is already tailor-made for running C/C++/wasm/LLVM on the web while assuming that JS exists. I put "easiest" in quotes here though because I realize this probably isn't easy, and I don't even know the depth of it myself as I'm not that knowledgable about Emscripten.

Timelines of a solution

One thing I'll also call attention to is the various timelines involved here. For example if it takes a year or so to figure out how to officially solve this then that technically means it's no longer a problem because at that point Safari support for wasm32-unknown-unknown is probably at a high-enough level it's ok to use then. This to me cuts both ways in terms of if folks need a solution right this red hot second then pushing on some solutions in this thread may not be the best path forward due to the timelines involved. On the other hand though now's the best time to figure out solutions for these so this doesn't keep coming up in the future.


Sorry for the long read and I'm also sorry I can't really offer much in the way of a strong conclusion here either. I suspect solving this "for real" will require some dedicated work by someone which is more than "just copy that solution over there and tweak it a bit", since this thread is showing that all the "easy ideas" have serious drawbacks one way or another.

3 Likes

Is the faulty part for overlong call_indirect encodings? Or with the rest of the reference types proposal? Only the former is used by rustc when reference types are enabled. The rest if I recall correctly was used by default in older wasm-bindgen versions when any object file indicates reference types usage, while newer wasm-bindgen versions keep it disabled by default even in that case.

On my side, the errors I'm seeing in Safari up to and including 16.3 are of type RuntimeError: Out of bounds table access (evaluating 't.crop_and_call(e,n,_)') when running Rust-based image cropping code in a web worker, with wasm-bindgen version 0.2.99. I feel that this is a different issue from the one affecting Safari 15, but I did not manage to create a minimal reproducible test case and thus I might be wrong.

The error reported by someone using Safari 15 prior to the wasm-bindgen bump said RuntimeError: Out of bounds table access (evaluating 'b._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h281f2f93d3d6cf28(n,e,t)')