← Back to context

Comment by DarkUranium

21 hours ago

I think one of the issues is that WASM is notoriously hard to generate code for because they decided to use an IR that's fundamentally incompatible with literally any existing native compiler backend's IR (not counting very specialized ones or toy direct-ast-to-machine-code compilers).

It feels like nobody actually consulted actual compiler writers when designing this. I'm sure that isn't true, but it definitely feels that way. (I suspect the truth is that they were consulted, but ignored.)

It means codegen needs to resort to all sorts of hacks (like the relooper) in order to target WASM, a property not shared by any other target.

And apparently, the way they handle variables also results in deoptimization, though I don't recall the details of that.

Add the fact that interacting with the browser on the web still has to go via JavaScript to this day (for the most part, at least), and, well.

---

TL;DR a combination of poor IR design that has a massive impedance mismatch with pre-existing compilers (and most new ones, because it turns out there's a reason the WASM approach isn't standard) plus WASM still being a second-class citizen in its supposed primary environment (the 'W' in WASM) --- the former ensures targeting it consumes a lot of resources/time, the latter ensures the bar for that to be worth it is much higher.

You can target most architectures with little trouble (at least a a baseline --- optimization's a hard problem regardless of target, except maybe SPIR-V due to the recommendation that pre-optimization is limited in scope). But WASM is completely out there, it's closer to trying to target e.g. Java (not JVM!) at the backend instead of machine code or some other IR.

You don't make an IR intended to be targeted by existing/native compilers by making it completely different to anything they had to target before and completely different to their own IRs and representations ... unless you're the guys behind WASM.

I don't think the controversy about Wasm's structured control flow has anything to do with any of this? It's not actually difficult to target Wasm in codegen; I've never heard of any real-world compiler project complaining that this was a major burden. ABI concerns are at a different level.

Most low-level IRs don't do structured control flow because most low-level IRs don't need to be translatable to verified-safe machine code in a single fast pass, whereas for WebAssembly that's a core design requirement.

  • http://troubles.md/posts/why-do-we-need-the-relooper-algorit... has a more detailed version of this argument: if WebAssembly had used a CFG as the basis for its control flow, it would have been easier to compile to and easier to efficiently execute/translate while maintaining safety, and maybe GCC would have released a WebAssembly backend by now.

    The author alleges that the real reason WebAssembly uses loop/block is because that's how V8 worked internally at the time and Google didn't want to go to the trouble of implementing something different. But more recently V8 has started moving towards CFGs ( https://v8.dev/blog/leaving-the-sea-of-nodes ) so maybe there's hope in the future.

    • I'm familiar with that post. However, it doesn't include a convincing argument that a CFG interchange format wouldn't have performance costs for Wasm runtimes; it just handwavingly asserts this. It blames Google because Google is a popular villain, but the other three browser vendors (this was before Edge adopted Chromium), all of which initially used different Wasm runtime architectures from Google and from one another, were also in favor of structured control flow, and I assume they knew what they were talking about. Once you get past the conspiracy theory, it's clear that the real issue is just that the author disagrees with the Wasm committee's decision to trade off convenience for compiler writers in order to make things work better for runtimes.

      More to the point, none of this has anything to do with ABI.

From what I remember, it was specifically chosen (among other reasons) because of experience with the JVM, where it was difficult to verify bytecode type-safety due to unrestricted jumps and branches.

So the choice was made to put the burden of regularizing the control flow on the compilers at compile time, rather than the browser engine at website load time. Which seems rational to me.