Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Wasm3 compiles itself (using LLVM/Clang compiled to WASM) (twitter.com/wasm3_engine)
178 points by 0xedb on April 24, 2021 | hide | past | favorite | 105 comments


What is the state of the world with wasm at this point? It seems like it's been this huge tease for 10 years now, promising that we'll be able to build web apps in any language. But as far as I'm aware, garbage collection and DOM access is still nonexistent.


Good question, still a "green" technology but I have had great successes with it for the past 4-5 years in production (ASM.JS before widespread WASM compatibility).

"promising that we'll be able to build web apps in any language" is not how I see WASM, nor is it really used in this way outside of transpiling Unity3D/Unreal games (this may be the one area there is an exception). I use it to transpile C++ to WASM libraries used within React apps, Edge Lambdas, and Node.JS servers. Primarily down to 2 reasons: speed and efficiency. WASM unlocks excellence and resources in other disciplines/languages such as AI and AR tool chains, Engineers, OpenCV, etc. When used like this, it is outstanding.

What WASM will never be good at is being used for the whole experience. You lose the semantic web, and/or accessibility tooling. Web has some outstanding guidelines and frameworks to help the impaired, screen readers and the like. Using WASM to pump a native app into a HTMLCanvasElement will lose all of these advances, therefore, WASM shouldn't be used for this use case (outside of games). Like all tooling, there is a time and a place to use them.

Below are a few links which use WASM in production:

https://holition.com/play/holition-brings-home-twenty-awards...

https://winners.webbyawards.com/2020/apps-mobile-and-voice/a...

https://www.youniqueproducts.com/beautyguide#.YIS9hOhKguU

https://www.charlottetilbury.com/us/products/charlottes-virt...

https://visagetechnologies.com/demo/


> "promising that we'll be able to build web apps in any language" is not how I see WASM

Unfortunately it kind of got branded this way for people who aren't close to the front-end industry. There's a segment out there who would like to write web apps but aren't willing to touch JavaScript with a ten-foot pole, and their hopes were gotten up that WASM would give them that. It's not exactly a lie, but it has so many asterisks that it may as well be.

In practice, the reality is that JS will continue to be the only first-class language for the web. WASM has many uses, some on the web and some outside of it, but the closer your app is to the DOM and to the browser as a platform, the less likely it is that you'll ever be able to pretend JS doesn't exist.


Blazor client-side (for dotnet) works fine with minimal asterisks, and even those issues are being slowly solved as WASM evolves with multithreading, GC, and DOM access.


In general I agree with your points, but:

> What WASM will never be good at is being used for the whole experience.

The Flutter team would disagree.

They are leaning on WASM for browser builds of Flutter apps, with the whole app rendering in a canvas.

They do accessibility via separately created accessibility trees.

The experience far from great at the moment, but give it a few years and I think it will get there. (better wasm optimisations, direct host interop without JS shims, GC, threads, maybe WGPU instead of canvas, ...)

If that's a good thing for the web is another question...


Unfortunately, Flutter apps still seem to be lagging on the accessibility front. The Flutter web gallery[0] has many examples of beautiful apps, but something as "simple" (on the web) as being able to select text is absent.

For some use-cases, this is a nonstarter. (Sadly, not to as many as I'd like! But let's simply not regress, to start.)

[0] https://gallery.flutter.dev/


It also seems to be lagging on the literal front, at least on my iPad.

Considering these are just hello world apps, the performance has a long way to go.


It’s worth keeping in mind that Flutter for web had its 1.0 release a matter of weeks ago. It’s very impressive with what they have done so far but let’s see where it goes. The amount of potential there is truly huge.


Agree that it's exciting to see, but what's the actual potential? Flutter developing into a latter-day Macromedia Flash?


It’s genuinely hard to tell if you are serious about this or not. Either way it somehow perfectly encapsulated the kind of thing this website is famous for. Congratulations?


Flutter feels so strange to me. In many ways, it's reimplementing major parts of a browser, compiled to (web)assembly, running inside a browser compiled to assembly... Watch five years from now someone add a low-level programming framework to Flutter and then soneone else reimplement the browser using that


Flutter is a UI framework on top of a low level programming framework, Dart. Sort of like UIKit and Cocoa.


I think you're thinking of Skia. Dart is a language.


Turtles all the way down! It would be more humorous if we used Skia, since that arguably fulfill's OPs proposition that someone would eventually rewrite the browser in said framework


The flutter web text field don't even handle multiline text input with IME properly. Cause the whole text field to scroll while select character from IME dropdown. I'd doubt how could that be count as "good user experience".


WebAssembly Summit 2021 was this week, and that is definitely not how the people on the frontline are selling it, BBC is even on the process to fully rewrite they iPlayer in C++.


Well built in garbage collection is non-existent. You can definitely use languages with GCs, you just need to include the GC in the bundle. You can do DOM access as well, it's just not particularly efficient.

Overall I think WebAssembly definitely has some usecases, they're just not as visible as people expected. Sites like Figma or Lichess use WASM but not in a super flashy way.


I'm optimistic dom access will get better soon. Check out https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtua... for example.


Funny story, in 2013 I was working for the Google Earth team. A new clean slate version of Google Earth was in the works (which has been released since) and this was at the time that wonderful demos were being made with asm.js

I convinced one of the engineers to try compiling it in emscripten. It was a total success, running at 45 fps. The middle manager got so excited about this that he decided to make a full push for this version of google earth to be used since it was truly cross platform product running in the browser at near native speed.

The portable Native client / webassembly team caught wind that this was happening and convinced management to kill the project. The middle manager who was overly excited about this technology, was also let go.

All this to make way for web assembly which was “right around the corner” but actually wasn’t (back in 2013). Today web assembly is essentially doing the same thing that asm.js was doing 8 years ago.

If Google had not messed up this decision it would have really been a trailblazer for other companies to follow suit.


Lol! The funny thing is that at that point, the code you were shipping was "just javascript" but in a machine generated format. When places go out of their way to tell you about their engineering culture, they often aren't.


TBH DOM is garbage for building apps, but if you need to use it it's clear that it's built for JavaScript. TypeScript made JS manageable and there's so much work in the JS ecosystem arround DOM interaction, I sincerely doubt you'll see anything come out of this. I haven't looked at Blazor/MAUI but having experienced MS frontend tech in Silverlight and Xamarin, I'll take the JS/DOM any day.

Ideally WASM would expose lower level APIs and then we can start treating the browser as the app sandbox that it is (in the case of buildign apps).


You would love Svelte. It makes the entire web ecosystem look and feel like the dark ages in comparison.


Svelte made me want to have time to write a new Common Lisp framework. Really, that's how one should look like, at least as far as the results on the client side are concerned.


DOM access is possible with a bit of boilerplate to make the WASM aware of the APIs. In Rust, crates like js-sys and wasm-bindgen automate most of this.

Rust also has the Yew framework, which is surprisingly nice to work with given that Rust is not a frontend language and it only uses the built-in macro system rather than a preprosessor like JSX.


It is stuck in MVP 1.0 capabilities, still years away to reach out the capabilities of Flash/CodeAlchemy and PNaCL in 2021, while tools like Emscripten feel like stone age technology, where you need to mount Lego pieces by yourself.


The priorities seem to have shifted, with most standardization efforts being focused on running WebAssembly on the server, rather than web browsers.

Flutter and Blazor are exceptions, but they had to reinvent everything their own way.

Regarding languages, the landscape is pretty much limited to Rust (when using compatible crates), Zig, TinyGo, AssemblyScript and C# (with Blazor).

The specification started with something very simple but keeps getting more and more complicated, not to mention breaking changes, that don’t encourage writing tooling for it. At least not until things settle a little bit.


In my view, the DOM is too cluttered and bloated, difficult to work with if you're a browser. There are a lot of things that should be made deprecated, but it's difficult to decide which things, since big browser are usually rivals (apple, google, microsoft, mozilla...).

Browsers are already pretty complex machines, considering javascript and the DOM and everything that comes along. Expecting all browser to let WASM have access to the DOM is a big demand.


It probably needs a killer app. To me it feels like it's a solution looking for a problem.


WASM alredy got a killer app: being able to run any snippet of any language in a browser. For teaching programming, it's use, because projects like pyiodine can load a full python vm in a the browser and let the student experiment with the snippet without taking the risk of ruining my server.


Pyodide is pretty amazing. https://pyodide.org/en/stable/


Figma is pretty killer


> in any language

Is anyone using a language other than C, C++ or Rust to target Wasm? Many other languages seem to have experimental support - but are any of them ready for production, or even making significant progress towards being ready?


Go also has good support and Java has http://teavm.org/ and JWebAssembly. There is also the general https://wasmer.io/ for using web-assembly in any language. They claim they have good support for other languages like Python and PHP but I personally never tested that.


There is Blazor, which compiles C# ASP.NET-like code to a client-side application that runs on wasm.

https://en.m.wikipedia.org/wiki/Blazor


Wish I had a RemindMe! bot on HN for comments like these.


There's no garbage collection in WASM. Why do you think that there is garbage collection in WASM?

And WASM has been around since 2017, which is only 4 years, not 10 years... Bitcoin has been around much longer (~12 years), for example.



Yes, and this is just an extension. Existing WASM compiler front-ends for non-GC languages don't have to necessarily use it. Wasm itself still won't take a performance hit, unless individual devs opt in by using front-ends for GC languages.


Emscripten hit 1.0.1 around November 2012 (looked it up on GitHub)

So if wasm is the spiritual successor to Emscripten's "Compile C to JavaScript and run C in a browser" then it's only 8 years.


I mean, you can keep playing this game and take Microsoft ActiveX or Google NaCl as another spiritual successor. I maintain that WASM has been around for 3 years.


For those wondering, Wasm3 describes itself as "the fastest WebAssembly interpreter". Other webassembly runtimes are JIT based, rather than being interpreters. The project's readme (https://github.com/wasm3/wasm3) talks more about this decision.

For more on the difference, and an explanation of what JIT is, check out this section of the book Crafting Interpreters (https://craftinginterpreters.com/a-map-of-the-territory.html...)


Wasm3 calls its interpreter design a "meta machine": https://github.com/wasm3/wasm3/blob/main/docs/Interpreter.md...

It is heavily based around tail calls. I recently wrote a blog article about how we applied a similar tail-call-oriented strategy to accelerate protobuf parsing to 2+GB/s: https://blog.reverberate.org/2021/04/21/musttail-efficient-i...

I also recently landed a change in Clang trunk that offers guaranteed tail calls, so that this tail call design is safe in non-opt builds: https://reviews.llvm.org/D99517 I think wasm3 could benefit from using this attribute when it is available.


How do guaranteed tail calls work when you needs to put arguments on the stack, which usually prevents tail call? (and whether a specific call needs to pass arguments on the stack depends on the platform, and the number and type of arguments)


The musttail attribute performs several checks to ensure that a tail call can be guaranteed, and rejects the program if these rules are violated. The documentation has the details: https://github.com/llvm/llvm-project/blob/3b8ec86fd576b9808d...

These rules guarantee that the tail call is possible to perform on every platform. They end up being more strict than is necessary on some platforms and calling conventions.


> Other webassembly runtimes are JIT based, rather than being interpreters.

Do none of the notable ones do normal compilation?


Some runtimes like wasmtime support AOT compilation artifacts that can be loaded.

But in general you can't "just compile" Webassembly, because you need a runtime.

There is a C project that can compile an executable that includes the runtime and the compiled WASM, but the name is escaping me right now.

Note that JIT in the WASM world doesn't quite mean the same thing as for eg Java. Almost all runtimes compile a whole module at once, not individual functions.


Compiling individual functions was something in Java JITs like 20 years ago, they are a little bit more clever nowadays.


What would the difference be between “JIT” and “normal” compilation for WebAssembly?


An AOT compiler would do a one-time translation to a platform-specific binary.

If the environment you run on doesn’t support JIT compilation (iOS for example), AOT compiling WASM is useful.


At that point, what's the purpose of using WASM at all?


You can keep the sandbox intact after AOT.

https://hacks.mozilla.org/2020/02/securing-firefox-with-weba...

> The core implementation idea behind wasm sandboxing is that you can compile C/C++ into wasm code, and then you can compile that wasm code into native code for the machine your program actually runs on. These steps are similar to what you’d do to run C/C++ applications in the browser, but we’re performing the wasm to native code translation ahead of time, when Firefox itself is built.

It's a middle ground between sandboxing with subprocesses (which adds all the overhead of IPC) and switching to a fully memory-safe language (Rust, JS, etc.)



If I were writing a sandboxing or instrumentation tool, operating on WASM would be much simpler than dealing with the quirks of assembly, syscalls, or some higher-level IR.


How can a platform not support j.i.t. compilation?

In what way does a platform need to coöperate with that?


A JIT generally means it compiles parts of the program to machine code on the fly before running them, as needed.

To support that, the environment must allow the JIT to write machine code to memory, and then execute that same code.

CPUs have memory protection flags to control which memory areas can be written, and which can be executed. The OS is in charge of setting those flags, on request from the application. Eg. mmap and mprotect system calls.

iOS denies requests for memory that is both writable and executable at the same time. So applications cannot get the type of memory area a JIT needs. There are indirect methods where a file is written then mapped, like generating a small program or shared library on the fly. But iOS restricts these as well.

There are workarounds for a developer's personal applications, used on their own registered iOS devices. But these workarounds cannot be run by everyone else, except people with a jailbroken iOS. They cannot be used in applications on the App Store.


W^X is not the issue here. JITs can deal with that, and in fact should do so even when it's not OS-enforced for security reasons. The problem on ios specifically is code signing, which is a problem for both JIT and AOT.


"There are indirect methods where a file is written then mapped, like generating a small program or shared library on the fly. But iOS restricts these as well."


Some platforms are enforcing https://en.wikipedia.org/wiki/W%5EX because malware also wants to create novel machine code within a running process.


Note that it is possible to JIT even with W^X. What these platforms do is prevent memory that has been mapped writable and overwritten with new code from ever being mapped executable again.


So mostly I'm interested in compilers that compile the entire thing before any execution happens. Technically both AoT and JIT compilers can do that, but 95% of the things associated with "JIT" involve compiling the program one piece at a time.

But even with the broad definition of JIT, one important difference is that AoT compilers don't have to mark pages executable.


I think the model is typically that optimisation applied in "normal compilation" are applied when the source language is translated to WASM, meaning that the WASM -> native translation can be quite straightforward and still performant.


I worked on one as an undergrad: https://github.com/gwsystems/aWsm

Full AoT compilation, C programs run within 10% of native


10% difference from native, or 10% of native performance?


10% worse performance. Not 10x worse :D


Since it compiles using llvm, what's the reason for the discrepancy?

Lost information about e.g. aliasing?


Bounds checking, dynamic dispatch is more expensive, wasm semantics have no undefined behavior to exploit for optimizations. And there is bloat in the process. I’m sure losing information effects things as well



WAVM and SSVM do normal compilation.


I'm a newer dev so pardon my ignorance. Is webassembly the new, more open JVM? Feels like that write once, run everywhere but this time with any(most) mainstream language.


I certainly would not say ‘more open’. It is newer, but that's a mark against it, not for it.

It lacks most of java's ‘batteries’—there are projects like WASI that try to resolve this at a low level, but they miss the point somewhat. On the other hand, wasm is saddled with fewer assumptions about the type of code that will run on it. Wasm has generally poorer performance, which is mostly (though not entirely) an artifact of its design, and hence not easily rectifiable[0]. It's not clear to me the extent to which the jvm suffers similarly[1].

Socially, I think wasm is not as interesting as java. Write-once-run-anywhere was solved in practice not by java but by open source; by compatibility libraries like sdl; by standards, like posix and opengl; and by static linking. (Yes, it's not quite as convenient as just plopping in a jar, but it's close enough.)

I don't think we're ever going to see a desktop full of wasm apps. Despite stated goals, the point of wasm was always to be an evolution of the web as a platform for applets. The Birth and Death of Yavascript[2] has many insights thataways (even though it failed to predict wasm as such).

0. https://www.usenix.org/system/files/atc19-jangda.pdf

1. It's also difficult to directly compare the performance of the two systems in their current state. A number of proposals for both (gc for wasm, value types for java, simd for both) are yet pending and are likely to change the runtimes' respective performance profiles.

2. https://www.destroyallsoftware.com/talks/the-birth-and-death...


Why do you say that WASI misses the point? (genuinely curious)


It seems like it's headed that way. At the moment, it's only really practical to generate WASM from compiled languages, or really small languages, like Lua. And your interfaces to the browser (and thus, the outside world) itself are pretty limited, so still lots of javascript involved.


Can confirm that Lua does run in WASM in the browser: https://github.com/vvanders/wasm_lua

I sometimes wonder what the world would be like if Lua had zero based indices and saw a bit broader adoption. It's such an easy language to embed/extends although QuickJS looks like it's going to give it a run for the money in the long term given the similar goals on ease of embedding.

I wonder if anyone has compiled QuickJS to WASM and run it in the browser.


> I wonder if anyone has compiled QuickJS to WASM and run it in the browser.

Fabrice Bellard actually did it himself here: http://numcalc.com/


If your language is supported by LLVM, then Emscripten can compile it to WASM.


Yes, but for interpreted language 'X', are the created artifacts of a practical size to send down the wire for an actual production site? The idea being that as WASM adds higher level primitives, that size gets smaller.


Sorry, I misread your comment. I thought you wrote that only "small languages", or Lua, can be compiled to WASM.


I'm also trying to build a mental model of what wasm is so someone correct me if I'm wrong.

As I understand, the JVM adds a thick layer of abstraction between incoming bytecode and output machine instructions. A wasm "runtime" OTOH adds a much thinner abstraction between incoming wasm and outputted machine code. It's a fairly 1:1 transformation.

However, I think you're correct in that, in order to serve as a host for GC'd and/or web-API-aware scripting languages (DOM, etc), a wasm runtime will need to become more JVM-like. How will wasm remain "web assembly" while doing that? No idea. This is where my mental model breaks down.


Wasm lacks a lot of lower level system specific operations that the jvm offers.


In a way, but wasm is designed to be a lot better at sandboxing.


Not really, whilst bytecode would be slightly harder to verify than an AST a paranoid interpreter wasn't that hard to craft.

Iirc J2ME impls could be fairly secure (barring bugs since many were written in an age before security became a focus), and I think the spec even mandated pre-computed stack-frames (the expensive part of verification that is easy to post-validate for correctness).

Another part of J2ME was because like wasm/web, the runtime API was fairly small and all code could be contained within the sandbox with only API-extensions allowed to be native functions. (This restricted API and it's quite sad UI capabilities was probably part of why Apple ignored it entirely for iPhones)

What was much worse however was the mainline JVM and the Applets, Applets had from day 1 relied on all kinds of mainline JVM features and this featureset kept growing.

Features were encouraged to be written as much as possible in Java but many still had more or less large native parts. This is in addition to the core that allows for quite a bit of code loading,etc (that was allowed from applets).

All these features and loading that could allow for insecure behaviour was secured by a security policy system, sadly there was so many features that were exposed that used powerful dynamic features (the because they were whitelisted) allowed for untrusted code to behave or do stuff only trusted code should.

https://docs.oracle.com/javase/7/docs/technotes/guides/secur...


Self-hosting (compilers) https://en.wikipedia.org/wiki/Self-hosting_(compilers) :

> In computer programming, self-hosting is the use of a program as part of the toolchain or operating system that produces new versions of that same program—for example, a compiler that can compile its own source code


How big of a milestone is self-hosting for a language?


The wikipedia article lists quite a few languages for which there are self-hosting compilers.

JS can already write more JS. Are there advantages and risks introduced by this new capability for browser-hosted (?) WASM LLVM to compile WASM?


Has anyone built a compiler extension and libffi-based runtime that supports compiling otherwise normal native code to WASM (eschewing hard linking for runtime resolution)?

Would be fun to make it so that native apps for any platform can be run from an interpreter


Emscripten?



I'm somewhat curious at what pace WASM will gain "market share" while it's only practical to target it with C, C++, Rust, etc.

Supposedly, there are plans to expand it to where it looks more like a virtual machine and less like ASM. Adding things like garbage collection, direct DOM manipulation, polymorphic inline cache, etc. Things that would make it possible to run a decent scripting language without pulling in some huge runtime.

Or forgetting the scripting languages, just the direct DOM access might make it less tedious to use with compiled languages.

It's sort of a second run at getting "applets" right, but in a cross-language way.


> Adding things like garbage collection, direct DOM manipulation, polymorphic inline cache, etc. Things that would make it possible to run a decent scripting language without pulling in some huge runtime.

Doesnt this just imply building a 'huge runtime' into the language?


Not necessarily. GC can be implemented in a way that's fairly compatible with low-level programming, by leveraging support for multiple address spaces and/or memory segmentation. And WASM needs that kind of support anyway for its planned module-based security.


FWIW, AssemblyScript[0] adds its own garbage collection runtime into Wasm. The team had a good post recently on the performance implications[1]

[0] https://www.assemblyscript.org/

[1] https://surma.dev/things/js-to-asc/index.html


Not sure I understand. If parts of the runtime are already in the browser, then there's less to download.


> Things that would make it possible to run a decent scripting language without pulling in some huge runtime.

Seems to me the web already has an answer for that: transpile to JavaScript, and leverage the existing high-performance JavaScript engines.

Dart does this, for instance.


Graalvm native image has the ability to target llvm with a goal of making it easier "to target a new architecture without having to implement a complete new backend for Native Image."

https://www.graalvm.org/reference-manual/native-image/LLVMBa...


> while it's only practical to target it with C, C++, Rust, etc.

You might not want to bundle Rust in with C and C++ in this context. Rust is pretty accessible to developers coming from scripting languages (JavaScript, Python, etc).

Direct DOM manipulation (and the ability to send reference types across the JS-wasm boundary) is a pretty big deal though I think. Currently it doesn't make an awful lot of sense to build code that interacts with the DOM in WASM (although in Rust there are automatically generated bindings that go through a JavaScript shim).


> Rust is pretty accessible to developers coming from scripting languages (JavaScript, Python, etc).

Not in a way that is unique to Rust…


I think WASM success won't be measured by market share gain on the web, but by number of new non-browser things that are programmed with WASM.


Agreed. An interesting example is the new Microsoft Flight Simulator, which uses WASM[0] as a sandboxed language to create airplane gauges and custom flight models (HN discussion[1]).

[0]: https://forums.flightsimulator.com/t/getting-started-with-wa... [1]: https://news.ycombinator.com/item?id=24281400


Very Cool!


In that specific situation I find it very uncool. It's targeted only by C++, a language that is far too complex to have any business being used as a scripting language to make needles move on a virtual altimeter. You get all of the drawbacks with none of the benefits of a C++.


I don’t find it uncool at all. Well we have to start somewhere. Don’t you think this usage of WebAssembly is at least providing some feedback into it’s ecosystem to make improvements for next time? Id rather have developers choosing webassembly even if the implementation doesnt meet our expectations yet


EOS blockchain contracts are compiled to WASM.


it seems more like it's it's trying to be LLVM but for the web?


Looks like wasm3 is created by embedded/hardware guy, that is really interesting.


anybody wasmer.io




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: