Had it been today, Chrome would have just pushed NaCl and PNaCl no matter what, and then everyone would complain why Safari and Firefox aren't keeping up with "Web" standards.
I really thought, for a time, that we'd be doing everything in the browser. And in a way that's increasingly true, but it all just feels worse than ever. I like WASM and I want to like WASM but the rate of maturity within the ecosystem is incredibly abysmal.
What's worse is that we should all be running our untrustworthy AI tools and their outputs in precisely such a sandbox, and companies are selling the reverse: hosted sandboxes, hosted JS-based VMs.
I guess that was always the problem: there was never any money in a client-side sandbox.
The original NaCl was a 'validated subset' of native CPU machine code (e.g. actual x86 machine code with some instructions and instruction sequences disallowed which would allow to escape the sandbox).
The next iteration was P(ortable)-NaCl which replaced the native machine code with a subset of LLVM bitcode, which was then compiled at load time. Unfortunately with this step NaCl lost most of its advantages. Startup time was atrocious because it was basically the second half of the LLVM compilation pipeline (from LLVM-IR to machine code). LLVM-IR also isn't actually great as CPU-agnostic bytecode.
WASM was designed from the ground up as CPU agnostic bytecode that's also much easier and faster to validate.
The only major advantage of PNaCl vs early WASM was that PNaCl supported shared-memory threading right from the start (this is still knee-capped in WASM because of the COOP/COEP response header requirement).
...apart from Emscripten => asm.js => WASM, and Google's NaCl/PNaCl there was also a system by Adobe (Flascc/Alchemy(?) I forgot all the names this went through) to compile C and C++ code into Adobe Flash bytecode.
I have an ancient blogpost from 2012 which compares the three (and where I have been flabbergasted by how well Emscripten actually worked - and this was even before asm.js - the linked demo is unfortunately no longer up):
IIRC a big reason it didn't end up working was because NaCl was such a "big" technology and asm.js such a "small" one that asm.js was able to reach production-ready first despite starting work several years later.
https://www.destroyallsoftware.com/talks/the-birth-and-death...
(And to those who haven't encountered this before, I strongly recommend a watch. It may be the greatest tech talk of all time, for certain values of greatest.)
And at some point we're going to have a period or war and our psychological attachments to old programming paradigms will be released so that we can move on to a more advanced way of doing things (but that won't stop your bank from running YavaScript for at least another 85 years).
12 years on, it’s shocking how much of his fiction became reality.
[0] https://www.destroyallsoftware.com/talks/the-birth-and-death...
But wasm is too isolated from javascript. From my limited use of it, I was considering trying to compile to asmjs instead.
But I wasn't sure that emscripten still fully supported it.
You can't call most web apis from wasm.
But more important for what i was trying to do, you can't zero copy buffers from js to wasm.
Everything is a trade off. The isolation is a good thing, but also a bad thing.
asmjs is going to be strictly more limited in interacting with JS than wasm. You're basically limited to simple number values and array buffers. Whereas wasm now a days has GC types and can hold onto JS value using externref.
> But more important for what i was trying to do, you can't zero copy buffers from js to wasm
I'm pretty sure you can't do that with asmjs either. There is a proposal for zero-copy buffers with wasm: https://github.com/WebAssembly/memory-control/blob/main/prop...
Had WASM not been adopted we would have SIMD in JS ( probably via asm.js) by now. Because we didn't, JS just cannot compete with WASM in many computationally heavy workflows. We'd also have general purpose JS to Asm.js compilation, with few API restrictions, making writing it much easier.
> You can't call most web apis from wasm.
You can't from strict asm.js either, since it only supports numbers (no JS strings or objects) and manages the C heap in an ArrayBuffer object just like WASM.
> But more important for what i was trying to do, you can't zero copy buffers from js to wasm.
Same problem as above, you need to call out into "real" Javascript from asm.js and you can't map other ArrayBuffers directly into the 'asm.js heap' either, a copy is needed. The "Javascript FFI" really isn't much different between asm.js and WASM.
AFAIK as soon as you'd start mixing idiomatic JS and asm.js, you lose the "special sauce", you only got the special asm.js treatment in browsers when putting a "use asm" at the top of a source file, and that would prevent using regular JS features in the same file.
(compiling legacy code with legacy versions of Emscripten is quite frustrating, almost as bad as updating your JS code to be compatible with accumulated changes in the Emscripten ABI)
https://monkeyink.com/ink/blog/archives/2016/08/_this_is_a_f...
"The image is a collage of antique open source art reflecting the open source code."
It's true that in the beginning (around 2017), WASM wasn't much faster than asm.js, but meanwhile WASM has seen real performance improvements.
Featurewise, asm.js is much closer to WASM than to regular JS, it definitely cannot do everything that regular JS can do (mainly because asm.js is limited to the Number type, it cannot deal with JS strings or objects).
I don't think Chrome ever did an asm.js specific optimization.
Furthermore, if you use wasm, you'll have fewer bounds checks (because of better memory allocation strategies[1]), access to SIMD, bulk memory operations, and a host of other niceties that have been added to wasm over the years. If your asm.js code is outperforming someone else's wasm code, that probably just means their wasm code is worse.
[1]: https://spidermonkey.dev/blog/2025/01/15/is-memory64-actuall...
I took off the shelf wasm crypto libraries to compare it, but the leading one was 10x slower.
will try to rip it out of the project and put it in a standalone benchmark.
Last time I tried https://github.com/Daninet/hash-wasm
edit: I focus on browsers, that's wasm but not for browser envs.
----
https://theultdev.github.io/web-sha256-benchmark
https://github.com/TheUltDev/web-sha256-benchmark
seems it is chrome wasm that is slow.
asmjs is about the same speed in chrome and firefox (with asm optimizations still enabled) but wasm is slow as hell in chrome, asm still better.
side note: someone mentioned native crypto.subtle, but that doesn't have incremental hashing so can't use it for large files. however I do use it in practice for smaller files.
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypt...