Why am I excited about WebAssembly?
blog.colinbreck.com
blog.colinbreck.com
My team has built out WASM/WebGPU support for Unreal Engine 4 and is in progress for Unreal Engine 5 (and other engines) with a suite of optimization tools like asset streaming (so you don't have to download a whole game at once) and advanced texture compression (necessary for low powered devices like mobile/Chromebooks).
More info on us in this Venturebeat article we were featured in:
https://venturebeat.com/2022/05/12/wonder-interactives-the-i...
WebGPU in general is very nice. We're building a game engine[0] that uses Zig to build Dawn (Google Chrome WebGPU implementation) from source for running on desktop / Steamdeck, and working on browser support via WASM now.
The future is bright here.
And is the stutter issue that plagues anything 3d in the browser, solved?
As for blaming Apple, the reason why WebGL 2.0 lost compute shaders, a GL ES feature from 2014 (!), was because Google dropped it from Chrome after two failed attempts from Intel to bring it, as WebGPU was just around the corner, two years ago!
This is what happens with committee APIs, everyone messes up and we end up stuck with MVPs forever.
As for what we are getting instead, it is quite clear from console vendors, server side rendering with pixel streaming.
(a) WebGPU could be dangerous anyway, so why not just expose Vulkan entirely with no safety?
(b) Committee-designed APIs are always doomed to fail, equally Google/Apple/Intel's fault, they won't ever ship a non-MVP anyway, 'so why bother' I presume?
(c) Console vendors are pushing server-side rendering pixel streaming too, so we won't have any control over our devices ultimately in the future anyway - so none of this matters.
If those are the arguments, I'd rather have WebGPU than not have it, personally.
Looking forward to WebGPU support on ShaderToy, pity we will have to rewrite all shaders to Rust flavoured WGSL.
WebAssembly does nothing to address any of this. The least important part about this is the language the code is written in. I think this person has thoroughly confused code running in a VM with code being secure, safe and performing to specification.
The benefits WASM brings are:
1. Sandboxing - security 2. Isolation - if a plugin crashes, it won't bring down the whole program 3. Interoperability - write a plugin in lots of different languages, not just lua or js 4. Speed
I'm hoping to write my thesis for my master's degree on this topic this year. I'm also in the process of writing a game like screeps, where users provide a WASM script to control units for an RTS-style game (without combat though) https://github.com/JMS55/botnet.
It's amazing how simple it is to constrain memory usage, runtime duration, and secure exported functions to a WASM VM. Performance is also great - currently about ~6 microseconds per tick per unit, up to ~200 microseconds when doing expensive pathfinding. All that, while letting you program your units in Rust - the same language as the server is written in, while being able to share code with the server, and not having to use something more script-y like lua.
Curious if people have seen any other routes to doing it via WASM.
> definitely don’t go converting all your websites’ JavaScript to WebAssembly! However, that’s not really the aim of WebAssembly. Its aim is to enable richer experiences on the web that require higher performance, for example machine learning, virtual reality, or gaming.
WASM functions aren't meant to replace small JS functions on your standard website. It's meant to be a general purpose VM you can target large amounts of non-webpage code to.
Whereas Asm.js had (has?) perfect backwards-compatibility with unsupported browsers and JS interpreters, WASM requires users to remain on the bleeding edge of new browser features as it continues to evolve, and introduces a whole host of fantastic new bottlenecks as the designers puzzle over how to interface WASM modules with the rest of the facilities JS can already access.
The whole thing is a hilarious boondoggle- an insane amount of effort and complexity for mild bandwidth and page-load time savings- made all the more hilarious for the fact that a remarkable number of people seem unaware that Asm.js ever existed in the first place.
WASM has continued to evolve past what's possible in JS/asmjs since that article as well, with things like SIMD support
E.g. if you had only done rendering on a CPU and someone came by and said "we can do all sorts of stuff we couldn't do before with this GPU check it out!" it'd be easy to say "I could do all that on a CPU" and you could even show the exact same benchmarks presented here and then say "see, the CPU even runs the single threaded factorial function many more times per second than this new GPU". Everything you said would be absolutely correct in the most literal form yet it'd still be completely missing the point of why the GPU was made and how to assess if it fits that purpose better.
Then someone shows you the GPU doing rendering it was designed to do well better than the CPU and the reply is "So it is about the GPU being faster than the CPU?". Yes. No. It depends what context you're asking from. Traditional use cases no, what it was designed to do well yes.
The original article which talked about WASM being slower itself specifically notes this relation of purpose, functionality, and performance it's just tucked away in the conclusion:
> definitely don’t go converting all your websites’ JavaScript to WebAssembly! However, that’s not really the aim of WebAssembly. Its aim is to enable richer experiences on the web that require higher performance, for example machine learning, virtual reality, or gaming.
WASM was an evolution to say rather than do all that why not just have a way to tell the browser's VM what we want to do directly. Now instead of having to parse JS syntax to find type hints and so on the browser can just parse pre-encoded bytecode. Instead of having to understand certain logic is trying to emulate functionality like 64 bit integer multiplication and optimize it out the browser can be told to do a 64 bit integer multiplication directly. Since this is a separate interface from JavaScript it allows work on things like threads, SIMD, and garbage collection to not worry about how JavaScript has a hard time with these concept since JavaScript is not the base anymore.
JIT-compilation with optimisation (and de-optimisation!) is costly, so browsers tend to only interpret Javascript the slow way at first, enabling each (higher) tier of compilation only after run-time profiling. With higher complexity comes higher risk of errors, and there have been a number of serious vulnerabilities in browsers' Javascript JIT-compilers in the last decade.
Not many companies have the resources to develop a high-performance Javascript engine that can compete with the best.
Also, writing optimised Javascript code so that it gets made into fast JIT-compiled code is a black art.
WASM on the other hand, has been designed so that it could be assembled into machine code straightforwardly in a single pass using little CPU time. You'd get native performance straight away. (Not that optimising WASM runtimes don't exist)
Java introduced a language and library… but the real innovation was that it introduced a cross platform VM that was supported by some organization
WebAssembly is now doing the same thing… but just the cross-platform VM part
Now you can run Python and JS on the JVM these days but these are not de-facto implementations and so their adoption is pretty low. I wonder if the same issue will apply to these alternate WASM implementations of existing languages.
It's not a secret that you can write JS which will be JIT-ed into an extremely efficient machine code. But it's a "secret" - how to write that JS. You would need seriously advanced hackers who can study V8 assembly output and correlate it with used JS features. And do it all the time, when someone changes that code. Or may be even unrelated code changes will change the way V8 compiles that particular code snippet. JS compilation is black magic.
On the other hand, writing C is boring and solved problem. Compiling C to wasm works. It's predictably fast. You can use it for performance-critical code and it'll probably work without any adventures to V8 internals.
Another use case I’ve toyed with is date time. Specifically trying to figure out if something like the rust Chronos crate is a better fit for crunching and calculating dates than something like date-fns or Luxon. Not sure about this one yet.
1. Browser support - its not there yet. you'd have to polyfill. A production level polyfill is 16 KB, and is still very nasacent, and, on top of that, requires support also for BigInt[0]. The polyfill that tc39 put out is decidedly marked as non-production ready[1].
2. Polyfilling - as mentioned above, we have to deal with polyfilling the API, and that isn't a clear and easy story yet. WASM support goes back farther than this.
3. Size - its entirely possible to get WASM builds under 16 KB, and the support is better, espcially for operations on strings and numbers (dates fit this category well). The only complication I haven't quite solved yet is:
A) Can I validate that a WASM build will be under 16 KB. This is crucial. I'd even accept it at 20 KB because of wider browser support[2]
B) Can I fall back to asm.js if needed (there is a slim range of browsers that support ASM.js but not WASM, mostly pre-chromium Edge[3]
C) Is it performant compared to something like Luxon or date-fns? WASM excels at string / numerical operations so my sneaking suspicion is yes, at least in terms of the WASM operations. The complexity will be serializing the operations to a JS Date instance, Luxon & the Intl API might be most useful here
[0]: https://github.com/fullcalendar/temporal/blob/main/packages/...
Don't forget WASM doesn't provide direct access to any OS time APIs (timezone info, current time, regional time change modifications) so the solution will still basically boil down to "call Date() and polyfill a better library" except now you have extra code to ferry the data back and forth to do a few string and math ops. Unless the use case is processing very large datetime datasets in one call the JS<->WASM function call overhead for all of this will probably take the majority of the execution time.
Not to mention after you get all of this solved, tested, and deployed you know as soon as Chrome starts shipping Temporal the cool custom solution becomes 50% slower for the average user despite all the effort because you didn't just use something like a Luxon which automatically updated to use Temporal on release. This may just be me being lazy though :p.
strings & numbers are WASMs strong point, so if you can pack the locale information tightly in a binary format, you might actually win out in the medium term. This shouldn't be a years long project by any means. And frankly, with the way enterprises move, you'll always have some client (at least in my business) where I need to support some modernish browser that may not have Temporal, so if this is more performant (we do alot of date time datasets, so yes, thats part why I'm looking at this) why not?
It could also be the wrong solution. I'll found out one way or another.
WASMs strong point isn't necessarily "strings and numbers" it's running large amounts of compiled code on large amounts of data. Video processing, PDF readers, video games. As an example even computing a large image the Mandelbrot fractal (pure math workload) then passing back an arraybuffer of the pixels was faster in JavaScript until WASM SIMD+Threads finally landed and JavaScripts poor parallelism finally factored in. Doing it with a functional call per pixel JavaScript is still ahead of even WASM with SIMD due to the functional call overhead.
But all that said I think it's a really cool project to try and I hope you're able to build what you're seeking. If you do be sure to post it to HN so I can check out how you managed to pull it off :).
Afaict it's much easier to write a high performance JIT for WASM because those cases aren't possible. And consequently, it's easier for something compiling to WASM to get high performance out.
I imagine Python performance isn’t too great either.
Whereas if you compiled (or translated — not sure how comparable the WASM instruction set is) x86 bytecode to WASM, it’d be a walk in the park.
Not once in my entire life have I heard anyone say this
Almost always its either about it being faster or so they can use a language that isn't JS. And both are those have dubious value because I seen wasm be slower and people complain a lot about lack of tool support. Which is why the other day I claimed very few people use it. I seen many try it once or twice and not want to go through it again
1. Create an object with a fixed number of keys and NEVER add keys, remove keys, or change the data type of a key's value.
2. Make arrays of a set length and only put ONE type data type inside. If that data type is an object or array, all the objects/arrays must have the same type
3. Functions must be monomorphic (always called with the same parameters in the same order of the same type)
Do this and your code will be very fast. Do something else and it will get progressively slower.
Running the profiler in Chrome or Firefox is very easy and it will show you which functions are using up most of your processing time. Focusing on applying these rules to just those functions will usually get you most of the way there.
I wish TypeScript helped more here. I'd prefer if it had a performance option that disallowed or at least warned about these kinds of things.
Which is what wasm will, hopefully, give us in the long run. And ensure that said PL will have to remain competitive against the new contenders, since they can always replace it.
There's nothing you can do to guarantee your JS isn't passed inputs that trigger pathological cases. There's no linter that can guarantee that you're writing code in a way that is the fastest it can be (even with type checking!). Asking developers to be a human linter for the sake of consistent performance is a bad developer experience no matter your skill level.
WASM simply doesn't have this problem.
why doesn't this problem also apply to WASM?
That is comparing WASM+JavaScript vs pure JavaScript. Unsurprisingly there’s some interop overhead. Those benchmarks are not relevant if you’re not using JavaScript (e.g. WASI stuff) or you’re doing the bulk of your calculations in WASM and not rapidly jumping back and forth between WASM and JavaScript.
The second benchmark isn't measuring the performance of Javascript, but the performance of the Javascript sort() call (which most likely is implemented as native code).
In general, WASM should be both in the same ballpark as portable natively compiled code (e.g. not using SIMD), as well as Javascript which has been written for performance (which also means that well written - but non-idiomatic - Javascript can be in the same ballpark as portable native code).
The main advantage of WASM versus JS isn't mainly performance, but predictable performance (because the GC is taken out of the picture, and the linear memory model), and that WASM is a better compilation target than JS.
I'm not 100% certain the W3C working group won't end up fumbling it, but if you're not excited about wasm then you probably just don't know much about it.
As for Docker, it is basically Java Application Servers full with YAML spaghetti to the point it makes me miss Websphere 5.
Or even better, mainframe and microcomputers language environments like on IBM i, z/OS and Unisys ClearPath.
Maybe its founders should have learned what preceded it.
If anything, Java is a much much safer bet than the oligopoly of WebKit/Blink.
But also, that it's more for non-GC languages.
I wish browser makers would focus into making the browser user and development experience actually work instead of going after the latest shiny feature.
How about not relying on the JRE? Mobile support? Partitioning between applet world and JS world?
Browsers would include a JRE (which they actually did at a time as well, but that’s just a tiny technicality either way), there wasn’t even mobiles capable of browsing the net at the time, but there is nothing inherently unsolvable, it’s not like there is no partitioning between wasm and js world, but in this alternative reality there wouldn’t be js. Java could have access to the DOM.
WebAssembly doesn't have this problem: almost every user is already running a browser that supports it.
The project began in 1991 targeting set-top boxes. [source](https://web.archive.org/web/20100210225651/http://www.java.c...)
WASM is another iteration of the same noble idea done with different technologies at a different moment.
Java and the JVM have been incredibly successful. WASM has the potential to bring the dream of a universal binary even farther.
Never heard of UCSD Pascal?
The big win is the runtime doesn't need to check pointers for validity. However there are some downsides relative to native code:
1. Can't address more than 4GB of memory
2. Can't be efficiently implemented on 32 bit systems
3. Can't share memory between WASM modules
4. NULL dereferences don't trap (I think)
I would not be surprised if future CPUs had hardware support for this stuff, e.g. load/stores with a mask to confine the pointers.
https://www.youtube.com/watch?v=glL__xjviro
"The Security Risk of Lacking Compiler Protection in WebAssembly"
Currently WASM is both a client side and server side runtime. It's not clear where it will be in 5 or 10 years. I don't see a compelling server side story. Why WASM and not C#, Java, Node, Python, Rails (I intentionally don't write Ruby) or whatever any of us is using now with its standard runtime?
What makes you say Wasm is a server side runtime / imply that it's meant to be one?
There have been a few people who say if wasm (WASI on the server) existed already, Docker wouldn’t need to exist. Docker runs a whole OS just to run your binary - imagine the benefits of Docker but just running your binary.
It’s all early days so I am slightly waving my hands, but a lot of this works now. Check out _wasmtime_.
I think I've seen wasmtime before. If I needed to interface to any C/C++ things on the server I would probably just write in C/C++ (or Gx) yeah.
Say you are a C# developer and there is a C / C++ / Rust thing you want to use as a dependency.
Well, WASM is your interop layer. Same with Node.js, Deno, Go etc. You can start to share alot more code with a solid interop layer that WASM presents.
IBM and Unisys almost since the 1960's, depending on which model we are talking about.
I don't understand why you use a framework instead of a language there, but it seems to be in the same category of mistake as asking “why <compilation target> and not <thing that can be compiled to that target>”. They aren't mutually exclusive alternatives.
Losing Flash's excellent authoring tools is still a hard blow though.
.NET Core started as the Silverlight runtime, didn't it?
The article expressly stated that was not the exciting part, for them.
This is another iteration of the same old byte code blah blah, and each iteration has gotten better, and this is the best yet. Maybe.
Yeah, if you squint hard enough, everything new is just the reinvention of the wheel [4]. And yet – sometimes small, incremental improvements are what it takes to push a concept (steam powered machines, or bytecode for execution in the browser) from niche applications to being a breakthrough technology. I don't know if WebAssembly will be that incremental improvement, but claiming that it won't because Java tried and failed is a lazy, fallacious argument.
[1] https://en.wikipedia.org/wiki/Watt_steam_engine
[2] https://en.wikipedia.org/wiki/Newcomen_atmospheric_engine
[3] https://en.wikipedia.org/wiki/Aeolipile
[4] Speaking of reinventing the wheel: Those radial tires, eh, who needs them? They're basically just like cross ply tires. Not to mention the spoked wooden wheels that have been around since forever.
Like C and O are both chemical elements, so basically interchangeable, or like horse carriages and oil tankers are both methods of transporting things.
Provide relatively efficient support for languages other than JavaScript that is reliably available in major browsers without user action, an insecure plugin model, etc.
Wasm also has the ability to stream bytecode and validate/compile as it streams (fast parsing was a major design goal) resulting in much faster startup times.
Wasm is easier to integrate into the JIT/VM already shipping in browsers so they don't have to ship two massive engines.
Wasm is a bit lower level which should result in faster execution than the JVM in the future.
Wasm doesn't require garbage collection.
Wasm has unsigned integers.
Wasm isn't encumbered by Oracle.
Really? Is that a question?
The trend over the years has been to structure our code. GOTO throws all of that away. Jump straight over the guards.
At the bytecode level, all structured constructs get compiled into forms that rely on goto statements. Is this inherently insecure? Should the bytecode require structured programming too? How does this guard against malicious use any more than verified bytecode that relies on gotos?
But not really in high level languages
Everything before it eventually let you have full access to the host file system, if you asked nicely, were given permission, or leveraged a bug in the system.
"The Security Risk of Lacking Compiler Protection in WebAssembly"
That's the most important reason to use WebAssembly instead of Java.
It's also nice that it can do all kinds of things Java can't, but that's just icing on the cake.
What killed Java was to a large part loading times. First the Plugin had to load, then the bytecode had to be run. On many systems one immediately knew when Java was used by the browser getting slow and sleeping for a while.
Flash loaded a lot faster (also systems were better, generally) however Flash apps completely messed with user experience.
Nowadays JavaScript can do a lot of things better (say changing URL, history support, back button) which can be integrated with a wasm tool for having a way more seamless integration.
As a user you simply don't notice if something is using JS or wasm.
From there it imo carries over to the server side and other places. Java simply got a bad reputation as resource hog used for bad UI in Applets and many people looked elsewhere.
And then wasm supports C and C++ (and more) with huge eco system of libraries, applications, ... (While of course these days a Java VM (incl. Android) is often used with non-Java languages as well)
I'm building a static analysis CLI tool in Rust. It takes 30 seconds to build the WASM version, which I then upload to a website, providing a web-based version that other developers can use to demo the tool, and isolate bugs in its analysis.
It feels sort of magic.
But can we trust car manufacturers to do this testing and recertification before they push an update?
The article should have been titled "Why Am I Excited About WebAssembly Outside The Browser?"
The reasons the author gives don't seem that exciting.
I'm excited about WebAssembly in the browser because, as other commenters have pointed out, this allows a new area of delivering executables to run in a sandboxed browser tab with just a click. Convenience, speed and safety. I think it fulfills the early promise of the internet before the malicious hackers got to it. Some might want to say here that this is still insecure, but it's a lot more secure than downloading and running a binary on the main OS.
A great issue documenting a lot of the pain points around this is here: https://github.com/WebAssembly/design/issues/1397
Until this is solved WASM is dead in the water for a huge variety of applications. I am rooting for WASM, but it has been discouraging to watch this go unsolved over the years.
Asmjs was a clever hack but still a hack, and starting over with a clean slate let them fix various limitations inherent to using Javascript as a compilation target
You can test this pretty easily, since Emscripten still supports JavaScript output with a flag (for environments that lack wasm support for whatever reason). Comparing Emscripten's default wasm output to JS output for the same benchmark will show those benefits in most cases.
To be completely honest, WASM helps having cross platforms things, which is ALWAYS against the interests of companies who always divide their market territories to guarantees steady revenues. I'm also a bit curious how they managed to make WASM happen in the first place.
I'm also still waiting for C++ toolchain to directly output WASM. I haven't touched bynaryen since, but it was not a great experience.
WebAssembly is so big at this point it's too big to fail (famous last words maybe?). All major browsers support it (Firefox, Chrome, Safari and Edge), runtimes are available for non-browser usage, and a big amount of people are involved in moving it forward.
If it was early days, then maybe losing one key person could have changed the fate of WebAssembly. But at this point, there are multiple key people both inside and outside the WebAssembly organization.
The super tl;dr of WASM is that it's a universal bytecode format, an idea sort of like the JVM or the CLR. There are a few major benefits to this:
1. Languages can pick WASM as a compile target, and then run anywhere that WASM is supported. This includes the browser, the server, embedded devices, wherever.
2. WASM acts as a "Lingua Franca" for interop between languages, sort of like a C ABI. Any language that supports importing WASM bundles immediately gains support for calling code from any language that supports compiling to WASM.
It's trivial to write a program that calls functions from IE. Rust, Go, Zig, and C# in the span of 10 lines, because of WASM.On the clientside, you still need JS because WASM needs to interact with the browser's DOM API's. I'm not convinced of the benefits of WASM for writing web apps.
(One exception is maybe Blazor for .NET, which is exceptionally well-done)
[0]https://sudonull.com/post/62869-WebAssembly-and-DOM-manipula...
The DOM element then would be collected, when there are no JS references to it, its handle is disposed of by the WASM code, or the WASM runtime itself is destroyed.
Seems like a very similar problem to how game engines integrate scripting languages like Lua - with very similar solutions.
On top of that a lot of DOM manipulation is smoke and mirrors. While the exposed DOM APIs may provide you with some object, internally it's likely to be a collection of weird things in a trench coat due to all the optimisations that browser engines are doing.
And no one in their right mind will give you raw access to the underlying C++ object for many reasons, security being number one. And 30 years of assumptions that browsers have about these objects being number two.
But other than that there are OpenGL bindings (eg. in emscripten) and things for audio like SoLoud etc. You can usually put off writing JS for a while.
If you have a simple resizing algorithm I would consider using WebGPU/WebGL and a fragment shader to do it though.
But yeah Wasm has definitely been used successfully with performance results in production, eg. in Figma: https://www.figma.com/blog/webassembly-cut-figmas-load-time-...
But you're spot on otherwise. It's like they repeated the good parts of history and avoided repeating the bad parts. Weird.
| Browser | Option | Enabled by default |
|---------|-----------------------|--------------------|
| Firefox | dom.webgpu.enabled | Not yet! |
| Chrome | #enable-unsafe-webgpu | Not yet! |
I imagine this has something to do with why browser vendors have taken so long to ship WebGPU (another complaint I hear from WebGPU skeptics frequently), but what do I know."The Security Risk of Lacking Compiler Protection in WebAssembly"
> The standard has been designed with security in mind, as evidenced among others by the strict separation of application memory from the execution environment’s memory. Thanks to this separation, a compromised WebAssembly binary cannot compromise the browser that executes the binary.
Secondly, because WebAssembly is yet to become the next target of security researchers, those papers are the first steps.
Third, it is only a bytecode format, it cannot assure anything about the host implementation.
Naturally there are yet flaws to be discovered.
Of course libraries can be written that expose more and more functionality, but I don’t see anything inherently unsafe in the JVM as opposed to WASM, which is the exact same way. If anything, the jvm can’t even crash itself, while wasm is free to do all the old memory errors, just this time constrained to its virtual memory space.
Yes, and it is getting better each go around
Don't get me started on TVs, mine worked fine until it was updated and started hanging and refusing to turn off. I had a TV that worked well and then they made it stop working. This is the future of devices.
Never ever connect a T.V. to the Internet!
Use a Linux laptop sitting next to it.
Internet connected T.V.s are the sort of thing that keeps me up at night, worrying
TL;DR - Webassembly is completely unrelated to IoT provisioning and configuration.
And your comment itself reads as if it's a skim of the post itself. Yes, IoT security is obviously a huge risk, yet Wasm would dramatically reduce the possibility space of many (but not all) types of attacks.