WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the…
Three years ago, version 2.0 of the Wasm standard was (essentially) finished, which brought a number of new features, such as vector instructions, bulk memory operations, multiple return values, and simple reference types.
In the meantime, the Wasm W3C Community Group and Working Group have not been lazy. Today, we are happy to announce the release of Wasm 3.0 as the new “live” standard.
This is a substantially larger update: several big features, some of which have been in the making for six or eight years, finally made it over the finishing line.
64-bit address space. Memories and tables can now be declared to use i64
as their address type instead of just i32
. That expands the available address space of Wasm applications from 4 gigabytes to (theoretically) 16 exabytes, to the extent that physical hardware allows. While the web will necessarily keep enforcing certain limits — on the web, a 64-bit memory is limited to 16 gigabytes — the new flexibility is especially interesting for non-web ecosystems using Wasm, as they can support much, much larger applications and data sets now.
Multiple memories. Contrary to popular belief, Wasm applications were always able to use multiple memory objects — and hence multiple address spaces — simultaneously. However, previously that was only possible by declaring and accessing each of them in separate modules. This gap has been closed, a single module can now declare (define or import) multiple memories and directly access them, including directly copying data between them. This finally allows tools like wasm-merge, which perform “static linking” on two or more Wasm modules by merging them into one, to work for all Wasm modules. It also paves the way for new uses of separate address spaces, e.g., for security (separating private data), for buffering, or for instrumentation.
Garbage collection. In addition to expanding the capabilities of raw linear memories, Wasm also adds support for a new (and separate) form of storage that is automatically managed by the Wasm runtime via a garbage collector. Staying true to the spirit of Wasm as a low-level language, Wasm GC is low-level as well: a compiler targeting Wasm can declare the memory layout of its runtime data structures in terms of struct and array types, plus unboxed tagged integers, whose allocation and lifetime is then handled by Wasm. But that’s it. Everything else, such as engineering suitable representations for source-language values, including implementation details like method tables, remains the responsibility of compilers targeting Wasm. There are no built-in object systems, nor closures or other higher-level constructs — which would inevitably be heavily biased towards specific languages. Instead, Wasm only provides the basic building blocks for representing such constructs and focuses purely on the memory management aspect.
Typed references. The GC extension is built upon a substantial extension to the Wasm type system, which now supports much richer forms of references. Reference types can now describe the exact shape of the referenced heap value, avoiding additional runtime checks that would otherwise be needed to ensure safety. This more expressive typing mechanism, including subtyping and type recursion, is also available for function references, making it possible to perform safe indirect function calls without any runtime type or bounds check, through the new call_ref
instruction.
Tail calls. Tail calls are a variant of function calls that immediately exit the current function, and thereby avoid taking up additional stack space. Tail calls are an important mechanism that is used in various language implementations both in user-visible ways (e.g., in functional languages) and for internal techniques (e.g., to implement stubs). Wasm tail calls are fully general and work for callees both selected statically (by function index) and dynamically (by reference or table).
Exception handling. Exceptions provide a way to locally abort execution, and are a common feature in modern programming languages. Previously, there was no efficient way to compile exception handling to Wasm, and existing compilers typically resorted to convoluted ways of implementing them by escaping to the host language, e.g., JavaScript. This was neither portable nor efficient. Wasm 3.0 hence provides native exception handling within Wasm. Exceptions are defined by declaring exception tags with associated payload data. As one would expect, an exception can be thrown, and selectively be caught by a surrounding handler, based on its tag. Exception handlers are a new form of block instruction that includes a dispatch list of tag/label pairs or catch-all labels to define where to jump when an exception occurs.
Relaxed vector instructions. Wasm 2.0 added a large set of vector (SIMD) instructions, but due to differences in hardware, some of these instructions have to do extra work on some platforms to achieve the specified semantics. In order to squeeze out maximum performance, Wasm 3.0 introduces “relaxed” variants of these instructions that are allowed to have implementation-dependent behavior in certain edge cases. This behavior must be selected from a pre-specified set of legal choices.
Deterministic profile. To make up for the added semantic fuzziness of relaxed vector instructions, and in order to support settings that demand or need deterministic execution semantics (such as blockchains, or replayable systems), the Wasm standard now specifies a deterministic default behavior for every instruction with otherwise non-deterministic results — currently, this includes floating-point operators and their generated NaN values and the aforementioned relaxed vector instructions. Between platforms choosing to implement this deterministic execution profile, Wasm thereby is fully deterministic, reproducible, and portable.
Custom annotation syntax. Finally, the Wasm text format has been enriched with generic syntax for placing annotations in Wasm source code. Analogous to custom sections in the binary format, these annotations are not assigned any meaning by the Wasm standard itself, and can be chosen to be ignored by implementations. However, they provide a way to represent the information stored in custom sections in human-readable and writable form, and concrete annotations can be specified by downstream standards.
In addition to these core features, embeddings of Wasm into JavaScript benefit from a new extension to the JS API:
With these new features, Wasm has much better support for compiling high-level programming languages. Enabled by this, we have seen various new languages popping up to target Wasm, such as Java, OCaml, Scala, Kotlin, Scheme, or Dart, all of which use the new GC feature.
On top of all these goodies, Wasm 3.0 also is the first version of the standard that has been produced with the new SpecTec tool chain. We believe that this makes for an even more reliable specification.
Wasm 3.0 is already shipping in most major web browsers, and support in stand-alone engines like Wasmtime is on track to completion as well. The Wasm feature status page tracks support across engines.
I'm definitely excited to see 64 bit as a default part of the spec. A lot of web apps have been heavily restricted by this, in particular any online video editors. We see a bunch of restrictions due to the 32 bit cap today here at Figma. One thing I'm curious though is whether mobile devices will keep their addressable per-tab memory cap the same. It's often OS defined rather than tied to the 32 bit space.
I guess I’m just a crusty ol’ greybeard C++ developer, but it seems like a video editor is out of place in a document browser. There’s a perfectly good native operating system that nobody uses any more.
If we think we need a more thoroughly virtualized machine than traditional operating system processes give us (which I think is obvious), then we should be honest and build a virtualization abstraction that is actually what we want, rather than converting a document reader into a video editor…
> ... document browser ... document reader ...
I'm going to assume you're being sincere. But even the crustiest among us can recognize that the modern purpose for web browsers is not (merely) documents. Chances are, many folks on HN in the last month have booked tickets for a flight or bought a home or a car or watched a cat video using the "document browser".
> If we think we need a more thoroughly virtualized machine than traditional operating system processes give us (which I think is obvious)...
Like ... the WASM virtual machine? What if the WASM virtual machine were the culmination of learning from previous not-quite-good-enough VMs?
WASM -- despite its name -- is not truly bound to the "document" browser.
Alan Kay on “Should web browsers have stuck to being document viewers?” and a discussion of Smalltalk, HyperCard, NeWS, and HyperLook
https://donhopkins.medium.com/alan-kay-on-should-web-browser...
>Alan Kay answered: “Actually quite the opposite, if “document” means an imitation of old static text media (and later including pictures, and audio and video recordings).”
So you are telling me I can now directly render from WASM into the viewport of the browser with a11y? Nope, then it’s still restricted to interacting with the DOM through JS or or renderings to a cavas with no a11y support or significantly worse dx for a11y because you would need to render a screen reader only document layout ontop of your actual UI, instead of just handing the browser an interaction tree and allowing it to do what is needed for screen readers.
You can write Wasm bindings to the native UI toolkit of your choice and render with that. It doesn’t have to be in the DOM.
You understand why that is exactly pointless…
I could write those exact same bindings for my language that I will compile to wasm and then use the current WASI interface, but even that is pointless because at that point I have written a native app, what good reason would I need to run it through an emulator, specifically when a modern OS is already sandboxing things.
If I am targeting the browser my above point stands, unless the DOM is already a reasonably decent API for what needs to be built(it probably isn’t, it’s the best example you can get of horrible API design in my opinion) then I will need to build something ontop of that, prime example being react.
So I need to run my code in an interpreter, having built data structures to generate a document in an eDSL, which creates other data structures, which then calls into another API, which then calls into the OS/hardware layer.
When what I want to do, is call into the OS/hardware layer directly…
> what good reason would I need to run it through an emulator, specifically when a modern OS is already sandboxing things.
One good reason would be that “Which OS specifically?” is a question with at least 4-5 mainstream answers (and even more not-so-mainstream answers). That's what motivated the push from WWW-as-a-bunch-of-interconnected-documents to WWW-as-a-bunch-of-remote-hosted-apps in the first place: to be able to develop and deliver applications without having to worry quite so much about the client platform.
WASM is in this regard analogous to the olden days of Java/Silverlight/Flash, with many of the same tradeoffs (and some of the rough edges filed down due to lessons learned around browser integration and toolchains and such).
The discussion here was building bindings for the OS layer, which means to explicitlY worry about the client platform.
When using the web I have my own issues with that platform, or more specifically using wasm in it since it is literally useless for building web based applications over JS/TS. It is being targeted more as a library platform which gets called into from JS than being an actual “assembly “ language.
>> You understand why that is exactly pointless…
I don't understand any such thing.
Modern OS sandboxing doesn't give you memory safety from Wasm's memory model or the capability-based security of WASI.
>> When what I want to do, is call into the OS/hardware layer directly…
If that's what you want to do, then I'm not sure what we're even discussing in this thread. The only safe way to run such code is with a hypervisor.
The entire point was that WASM just calls to the existing C functions, the ones you would call from literally any language.
If you care about memory safety then use a “memory safe” language that guarantees the exact same thing as what you thing WASM guarantees except without all the pointless overhead or running a sandboxed interpreter inside a sandboxed operating system process, it is actually just pointless complexity at that point.
For native development WASM gives no benefits, the only useful parts that WASM might bring literally hasn’t been standardised because it’s a real hard problem to solve and has no use in browser.
So wasm is designed for the browser and unless you only intend to embed a library in your existing JS application it is pointless because you are still restricted to the DOM.
We have, but not by choice, I miss my native apps, even though ChromeOS Platform pays the bills.
> booked tickets for a flight or bought a home or a car or watched a cat video
Would you install a native app to book a flight? One for each company? Download updates for them every now and then, uninstall them when you run out of disk space etc
I can ask the same question about every other activity we do in these non-native apps.
I have installed all them on the phone, so yes.
Unfortunely several of them are glorified webviews.
I am old enough to have lived through the days Internet meant a set of networking protocols, not ChromeOS Platform.
And on those days hard disks were still bloody expensive, by the way.
> I have installed all them on the phone, so yes.
Isn't your phone providing a sandbox, a distribution system, a set of common runtime services, etc to get these native apps functional?
You don't have to squint your eyes to realize that this thing we call "document browsers" are doing a lot of the same work that Apple/Google are doing with their mobile OSes.
You mean like Windows Store, Mac App Store, apt, yum/dnf, emerge,....?
All the OS frameworks that are available across most operating systems that don't fragment themselves into endless distributions?
> don't fragment themselves into endless distributions?
My dear Lord! In what world are you living in?
Take a look at all of the "mobile apps" you installed on your phone and tell me which of those would ever devote any resource to make a apt/rpm repository for their desktop applications.
Even the ones that want to have a desktop application can not figure out how to reliably distribute their software. The Linux crowd itself is still at the flatpak vs AppImage holy war. Mark Shuttleworth is still beating the snap horse.
The Web as a platform is far from ideal, but if it weren't for it I would never been able to switch to Linux as my primary base OS and I would have to accept the Apple/Microsoft/Google oligopoly, just like we are forced to do it at the mobile space.
> The Web as a platform is far from ideal, but if it weren't for it I would never been able to switch to Linux as my primary base OS
As my old IT teacher said: you can use the browser on any OS. She also implied it requires no special skills, which is true if you are limited to the browser for the majority of the time.
So... are you saying that you are able to use Linux because all you are using is the browser?
> are you saying that you are able to use Linux because all you are using is the browser?
No, I am saying that the browsers provide a fallback for the applications that I need but do not have a native counterpart, and therefore I am not stuck with Windows or MacOS.
Without the web as a platform, I'd have to leave Linux the moment I got to a job that required Slack/Jira/Teams.
In the world we build for ourselves, a worse is better mentality world.
> a worse is better mentality world.
Seems like your preferred world is the totalitarian "choose any color you want as long as it is black" one, where everything is perfectly optimized and perfectly integrated into a single platform.
> > a worse is better mentality world. > > Seems like your preferred world is the totalitarian "choose any color you want as long as it is black" one, where everything is perfectly optimized and perfectly integrated into a single platform.
Idk, I have a feeling they would be anti systemd too
I don't know if you are serious or just trying to evade the discussion.
Two questions:
1) What is the primary OS for your desktop?
2) Would you sincerely make the argument that a world where everyone submits to a single design (Apple-style) would be better than an "organic" world where the barrier of entry is lower, but less "optimal"?
1) Windows or macOS, depending on the project or customer provided hardware
2) Yep, the Year of Linux Desktop already happened, it is a VM hosted on 1)
(2) reads like "to be free, first you need to submit yourself to the Overlords".
I will take the minor inconvenience of having to run web apps over the dystopia you are willing to subject yourself to in the name of "optimization", thank you very much.
You're doing all these things with web apps also, it's just that the browser orchestrates it for you.
But for some reason this takes 20M lines of code, which creates a moat that prevents browser competition.
Any sufficiently-capable graphical application runtime* contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of a web browser.
(* including every web browser)
I have wanted to try Chrome for the longest time but I cant justify overspending (you need a lot of memory for the modern web) and not being able to install half the Linux apps I would want OOTB (out of the box is a big deal for me).
I am still shocked Google has not rubbed two brain cells together and built a serious Google ChromeOS version for developers with a real desktop environment and real access to Linux, and keeping the browser as sandboxed as they have. I would spend top dollar on such a laptop. Heck it could come with an easy way to install Android Studio, and native apps for things like Hangouts or whatever they call it now.
That's literally ChromeOS now, it comes with a terminal built in and you can run any Linux apps
Without doing too much fancy stuff can I just run Zed or JetBrains IDEs?
Back when I tried to daily-drive a Chromebook Pixel it was, like, one flag in the settings app to enable Crostini and run whatever (GNU/)Linux program my heart desired, and that was many years ago; can't imagine it's gotten any harder (especially now that even Android is starting to offer similarly-turnkey Linux app support through the newfangled Terminal app).
Yes you can run them, they work well.
While web apps make sense, those are pretty weak examples. Booking and buying are pretty document-based and need to run little to zero external code. The cat video isn't technically a document but upgrading a photo to a video is not a very big change and doesn't require any external code at all.
document browser, document reader, printed paper, paper form, return to sender... those are all in the same concept space*
"virtual machine" is clearly not
that said, i love WASM in the browser, high time wrapping media with code to become "new media" wasn't stuck solely with a choice between JS and "plugins" like Java, Flash, or Silverlight
it's interesting to look back at a few "what might have been" alternate timelines, when the iPhone was intended to launch as an HTML app platform, or Palm Pre (under a former Apple exec, the "pod-father") intended the same with WebOS. if a VM running a web OS shows a PDF or HTML viewer in a frame, versus if a HTML viewer shows a VM running a web OS in a frame...
we're still working on figuring out whether new media and software distribution are the same.
today, writing Swift, or Nim, or whatever LLVM, and getting WASM -- I agree with you, feels like a collective convergence on the next step of common denominator
* note: those are all documents and document workflows with skeuomorphic analogs in the same headspace, and newspaper with "live pictures" has been a sci-fi trope for long enough TV news still can't bring themselves to say "video" (reminding us "movie" is to "moving" as "talkie" was to "talking") so extending document to include "media" is reasonable. but extending that further to be "arbitrary software" is no longer strictly document nor media
Well, that's my point. The modern purpose of the browser is for applications, and for very good reasons, namely to abstract away the OS. The problem is that the design of the browser is for documents, and is really unsuitable for applications. Applications need a UI toolkit that takes a rectangle and renders the button, whatever into it. But you can't even get a proper rectangle with DOM: a div is 100% width, which is usually not what you want, but a span is this strange thing that makes sense for text, but not for a button or slider. So everything has "display: inline-block;", which then overrides the div or span part, so that it doesn't even matter which you pick. You can't even center something vertically without doing a web search, although I guess these days you use flexbox. Flexbox at least is the equivalent of Qt or Swing's layouts.
Mind you, I think WASM is the best thing that has happened to the browser, but that's because I think the HTML/DOM is completely unsuitable for apps, and I hate developing with it so much that I won't do it, even if I have to switch careers.
I think WASM is a reasonable start to a proper virtual machine. But I think what we need is a "browser" that presents a virtual machine with a virtual monitor(s), virtual chunk of contiguous memory, virtual CPU(s), virtual networking, virtual filesystem, and basic drawing primitives, that executes WASM. The "browser" part would be that you can use a URL to point to a WASM program. The program would see itself as being the only thing on the machine (see, basically generalization of the OS process concept into a machine). The user would be able to put limits on what the virtual network can access, what parts of the OS filesystem the virtual filesystem could access, how many real CPUs (and a cpulimit) the virtual CPUs get, etc. So, sort of like a containerized Plan9. I would be happy to do this myself, but I just don't have the spare time to do it, so unless someone is willing to fund me, I'll hope someone sees this and catches the vision.
Using WASM in the web browser is a workaround.
Personally not a fan of Windows 95 in the browser, however the browser stoped being a “document reader” a decade ago it’s the only universel, sandbox runtime, and everything is moving in that direction ... safe code. WASM isnt a worst VM; it’s a diffrent trade off: portable, fast start, capability scoped compute without shiping a OS. Raw device still have their place (servers). If you need safe distribution + performance thats “good enough” WASM in the browser is going to be the future of client.
XMLHttpRequest was part of IE5 in 1999 as an ActiveXObject. Outlook Web team built it a year earlier.
Not to mention Java applets which is how you would do this sort of thing in the early 2000s
The problem is: even us old timers can't deny nor change the fact that operating systems have been putting up barriers to disallow running untrusted code downloaded from the internet.
Try to distribute an installer on Windows that isn't signed with an extensive EV-certificate for instance. It's scare popup galore.
Not to mention the closed gardens of the Apple and Google Stores which even when you get in, you can be kicked out again for absolutely no objective reason (they don't even need to tell you why).
> then we should be honest and build a virtualization abstraction that is actually what we want,
This is not in the interest of Microsoft, Google or Apple. They can't put the open web back into the box (yet, anyway), but they will not support any new attempts to create an open software ecosystem on "their" platforms.
Just wait until the Web finally becomes ChromeOS Platform, after the Safari barrier is out of the way.
Think of it like emacs. Browsers are perfectly good operating systems just needing a better way to view the web.
That's too true to be funny!
The browser removes the friction of needing to install specialized software locally, which is HUGE when you want people to actually use your software. Figma would have been dead in the water if it wasn't stupidly simple to share a design via a URL to anyone with a computer and an internet connection.
I can't shake the feeling that this ship has sailed and only a few got to get on it while it happened.
And this comes from someone who started with Flash, built actual video editing apps with it, and for the last 25 years build application with "it's not a web app, it's a desktop app that lives in a browser" attitude [1].
Even with Flash we often used hybrid approach where you had two builds from same codebase - a lite version running in the browser and an optional desktop app (AIR) with full functionality. ShareObjects and LocalConnection made this approach extremely feasible as both instances were aware of each other and you could move data and objects between them in real time.
The premise is great, but it was never fully realized - sure you have few outliers like Figma, but building a real "desktop app" in a browser comes with a lot of quirks, and the resulting UX is just terrible in most cases.
[1] just to be clear, there's a huge difference between web page and web app ;D
I would argue that as soon as it was decided to include JavaScript runtime in the browser, it stopped being a plain document browser. From then on, we were just on the evolutionary path of converting it from a low capability app sandbox to a highly capable one.
There are projects to run WASM on bare metal.
I do agree that we tend to run a lot in a web-browser or browser environment though. It seems like a pattern that started as a hack but grew into its own thing through convenience.
It would be interesting to sit down with a small group and figure out exactly what is good/bad about it and design a new thing around the desired pattern that doesn't involve a browser-in-the-loop.
> run WASM on bare metal
Heh, reminds me of those boxes Sun used to make that only ran Java. (I don’t know how far down Java actually went; perhaps it was Solaris for the lower layers now that I think about it…)
The Java went so far down that many early ARM cores could be placed in Jazelle DBX mode, which processed Java bytecode in hardware shudders
With hypervisors and a Linux kernel doing the heavy lifting, the WASM on bare metal probably just looks a lot like a regular process. I would bet Sun did similar … minus the hypervisor.
I do miss the Solaris 10/OpenSolaris tech though. I don’t know anything that comes close to it today.
Solaris is still around, while OpenSolaris forks support Oxide endeavours.
Technically, yes. I built+ported a majority of Debian packages onto Nexenta OS but that effort (and many parallel efforts) just vanished when Oracle purchased Sun. I don't miss SVR4 packages and I never grew fond of IPS. So many open-source folk warned of the dangers of CDDL and they were largely realized in fairly short time. Unsurprisingly, #opensolaris on irc also had a precipitous drop-off around the same time.
dtrace/zones/smf/zfs/iscsi/... and the integration between them all was top notch. One could create a zone, spin up a clone, do some computation, trash the filesystem and then just throw the clone away... in very short time. Also, that whole loop happened without interacting with zfs directly; I know that some of these things have been ported but the ports miss the integration.
eg: zfs on Linux is just a filesystem. zfs on Solaris was the base of a bunch of technology. smf tied much of it together.
eg: dtrace gave you access all the way down to individual read/write operations per disk in a raid-z and all the way up to the top of your application running inside of a zone. One tool with massive reach and very little overhead.
Not much compels me to go back to the ecosystem; I've been burned once already.
I think it was far less special that advertized, so it was probably a stripped Solaris that ran a JRE hoping noone would notice. Dog slow they were at least so from my viewpoint, there was nothing magic about those boxes at all.
SIM cards and credit cards also run Java bytecode: https://en.wikipedia.org/wiki/Java_Card
That's the idea of the Orca app/standard: https://orca-app.dev/
"What if we made a new WASM-based platform for apps, separate from the browser?"
I'm a fan of the browser becoming a sandbox for much more than "documents". It has the most developed, flexible, and powerful UI system ever, it established numerous standards that pervade modern software development, and it's already available as one of the most cross-platform standard utilities.
If the browser sandbox is a reliable cross-platform sandbox, the potential to develop and distribute software is huge. Progressive Web Apps are awesome because you can visit the website and use it normally, and then click a button to "install" the website to your device. If designed correctly, the website can work offline. By doing this, you get free distribution, automatic updates, no app stores, an excellent platform to develop an app on top of (the browser), etc.
I think PWAs are the future, but the web platform still has some ways to go. There are numerous amazing examples of what you can accomplish with PWAs in their current state, though.
There is no difference between a "document" and an "app". There has never been a difference between the two, it's a purely artificial distinction.
Word and LibreOffice "documents" can run embedded macros. Emacs has `org-mode`, which can call out to any programming language on your $PATH. A PDF document is produced by running code in a stack-based virtual machine. Even fonts have bytecode instructions embedded inside them that are used for hinting.
If by "document" you mean "static text with no executable bits", then only plain text files can truly be called documents. Everything else is a computer program, and has been since the dawn of computing.
the loose implication is that documents don't have access to resources outside of itself and they're somewhat static
imo when you start talking about dynamic documents the distinction starts to blur but it should be fine if it's just a few parameters that are meant to be manually updated... beyond that "document" seems like the wrong term (and tech)
those artificial distinctions are essential and perfectly practical as they can convey expectations just fine
GP is correct in that the browser has generalised to a point it has clear drawbacks for its original intended purpose, but that is just a fact of life at this point
IMO, html should have scaled back from 5.0 to the feature-set of 4, if not 3, with mass deprecations and beyond that it shouldn't be called html even if the main browsers carried on adding features and interoperable OS-like characteristics, so people could see beforehand if they were visiting hypertext documents or application sites, because certainly most of the web right now could not be reasonably called "hypertext"
but that isn't the way it was handled and tbh it was to be expected
> There is no difference between a "document" and an "app". There has never been a difference between the two, it's a purely artificial distinction.
Every distinction is artificial if you are willing to hair-split. No useful conclusion follows from this realization.
I don’t think the total dissolution of a blurry boundary is a useful act. Yes, many document formats become Turing complete and run Doom eventually, but there is still a notable practical distinction between the intent to create a document interpreter versus an application framework.
Plenty of people still want local-first apps that function offline.
Totally possible today with modern SPA technology that all major browsers support
You mean the convoluted enginnering exercise of service workers, in-browser proxies, and in-browser databases to simulate something native platforms don't need to care about?
So where are they?
Flutter?
Is Flutter an SPA framework?
Yes
The browser became an app engine so app developers could escape the Wintel monopoly that was pretty tight in the 90's and 00's when the Internet became a thing. These days, it's so there can be apps outside of app stores.
There's been various attempts to build "Internet operating systems" that are little more than a browser (that's what Chrome OS was intended to be in the beginning I thought) but Windows and it's pre-internet legacies are so entrenched in PCs and corporate life that nothing's ever gonna change there until Microsoft makes the entirety of Windows an app.
I a 64yo fart. Started programming with machine codes. Native is my bread and butter. Still have no problems and am using browser as a deployment platform for some type of applications. Almost each thing has it's own use.
Basically OS developer dropped the ball. Internet caught them by surprise and few decades is apparently too short for them to come up with new appealing abstractions to fit the new environment. So browser developers took over and did just that.
Same way webdevs ate desktop app dev's lunch because they had no idea how to innovate on decade old ideas.
To sum up, no matter how well you are positioned for something on paper, if you won't do it, someone else will.
But that's what they're doing. The hard part isn't the VM. The hard part is the long fought functional yet secure sandbox that a browser provides.
> functional yet secure
Secure? Debatable. Functional? Not really.
For example, try accessing a security key and watch the fun. Sure, if you access it exactly the way Google wants you to, things kinda-sorta work, sometimes. If you don't want to obey your Google masters, good luck getting your Bluetooth or USB packet to your security key.
And because you are "secure", you can't store anything on the local hard drive. Oh, and you can't send a real network packet either. All you can do is send a supplication request to a network database owned by somebody else that holds your data--"Please, sir, can I have some more?". The fact that this prevents you from exporting your data away from cloud-centered SaaS providers is purely coincidental, I'm sure. </sarcasm>
So in the name of security we just kneecap the end users--if the users can't do anything, they're secure, right? Diana Moon Glampers would be proud.
I'm not sure what any of that means but people like wasm because the web sandbox does work for many cases.
No one is saying it solves every single use case and it doesn't need to.
I feel way safer using apps inside web browser than installing / executing them directly on my PC.
.NET does this and nowadays you can compile most of your .NET code to machine code, it only keeps bytecode for the reflection pieces of code, but everything else is Ahead of Timed iirc basically you get all the VM benefits, and some native speeds in one go.
The browser has become the operating system for a while now because native OS things were too fragmented and too slow to keep pace with what people wanted.
PostScript is turing complete. SVG almost got the ability to open raw network sockets. Word files were (are?) a common platform for distributing malware.
Security model of web is needed to be brought to the OS.
lmfao
Unfortunately, Memory64 comes with a significant performance penalty because the wasm runtime has to check bounds (which wasn't necessary on 32-bit as the runtime would simply allocate the full 4GB of address space every time).
But if you really need more than 4GB of memory, then sure, go ahead and use it.
Actually, runtimes often allocate 8GB of address space because WASM has a [base32 + index32] address mode where the effective address could overflow into the 33rd bit.
On x86-64, the start of the linear memory is typically put into one of the two remaining segment registers: GS or FS. Then the code can simply use an address mode such as "GS:[RAX + RCX]" without any additional instructions for addition or bounds-checking.
The comedy option would be to use the new multi-memory feature to juggle a bunch of 32bit memories instead of a 64bit one, at the cost of your sanity.
We call it "pointer compression" now. :)
Seriously though, I’ve been wondering for a while whether I could build a GCC for x86-64 that would have 32-bit (low 4G) pointers (and no REX prefixes) by default and full 64-bit ones with __far or something. (In this episode of Everything Old Is New Again: the Very Large Memory API[1] from Windows NT for Alpha.)
[1] https://devblogs.microsoft.com/oldnewthing/20070801-00/?p=25...
A moderate fraction of the work is already done using:
https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html
Unfortunately the obvious `__attribute__((mode(...)))` errors out if anything but the standard pointer-size mode (usually SI or DI) is passed.
Or you may be able to do it based on x32, since your far pointers are likely rare enough that you can do them manually. Especially in C++. I'm pretty sure you can just call "foreign" syscalls if you do it carefully.
6502 zero page instruction vibes.
It was glorious I tell you.
Especially how you could increase the segment value by one or the offset by 16 and you would address the same memory location. Think of the possibilities!
And if you wanted more than 1MB you could just switch memory banks[1] to get access to a different part of memory. Later there was a newfangled alternative[2] where you called some interrupt to swap things around but it wasn't as cool. Though it did allow access to more memory so there was that.
Then virtual mode came along and it's all been downhill from there.
[1]: https://en.wikipedia.org/wiki/Expanded_memory
[2]: https://hackaday.com/2025/05/15/remembering-more-memory-xms-...
> Think of the possibilities!
Schulman’s Unauthorized Windows 95 describes a particularly unhinged one: in the hypervisor of Windows/386 (and subsequently 386 Enhanced Mode in Windows 3.0 and 3.1, as well as the only available mode in 3.11, 95, 98, and Me), a driver could dynamically register upcalls for real-mode guests (within reason), all without either exerting control over the guest’s memory map or forcing the guest to do anything except a simple CALL to access it. The secret was that all the far addresses returned by the registration API referred to the exact same byte in memory, a protected-mode-only instruction whose attempted execution would trap into the hypervisor, and the trap handler would determine which upcall was meant by which of the redundant encodings was used.
And if that’s not unhinged enough for you: the boot code tried to locate the chosen instruction inside the firmware ROM, because that will have to be mapped into the guest memory map anyway. It did have a fallback if that did not work out, but it usually succeeded. This time, the secret (the knowledge of which will not make you happier, this is your final warning) is that the instruction chosen was ARPL, and the encoding of ARPL r/m16, AX starts with 63 hex, also known as the ASCII code of the lowercase letter C. The absolute madmen put the upcall entry point inside the BIOS copyright string.
(Incidentally, the ARPL instruction, “adjust requested privilege level”, is very specific to the 286’s weird don’t-call-it-capability-based segmented architecture... But it’s has a certain cunning to it, like CPU-enforced __user tagging of unprivileged addresses at runtime.)
> The absolute madmen put the upcall entry point inside the BIOS copyright string.
Isn’t that an arbitrary string, though? Presumably AMI and Insyde have different copyright messages, so then what?
To clarify: when I said that “the boot code tried to locate the chosen instruction inside the firmware ROM”, I literally meant that it looked through the entirety of the ROM BIOS memory range for a byte, any byte, with value 63 hex. There’s even a separate (I’d say prematurely factored out) routine for that, Locate_Byte_In_ROM. It just so happens that the byte in question is usually found inside the copyright string (what with the instruction being invalid and most of the rest of the exposed ROM presumably being valid code), but the code does not assume that.
If the search doesn’t succeed or if you’ve set SystemROMBreakPoint=off in the [386Enh] section of SYSTEM.INI[1] or run WIN /D:S, then the trap instruction will instead be placed in a hypervisor-provided area of RAM that’s shared among all guests, accepting the risk that a misbehaving guest will stomp over it and break everything (don’t know where it fits in the memory map).
As to the chances of failing, well, I suspect the original target was the c in “(c)”, but for example Schulman shows his system having the trap address point at “chnologies Ltd.”, presumably preceded by “Phoenix Te”. AMI and Award were both “Inc.”, so that would also work. Insyde wasn’t a thing yet; don’t know what happened on Compaq or IBM machines. One way or another, looks like a c could be found somewhere often enough that the Microsoft programmers were satisfied with the approach.
I thought so, but "Copyright" is always the same? Haha, that's dangerously clever or cleverly dangerous.
And turned out we have the transistors to avoid it, but it's a really good optimization for CPUs nowadays.
At least most people design non-overlaping segments. And I'm not sure wasm would gain anything from it, being a virtual machine instead of real.
wait.... UNREAL MODE!
Somewhat related. At some point around 15 years ago I needed to work with large images in Java, and at least at the time the language used 32-bit integers for array sizes and indices. My image data was about 30 gigs in size, and despite having enough RAM and running a 64-bit OS and JVM I couldn't fit image data into s ingle array.
This multi-memory setup reminds me of my array juggling I had to do back then. While intellectually challenging it was not fun at all.
The problem with multi-memory (and why it hasn't seen much usage, despite having been supported in many runtimes for years) is that basically no language supports distinct memory spaces. You have to rewrite everything to use WASM intrinsics to work on a specific memory.
Stray thought: the way Zig uses first-class allocators might make it interesting for doing things with multiple memories.
It looks like memories have to be declared up front, and the memcpy instruction takes the memories to copy between as numeric literals. So I guess you can't use it to allocate dynamic buffers. But maybe you could decide memory 0 = heap and memory 1 = pixel data or something like that?
Honestly you could allocate a new memory for every page :-)
The irony for me is that it's already slow because of the lack of native 64-bit math. I don't care about the memory space available nearly as much.
Eh? I'm pretty sure it's had 64-bit math for awhile -- i64.add, etc.
They might have meant lack of true 64bit pointers ..? IIRC the chrome wasm runtime used tagged pointers. That comes with an access cost of having to mask off the top bits. I always assumed that was the reason for the 32bit specification in v1
Bounds checking in other PLT is often reproted to result in pretty low overheads. Will be interesting to see some details about how this turns out.
I still don't understand why it's slower to mask to 33 or 34 bit rather than 32. It's all running on 64-bit in the end isn't it? What's so special about 32?
That's because with 32-bit addresses the runtime did not need to do any masking at all. It could allocate a 4GiB area of virtual memory, set up page permissions as appropriate and all memory accesses would be hardware checked without any additional work. Well that, and a special SIGSEGV/SIGBUS handler to generate a trap to the embedder.
With 64-bit addresses, and the requirements for how invalid memory accesses should work, this is no longer possible. AND-masking does not really allow for producing the necessary traps for invalid accesses. So every one now needs some conditional before to validate that this access is in-bounds. The addresses cannot be trivially offset either as they can wrap-around (and/or accidentally hit some other mapping.)
I don't feel this is going to be as big of a problem as one might think in practice.
The biggest contributor to pointer arithmetic is offset reads into pointers: what gets generated for struct field accesses.
The other class of cases are when you're actually doing more general pointer arithmetic - usually scanning across a buffer. These are cases that typically get loop unrolled to some degree by the compiler to improve pipeline efficiency on the CPU.
In the first case, you can avoid the masking entirely by using an unmapped barrier region after the mapped region. So you can guarantee that if pointer `P` is valid, then `P + d` for small d is either valid, or falls into the barrier region.
In the second case, the barrier region approach lets you lift the mask check to the top of the unrolled segment. There's still a cost, but it's spread out over multiple iterations of a loop.
As a last step: if you can prove that you're stepping monotonically through some address space using small increments, then you can guarantee that even if theoretically the "end" of the iteration might step into invalid space, that the incremental stepping is guaranteed to hit the unmapped barrier region before that occurs.
It's a bit more engineering effort on the compiler side.. and you will see some small delta of perf loss, but it would really be only in the extreme cases of hot paths where it should come into play in a meaningful way.
> AND-masking does not really allow for producing the necessary traps for invalid accesses.
Why does it need to trap? Can't they just make it UB?
Specifying that invalid accesses always trap is going to degrade performance, that's not a 64-bit problem, that's a spec problem. Even if you define it in WASM, it's still UB in the compiler so you aren't saving anyone from UB they didn't already have. Just make the trapping guarantee a debug option only.
It's WASM. WASM runs in a sandbox and you can't have UB on the hardware level. Imagine someone exploiting the behavior of some browser when UB is triggered. Except that the programmer is not having nasal demons [1] but some poor user, like a mom of four children in Abraska running a website on her cell phone.
The UB in this case is "you may get another value in the sandboxed memory region if you dereference an invalid pointer, rather than a guaranteed trap". You can still have UB even in a sandbox.
Seems like they got overly attached to the guaranteed trapping they got on 32-bit and wanted to keep it even though it's totally not worth the cost of bounds checking every pointer access. Save the trapping for debug mode only.
Ah, so you meant UB = unspecified behavior, not UB = undefined behavior.
Maybe. Bugs that come from spooky behavior at a distance are notoriously hard to debug, especially in production, and it's worthwile to pay for it to avoid that.
The special part is the "signal handler trick" that is easy to use for 32-bit pointers. You reserve 4GB of memory - all that 32 bits can address - and mark everything above used memory as trapping. Then you can just do normal reads and writes, and the CPU hardware checks out of bounds.
With 64-bit pointers, you can't really reserve all the possible space a pointer might refer to. So you end up doing manual bounds checks.
Hi Alon! It's been a while.
Can't bounds checks be avoided in the vast majority of cases?
See my reply to nagisa above (https://news.ycombinator.com/item?id=45283102). It feels like by using trailing unmapped barrier/guard regions, one should be able to elide almost all bounds checks that occur in the program with a bit of compiler cleverness, and convert them into trap handlers instead.
Hi!
Yeah, certainly compiler smarts can remove many bounds checks (in particular for small deltas, as you mention), hoist them, and so forth. Maybe even most of them in theory?
Still, there are common patterns like pointer-chasing in linked list traversal where you just keep getting an unknown i64 pointer, that you just need to bounds check...
Because CPUs still have instructions that automatically truncate the result of all math operations to 32 bits (and sometimes 8-bit and 16-bit too, though not universally).
To operate on any other size, you need to insert extra instructions to mask addresses to the desired size before they are used.
WASM traps on out-of-bounds accesses (including overflow). Masking addresses would hide that.
Webapps limited by 4GiB memory?
Sounds about right. Guess 512 GiB menory is the minimum to read email nowadays.
I know you're in this for the satire, but it's less about the webapps needing the memory and more about the content - that's why I mentioned video editing webapps.
For video editing, 4GiB of completely uncompressed 1080p video in memory is only 86 frames, or about 3-4 seconds of video. You can certainly optimize this, and it's rare to handle fully uncompressed video, but there are situations where you do need to buffer this into memory. It's why most modern video editing machines are sold with 64-128GB of memory.
In the case of Figma, we have files with over a million layers. If each layer takes 4kb of memory, we're suddenly at the limit even if the webapp is infinitely optimal.
> 4GiB of completely uncompressed 1080p video in memory is only 86 frames
How is that data stored?
Because (2^32)÷(1920×1080×4) = 518 which is still low but not 86 so I'm curious what I'm missing?
> How is that data stored?
So glad you asked. It's stored poorly because I'm bad at maths and I'm mixing up bits and bytes.
That's what I get for posting on HN while in a meeting.
I would guess 3 colour channels at 16bit (i.e. 2 bytes)
(2^32)÷(1920×1080×4×3×2) = 86
Where does the 4 come from? I thought it was R+G+B+A, but you already have 3 colour channels in that calculation
Yep, my logic is faulty there. And even if we assume that it's 24bpp color, that's still a factor of 2 out.
Apparently with 24 bytes per pixel instead of bits :) Although to be fair, there's HDR+ and DV, so probably 4(RGBA/YUVA) floats per pixel, which is pretty close..
I'm strange to webdev, but can't you swap the remaining uncompressed frames that don't fit into memory to disk?
It doesn't actually allocate 4 GiB. Memory can be mapped without being physically occupied.
No, web apps can actually use 4GB of memory (now 16GB apparently).
In fairness, this is talking about Figma, not an email client
Finally a web browser capable of loading slack
I assume that looking into the present we need to think about running local LLMs in the browser. Just a few days ago I submitted an article about that [1].
I'm excited by the GC, ref types and JS string API! Been a while J, how are you going?
> Garbage collection. In addition to expanding the capabilities of raw linear memories, Wasm also adds support for a new (and separate) form of storage that is automatically managed by the Wasm runtime via a garbage collector. Staying true to the spirit of Wasm as a low-level language, Wasm GC is low-level as well: a compiler targeting Wasm can declare the memory layout of its runtime data structures in terms of struct and array types, plus unboxed tagged integers, whose allocation and lifetime is then handled by Wasm. But that’s it.
Wow!
It's very refreshing and good to see WASM is embracing GC in addition to non-GC support. This approach is similar to D language where both non-GC and GC are supported with fast compilation and execution.
By the way now you can generate WASM via Dlang compiler LDC [1].
[1] Generating WebAssembly with LDC:
Does this allow for shrinking the WebAssembly.Memory object?
- https://github.com/WebAssembly/design/issues/1397
- https://github.com/WebAssembly/memory-control/issues/6
This is a crucial issue, as the released memory is still allocated by the browser.
No, I don't think it will. Pointers to managed objects are opaque, and aren't actually backed by the wasm memory buffer. The managed heap is offloaded.
Shrinking the memory object shouldn't require any special support from GC, just an appropriate API hook. It would, as always, be up to the application code running inside the module to ensure that if a shrink is done, that the program doesn't refer to memory addresses past the new endpoint.
If this hasn't been implemented yet, it's not because it's been waiting on GC, but more that it's not been prioritized.
Wasm GC is entirely separate from Wasm Memory objects, so no, this does not help linear memory applications.
I'm not familiar with WASM. Can someone explain why this is a good thing? How does this work with languages that do not have a garbage collector, like Rust?
The answer was kind of known before hand. It was to enable the use of GCed languages like Python on Ruby to create WASM applications. Meanwhile, non-GCed languages like Rust, C and C++ were supposed to continue to work as before on WASM without breaking compatibility. This is what they seem to have finally achieved. But I needed to make sure of it. So, here are the relevant points from the WASM GC proposal [1]:
* Motivation
- Efficient support for high-level languages
- faster execution
- smaller modules
- the vast majority of modern languages need it
* Approach
- Pay as you go; in particular, no effect on code not using GC, no runtime type information unless requested
- Don't introduce dependencies on GC for other features (e.g., using resources through tables)
[1] https://github.com/WebAssembly/spec/blob/wasm-3.0/proposals/...Note that the high level language needs a sufficient abstraction in its own runtime to allow substituting the Wasm GC for the runtime’s own GC. Work has been done for Java and Kotlin, but Python, C#, Ruby, Go can’t yet use the Wasm GC.
Agreed. That's what I guessed too. WASM GC is probably a low level component which high level languages can wrap to get their native/idiomatic GC behavior.
> Work has been done for Java and Kotlin
I'm unaware of this development. What did they do? Did they create an interface to the GC specification in the draft proposal?
Well, for Java it's actually a separate compiler that targets Wasm and integrates with WasmGC: https://github.com/google/j2cl The Google Sheets team used it for their calc engine: https://v8.dev/blog/wasm-gc-porting
For Kotlin it's similar but the compiler backend is from Jetbrains themselves, targets Wasm and adapts the Kotlin runtime to use WasmGC: https://kotlinlang.org/docs/wasm-overview.html. https://seb.deleuze.fr/introducing-kotlin-wasm/ has some low level detail on how Kotlin works with WasmGC.
A bit more on Kotlin/Wasm here, seems like also Dart/Flutter uses WasmGC: https://developer.chrome.com/blog/wasmgc#kotlin_wasm
https://github.com/dotnet/runtime/issues/94420 has some notes on why C# can't use WasmGC (yet?).
Good info! Thanks!
to also consider this one https://github.com/6over3/zeroperl
Non-GCed languages will continue to manage memory themselves. Previously, GCed languages that wanted to run on WASM had to have an implementation of their runtime including GC compiled to WASM. The idea or hope here is that those languages can use the built-in GC instead and slim down the amount of WASM that needs to be delivered to run the application to only include a minimal runtime. The current scenario is closer to if a web app or node app built with JavaScript had to ship a significant portion of V8 with it to function.
This will probably benefit Java applets targeting Wasm the most considering the huge size of their JVM.
Here's a fun example of a language that takes advantage of this: https://spritely.institute/hoot/
I works very well, thank you for asking: https://rustwasm.github.io/book/
This seems less than ideal to me.
1. Different languages have totally different allocation requirements, and only the compiler knows what type of allocator works best (e.g. generational bump allocator for functional languages, classic malloc style allocator for C-style languages).
2. This perhaps makes wasm less suitable for usage on embedded targets.
The best argument I can make for this is that they're trying to emulate the way that libc is usually available and provides a default malloc() impl, but honestly that feels quite weak.
I don't see this as a problem in the JVM, where independently of what programming language you are using, you will use the GC configured on the JVM at launch.
That sounds like WASM is going into the Java direction. Is that really a good thing?
What do you mean by the Java direction? It's a virtual machine with GC support, so I guess in that regard it's similar to the JVM, CLR, BEAM, et al. If anything, those VMs show performance improvement and better GC over time and a strong track record of giving legacy software longevity. The place where things seem to fall apart over the long term is when you get to the GUI, which is arguably a problem with all software.
Java approach: create the JVM to support one language, so it has rich high-level concepts that are unfortunately skewed toward certain assumptions about language design, and it can be reused only for other languages that are similar enough.
WASM approach: start very low-level so C is definitely supported. Thus everything is supported, although every language has to roll its own high-level constructs. But over time more patterns can be standardised so languages can be interoperable within a polyglot WASM app.
When is WASM finally going to be able to touch the DOM? It feels like that was the whole point of WASM and instead its become a monster of its own that barely has anything to do with web anymore. When can we finally kill JavaScript?
Agreed. This and (sane) access to multi-threading. I want to be able to write a Rust application, compile to wasm and load it with
<html>
<body>
<div id="root"></div>
<script type="application/wasm" src="./main.wasm"></script>
</body>
</html>
Would be great for high performance web applications and for contexts like browser extensions where the memory usage and performance drain is real when multiplied over n open tabs. I'm not sure how code splitting would work in the wasm world, however.v8 could be optimized to reduce its memory footprint if it detects that no JavaScript is running - or wasm-only applications could use an engine like wasmer and bypass v8 entirely.
Another factor is that web technologies are used to write desktop applications via Electron/similar. This is probably because desktop APIs are terrible and not portable. First class wasm support in the web would translate to more efficient desktop applications (Slack, VSCode, Discord, etc) and perhaps less hate towards memory heavy electron applications.
> <script type="application/wasm" src="./main.wasm"></script>
<applet code="./Main.class"></applet>
Plus ça change...
The difference is that now it is cool.
<!doctype html>
<wasm src="my-app.wasm">
Why not just do the whole DOM out of your WASM?If you're at that point, the logical step would be to just support replying to the HTTP request with a "content-type: application/wasm" and skip the initial html step entirely.
I'm on this team 100%. It makes a lot of sense for a lot of use cases (where SEO doesn't matter).
Not sure what the Rust situation is like, but last I checked (and compiled a non-trivial personal application) WASM supported the pthreads API and it seemed to work reasonably well. Have you encountered stumbling points porting a heavily MT Rust program to WASM?
That's supposedly WASI, an interface specifically designated for system programming use, and that's where it implements part of the POSIX support including pthread.
OTOH you still need to start a wasm runtime first, then import the WASI module into the wasm host.
P.S.: used to tinker with wasmtime and wasmi to add wasm support to my half abandoned deno clone ;) I learned this the hard way
WASI does not implement POSIX. And it isn't the goal of WASI to implement POSIX. It does not support pthreads either. WASI is similar to POSIX because its an API that provides a "system interface" for WASM programs. But the API is much simpler and quite different and capability based. There are things like WASIX (by Wasmer) built on of WASI that aims to provide POSIX support for multiple languages
Correct
WASM itself does not support pthreads. However things like Emscripten have very good support for pthreads. WASM is one of the compilation targets of Emscripten (we had asm.js before that) and on top of that emscripten provides excellent shims for many POSIX APIs. Regarding Rust which has supported WASM as a compilation target for a long time now, the idiomatic way of doing this is not shiming, but using higher level APIs: if you need parallel execution threads and need to compile to WASM you would use a crate (such as rayon) that is able to compile to WASM (and will use web workers under the hood just like Emscripten does). You would not use pthreads directly (std::thread)
WASM does not support pthreads in the browser, only web workers, which are much more limited.
You can do all of this using Rust today. Very sane access to multi-threading => writing rust code that runs in parallel and is compiled without you worrying about it to run under several web workers
That still requires a bunch of glue code right? Like, I can't simply compile my application to a wasm target and threads just work
cargo build --release --target wasm64
I think wasi has access to threading, but I don't think browsers support wasi?Yes there is some glue needed. The amount of boilerplate needed can be reduced with a bundler or depending on the library you use (just like it is the case when you use workers with JavaScript on the web, you can use a bundler with support for them or plugins to make it less of a pain to setup). wasm bindgen rayon provide support to use rayon in that context. There are also projects that provide lower level apis similar to std::thread. Std::thread will probably never support the wasm target.
It’s not WASI that gives you access to threading. Multi threading is a WebAssembly spec feature. Each thread is a separate web assembly module, they can share memory/code using SharedArrayBuffer if needed or WebAssembly tables for code. The host runtime for WASM whether it’s the web or something like wasmtime is responsible for instantiating those module in Web workers on the Web (or node…) or in new OS threads for wasmtime. I guess this is the thick amount of glue needed
I completely agree. The WebAssembly multi-threading programming model with its reliance on the web worker API is a pain to deal with. Google’s Native Client had native threading support, why can this not be replicated in WebAssembly?
Basically never, because it would require re-standardizing the DOM with a lower-level API. That would take years, and no major browser implementor is interested in starting down that road. https://danfabulich.medium.com/webassembly-wont-get-direct-d...
Killing JavaScript was never the point of WASM. WASM is for CPU-intensive pure functions, like video decoding.
Some people wrongly thought that WASM was trying to kill JS, but nobody working on standardizing WASM in browsers believed in that goal.
People have to look at it, from the same point of view Google sees the NDK on Android.
"However, the NDK can be useful for cases in which you need to do one or more of the following:
- Squeeze extra performance out of a device to achieve low latency or run computationally intensive applications, such as games or physics simulations.
- Reuse your own or other developers' C or C++ libraries."
And I would argue WebGL/WebGPU are preferably better suited, given how clunky WebAssembly tooling still is for most languages.
It's really not that hard. Node.js has a very mature C FFI for interacting with JavaScript.
Just agree on some basic bindings
wasb_create_u32(env: *const env, value: u32, result *mut value) -> status
wasb_create_string_utf8(env: *const env, str: *const c_char, length: i32, result: *mut value) -> status
There is even a shim that ports the Node.js C FFI to wasm: https://github.com/devongovett/napi-wasm/blob/main/index.mjs...Heck, just include that in the browser so it doesn't need to be loaded at runtime
Stack that with support in the browser for wasi and you have everything you need to work with the DOM from wasm as well as things like threading
That's the issue with WASM. Very, very few people want a limited VM that's only good for CPU-intensive pure functions. The WASM group has redirected a huge amount of resources to create something almost nobody wants.
A bit unrelated, but are there any recent benchmarks comparing it with native perf?
Hard to believe it can compete with V8 JIT anytime soon. Might be easier to integrate fast vector libraries within javascript engines.
Contrary to naysayers, I'm pretty sure this is very doable. Most browser JS objects map 1-1 to C++ native objects implemeneted in the browser.
As others have pointed out, the Js compoment interface is define in a language called WebIDL:
https://firefox-source-docs.mozilla.org/dom/webIdlBindings/i...
How it works in Chrome(Blink) is that a compiler generates a wrapper between V8, which is a V8 object that holds onto the native object reference using this IDL.
Once V8 cleans up the Js object, the native code, holding a weak reference to the native objects, detects that it has become unreachable and cleans that up.
In any ways, the object lifetime is encapsulated by the v8 Isolate (which is depending on how you look at it, the lifetime of the HTML document or the heap), so it'd be perfectly fine to expose native references as they'd be cleaned up when you navigate away/close the page.
Once you support all the relevant types, define a calling convention, and add an appropriate verifier to Wasm, it'd be possible to expose all native objects to Wasm, probably by generating a different (and lighter weight) glue to the native classes, or delegating this task to the Wasm compiler.
Of course, if you wanted to have both JS and Wasm to be able to access the same object, you'd have to do some sort of shared ownership, which'd be quite a bit more complicated.
So I'd argue it'd make sense to allow objects that are wholly-owned by the Wasm side or the JS side, which still makes a ton of sense for stuff like WebGL, as you could basically do rendering without calling into JS.
I'm going out on a limb here, but I'd guess since this multi-memory support has landed, that means a single webassembly instance can map multiple SABs, so it might be the beginnings of that.
You can write a WASM program today that touches the DOM, it just needs to go through the regular JS APIs. While there were some discussions early on about making custom APIs for WASM to access, that has long since been dropped - there are just too many downsides.
But then you need two things instead of one. It should be made possible to build WASM-only SPAs. The north star of browser developers should be to deprecate JS runtimes the same way they did Flash.
That is never going to happen until you create your own browser with a fork of the WASM spec. People have been asking for this for about a decade. The WASM team knows this but WASM wants to focus on its mission of being a universal compile target without distraction of the completely unrelated mission of being a JavaScript replacement.
It's also too early to worry about DOM apis over wasm instead of js.
The whole problem with the DOM is that it has too many methods which can't be phased out without losing backwards compatibility.
A new DOM wasm api would be better off starting with a reduced API of only the good data and operations.
The problem is that the DOM is still improving (even today), it's not stabilized so we don't have that reduced set to draw from, and if you were to mark a line in the sand and say this is our reduced set, it would already not be what developers want within a year or two.
New DOM stuff is coming out all the time, even right now we two features coming out that can completely change the way that developers could want to build applications:
- being able to move dom nodes without having to destroy and recreate them. This makes it possible so you can keep the state inside that dom node unaffected, such as a video playing without having to unload and reload a video. Now imagine if that state can be kept over the threshold of a multi-page view transition.
- the improved attr() api which can move a lot of an app's complexity from the imperative side to the declarative side. Imagine a single css file that allows html content creators to dictate their own grid layouts, without needing to calculate every possible grid layout at build time.
And just in the near future things are moving to allow html modules which could be used with new web component apis to prevent the need for frameworks in large applications.
Also language features can inform API design. Promises were added to JS after a bunch of DOM APIs were already written, and now promises can be abortable. Wouldn't we want the new reduced API set to also be built upon abortable promises? Yes we would. But if we wait a bit longer, we could also take advantage of newer language features being worked on in JS like structs and deeply immutable data structures.
TL;DR: It's still too early to work on a DOM api for wasm. It's better to wait for the DOM to stabalize first.
I am oversimplifying it, why should anything be stable?
That is the trend we face now days, there is too less stable stuff around. Take macOS, a trillion dollar company OS, not an open source without funding.
Stable is a mirage, sadly.
On the contrary, it’s something that solid progress is being made towards, and which has been acknowledged (for better or for worse) as something that they expect to be supported eventually. They’re just taking it slow, to make sure they get it right. But most of the fundamental building blocks are in place now, it’s definitely getting closer.
Aside from everything WASM has ever said, the security issues involved, and all the other evidence and rational considerations this still won’t happen for very human reasons.
The goal behind the argument is to grant WASM DOM access equivalent to what JavaScript has so that WASM can replace JavaScript. Why would you want that? Think about it slowly.
People that write JavaScript for a living, about 99% of them, are afraid of the DOM. Deathly afraid like a bunch of cowards. They spend their entire careers hiding from it through layers of abstractions because programming is too hard. Why do you believe that you would be less afraid of it if only you could do it through WASM?
Sounds to me like they forgot the W in WASM.
I agree with the first part, but getting rid of JS entirely means that if you want to augment some HTML with one line of javascript you have to build a WASM binary to do it?
I see good use cases for building entirely in html/JS and also building entirely in WASM.
getting rid of javascript entirely means to be able to manipulate the DOM without writing any javascript code. not to remove javascript from the browser. javascript will still be there if you want to use it.
Most of the time your toolchain provides a shim so you don’t need to write JS anyway. What’s the difference?
right, that's exactly the point. those that have a shim already successfully got rid of javascript, and that's enough.
Fair enough, I misunderstood what he meant by "deprecate JS runtimes".
You can use a framework that abstracts all the WASM to JS communication for DOM access. There are many such framework already.
The only issue is that there’s a performance cost. Not sure how significant it is for typical applications, but it definitely exists.
It’d be nice to have direct DOM access, but if the performance is not a significant problem, then I can see the rationale for not putting in the major amount of work work it’d take to do this.
Yew, Leptos and Dioxus are all pretty decent with their own advantages and disadvantages if you like Rust. It's been a year or so since I last looked at them, to me the biggest missing piece was a component library along the lines of MUI to build useful things with. I'd be surprised if there weren't at least Bootstrap compatible wrapper libraries for them at this point.
I was under the impression that this very much still on the table, with active work like the component model laying the foundation for the ABI to come.
I have slightly different question than OP - what's left until it feels like javascript is gone for people who don't want to touch it?
Say I really want to write front end code in Rust* does there just need to be a library that handles the js DOM calls for me? After that, I don't ever have to think about javascript again?
> Say I really want to write front end code in Rust* does there just need to be a library that handles the js DOM calls for me? After that, I don't ever have to think about javascript again?
yes, e.g. with Leptos you don't have to touch JS at all
Isn't going through the JS APIs slow?
used to be, in the early days, but nowadays runtimes optimized the function call overhead between WASM and JS to near zero
https://hacks.mozilla.org/2018/10/calls-between-javascript-a...
It did improved a lot, but unfortunately not near zero enough.
It is managable if you avoid js wasm round trips, but if you assume the cost is near zero you will be in for a unpleasant surprise.
When I have to do a lot of different calls into my wasm blob, I am way way faster batching them. Meaning making one cal into wasm, that then gets all the data I want and returns it.
Could you list some of these downsides and what are the reason of their existence?
For starters, the DOM API is huge and expansive. Simply giving WASM the DOM means you are greatly expanding what the sandbox can do. That means lower friction when writing WASM with much much higher security risks.
But further, WASM is more than just a browser thing at this point. You might be running in an environment that has no DOM to speak of (think nodejs). Having this bolted on extension simply for ease of use means you now need to decide how and when you communicate its availability.
And the benefits just aren't there. You can create a DOM exposing library for WASM if you really want to (I believe a few already exist) but you end up with a "what's the point". If you are trying to make some sort of UX framework based on wasm then you probably don't want to actually expose the DOM, you want to expose the framework functions.
> you probably don't want to actually expose the DOM, you want to expose the framework functions.
Aren't the framework functions closely related to the DOM properties and functions?
I am watching patiently from a distance to my hands on a well-designed frontend language but can't help to wonder... is it really _that_ inefficient to call a JS wrapper to touch the DOM?
Most code already is so horribly inefficient that I can't imagine this making a noticeable difference in most scenarios.
No, it's not that bad honestly. But it's not more efficient than JS either, and all this ugly glue code hurts my sensibility.
Sounds like something that could be trivially turned into a library, no?
There are some already (https://docs.rs/web-sys/latest/web_sys, for example), and I made mine too as an exercise. But it's still ugly, unecessary, verbose and inefficient code.
GC was required part, because it was needed to allow interaction between DOM-side lifetimes and WASM-side lifetimes. You might still need a puny shim to essentially "declare" whatever form you want the DOM API to look like on WASM side (probably utilizing components and WIT in the future) but that shim won't have to do anything other than register the APIs because WASM will be able to take a reference to DOM object and vice versa instead of throwing a copy of data over the wall as it is now.
> When can we finally kill JavaScript?
If you think JavaScript has problems I have bad news about the DOM…
Wanted to say the same thing. People often conflate JS with the DOM API, but that couldn't be further from the case.
You can get rid of JS, but that won't help much because it's just a small language interfacing with a huge, old, backwards compatible to 20+ years ago system that is the DOM.
yep, ive still never understood the fetish of HN folks wanting to eliminate JS completely. you tell them to use TS, they say its overcomplicated... i've never heard a definitive or decent answer to "ok what language WOULD you use for manipulating the DOM?" its infuriating, though i suppose those complaining have probably built like one website once. yes, JS is not your strongly typed Rust / Go / .NET, get over it - go learn TypeScript and be happy
I don't think WASM by itself will finally kill Javascript, other languages and their tooling are not well equipped to create DOM-based applications with the constraints expected for the web (fast loading times, lazy-loading, asset bundling, etc).
I don't think most languages it is even feasible to compile to wasm in a way that doesn't include a splashscreen for any non-trivial application. Which is simply unacceptable for most web content. And that is even before all the work required in user-land to support browser primitives (like URL routing, asset loading, DOM integration, etc).
So I can foresee this unlocking "heavy duty productivity apps" to run in the browser things like video editors or photoshop using web-first GUI (meaning DOM elements) without significant amounts of JS. But for general web content consumed by the masses I find it unlikely.
I expect the real "javascript death" will mean a completely new language designed from the ground-up to compile to WASM and work with browser APIs.
One of the things that I think make this tricky is that if you have any DOM references you now have visibility into a GCable object.
Part of the web Javascript security model is that you cannot see into garbage collection. So if you have some WASM-y pointer to a DOM element, how do you handle that?
I think with GC in properly people might come at this problem again, but pre-GC WASM this sounds pretty intractable
Probably never. There's a pretty good recent thread on this topic:
Hot take alert
> When is WASM finally going to be able to touch the DOM?
Coming from a web background, and having transitioned to games / realtime 3D applications...
Fuck the DOM dude. The idea that programming your UI via not one but TWO DSLs, and a scripting language, is utter madness. In principal, it might sound good (something something separation of concerns, or whatever-the-fuck), but in reality you always end up with this tightly coupled garbage fire split across a pile of different files and languages. This is not the way.
We need to build better native UI libraries that just open up a WebGL context and draw shit to that. DearIMGUI can probably already do like 85% of what modern webapps do.
Anyways .. /rant
> DearIMGUI can probably already do like 85% of what modern webapps do
I’m with you. Main blocker I’ve seen to “just use ImGui for everything” (which I’d love to adopt), is if I run ImGui in WASM the keyboard doesn’t open on mobile. This seems possible in theory because egui does it.
Even though running ImGui on mobile via WASM isn’t the primary use case, inevitably the boss or someone is going to need to “just do a quick thing” and won’t be able to on mobile, and this seems to be a hard ceiling with no real escape hatch or workaround.
One of those scenarios where, if we have to use a totally different implementation (React or whatever) to handle this 1% edge case, we might as well just use that for the other 99%.
I'd say two things about this.
1. Opening the native keyboard and plumbing those events through to the WASM runtime sounds pretty easy. It's probably not cause modern software, but conceptually it should be trivial.. right??
2. In terms of 'the boss' wanting to do 'that one weird thing' that there isn't a library/plugin/whatever for in DearImgui land. If dev time for everything else gets faster, than the 10x cost of that small corner case can be absorbed by net win. Now, I'm pretty sus on the claim everything else gets better today, but we can certainly imagine a world where they do, and it's probably not far away
> Opening the native keyboard…
I think this is the roadblock, that there isn’t always a way to pop open the keyboard programmatically. Rather, the mobile keyboard only pops up when there’s a DOM input element detected. So it would need a hidden input layered on top of the ImGui WASM app and mapping coordinates, or would need an HTML input element overlayed on top of every text input.
I mean, yikes. But having a hidden html input you just piggy back off of also doesn't sound that bad
Preach. HTML and CSS are markup languages for creating documents. Using them for GUI applications is wild and obviously a bad idea.
HTML is pretty bad (XUL was better), but (subset) of CSS is probably OK.
HTML isn't even a particularly good markup language for documents, web or otherwise.
> Using them for GUI applications is wild and obviously a bad idea.
I agree it's wild, but bad idea implies there are better options for cross platform applications with the same ease of distribution, and accessibility as the web.
Most major GUI frameworks operate on something very similar to HTML + CSS.
> We need to build better native UI libraries that just open up a WebGL context and draw shit to that. DearIMGUI can probably already do like 85% of what modern webapps do.
Would be totally into that! But then as soon as you're developing for a worldwide paying audience (or your employer is), one manager realizes the need for ARIA stuff, another for SEO, another for fully-native input controls (textboxes, checkboxes, radios, buttons etc) for most-fluid&familiar UX on every OS, another for embedding externally loaded markup+scripts (whether that's social media sharing widgets, auth providers, Google Maps / OpenStreetMaps etc), for supporting user-generated `<img>`s and `<video>` in all the various formats the browser natively furnishes, and on and on and on =)
That's true. But without the DOM we also loose the browser native accessibility support and text interaction and so on.
I know nothing about how accessibility supports works in the browser, but could they offer a way to use the accessibility API with your custom UI rendered in WebGL/WebGPU?
There doesn't exist a way to infer the individual elements of a rendered frame in canvas because it just encodes the pixels. You can't know which pixels make up a text or button, that information is lost, unlike a DOM tree.
> We need to build better native UI libraries that just open up a WebGL context and draw shit to that.
This is what Flutter does. It works well, but you do lose some nice things that the browser/DOM provides (accessibility, zooming, text sizing/selection, etc). There’s also a noticeable overhead when the app + renderer is initially downloaded).
Couldn't you implement something like HTMX in wasm then and still have locality-of-behavior by specifying the behavior as html attributes?
Maybe some day, maybe never. A different, perhaps more important question is, does it matter?
Probably only after Components and WIT are stabilized. No point of making it wihtout it IMO.
From what I understand, WASM is purely functional, to perform side effects, you will need a runtime like WASI to implement it
Even if you had that environment today, how would you replace the function of JS?
Web development moves faster than any software in history. A lot of this is on the back of JS being ergonomic/fast to code and having very good performance and a lot of what makes it good at this is also what coders familiar with other languages dislike.
What other language has that right combination of really fast development and good performance?
You would probably have to go outside the mainstream to something like Scheme or StandardML to get the ergonomics and performance, but that would upset a whole other group of people.
After that is an even bigger problem. If everyone adopts different languages, different frameworks for those languages, and different user-facing APIs for the WASM APIs, then finding devs for your frontend team who can be productive quickly suddenly becomes impossibly hard.
I would bet on browsers being able to consume Typescript before WASM exposing any DOM API. That'd improve the Javascript situation a bit, at least.
Not TS, but there are plans to allow something similar with special type annotation syntax. The runtimes still won't do anything with that extra info though, it'll get stripped just like comments.
What are you referring to?
My bad, didn't fact check myself before I made an annoying quip. For some reason I thought browsers and started to roll out out native support for TS.
It's been stuck at stage 1 since early 2022 unfortunately. https://github.com/tc39/proposal-type-annotations
Maybe you got confused, because NodeJS is now able to strip annotations (it does not transform enums, etc) to let you run Typescript files directly.
Ahhhh, that was it. Thank you
this is a really bad and out of touch take