Hacker News new | ask | show | jobs
by vincentriemer 3121 days ago
Maybe I just can't find it, but the largest blocker for using Rust on the web for me is a lack of a exposure/binding system (like embind).

I'm not particularly interested in writing entire webapps in Rust but I do see it being useful for smaller self-contained modules inside a larger JS app. Not having a robust binding API makes that difficult.

EDIT: But unrelated criticisms aside, congrats on the progress! I'm excited to see more first class support of WASM from languages other than C/C++.

4 comments

I agree that the best use-case here isn't full apps in Rust, but writing high-performance modules.

The webpack team is working on stuff so you can just drop a rust file into your proejct, and it will do everything needed for super easy integration.

https://crates.io/crates/stdweb sort of gives you the bindings you want, by the way.

I am excited for WASM for the same reason; not for wholesale migration, but targeted optimization. Hope documentation for this (likely very popular use-case) improves as WASM matures.
Can anyone describe the (overhead) cost of calling into WASM code in the implementations so far? A lot of optimize-able areas are things like RxJS or Promise implementations (eg Bluebird), or generally libraries making the stack trace like [userspace code] -> [library code, approx 20 stack frames] -> [more userspace]. Should we think of the WASM-JS bridge cost like system calls, or like inline assembly?
I'm curious about this too.

I hand-wrote a perlin noise generation function in asmjs when that was the future. Then I called my noise function from a loop in javascript to paint an image (1 call per pixel - about 1M calls). Running the perlin noise code with the asmjs engine in Firefox turned out to be a bit slower than running all the code through FF's regular javascript engine. The asmjs code ran fast, but the FFI overhead at the boundary between JS and asmjs made the system slower overall.

Given how easy it looks, I might try the same experiment with Rust & WASM to see where we're at. That said, this is the sort of thing which can definitely be improved over time.

These days it's probably possible to use a buffer in the asmjs/WASM side and generate the image data there, only exporting back to the JS side after the job is complete. That should significantly cut down on the overhead.
You need to look at serialization overhead for exchanging data. For example, I don't think web assembly has direct access to JavaScript strings? What about JSON?

Seems like you're either converting a lot of strings (which wastes memory) or calling lots of JavaScript string methods from web assembly, which is not likely to be fast in an inner loop.

To be clear, I haven't done anything serious in WASM that would hit any limits here.
I guess it will depend heavily on the type of your exchanged parameters. If it's a few integers then it's no problem since both JS and the WASM side can easily read those.

However for complex objects (like Javascript objects, strings or DOM objects) objects you need a serialization mechanism for those. That might be similar to what typical system call implementations do. However system calls mostly have a very simply set of parameters, so transferring Javascript objects might be far worse. If you would want to share Javascript objects on both sides you would also need some kind of reference-counted handles, which can identify the objects.

I haven't done anything with WASM yet, but I'm pretty sure the domains you mentioned (promises, asynchronous programming and also DOM handling) are the ones which will least likely benefit from WASM. Lower level math algorithms might however benefit a lot.

I think the real issue is the lack of DOM access rather than binding to JS.
Isn't the point of the whole architecture that from a security perspective all IO will always be through JavaScript.

Replicating the attack surface of the browser in JavaScript land in WebAssembly land goes against the whole design of it.

It's for the community to make nice libraries that expose the browser features to WebAssembly land in JavaScript. It's also the right place to deal with cross browser differences.

Well the IO is ultimately handled/sandboxed by the browser not by JavaScript so as far as security is concerned JavaScript and WASM should have the same access to IO/Web APIs. I think the attack surface you are talking about is really a implementation detail and browsers could use a common middleware that both JavaScript and WASM can use.

In a distant future I would see JavaScript actually compiled to WASM(maybe the browser would pipe it directly into a WASM compiler before to execute it) to reduce the maintenance costs and perhaps also the attack surface you are talking about.

The whole point of WASM was to cut off the middle man (i.e. JavaScript) so that we can reach native-like performance. WASM should be the ultimate dominator not JavaScript.

>> It's for the community to make nice libraries that expose the browser features to WebAssembly land in JavaScript. It's also the right place to deal with cross browser differences.

I believe the community could make nice libraries compiled to WASM that anyone can use regardless of the programming language. JavaScript would be just another language(albeit a popular one, at least due legacy reasons).

>I believe the community could make nice libraries compiled to WASM that anyone can use regardless of the programming language. JavaScript would be just another language(albeit a popular one, at least due legacy reasons).

I understand and respect the aim -- the browser should be ambivalent about programming languages.

But this is not intention, because it is quite unfeasable. WebAssembly allows one to target the web with much more low-level languages, but that also means that the languages dictate the memory structure of things. In WebAssembly world there are no 'javascript arrays' or 'object hashmaps'.

Imagine mapping the Javascript DOM API surface (with all its dynamic datastructures and callbacks) to C++, Haskell and Smalltalk. Three languages that may compile to WebAssembly, but would have drastically different internal datastructures. And all of that data marshalling that you would need to do, would need to happen for every dom feature for every language that compiles to WebAssembly.

OR! We just implement an API that does nothing more than interop with JS land. This doesn't change often and it will be easy to support many different languages quickly.

Think of Javascript as the BASH of the web. In a shell script you would pipe the output of one written-in-c program to the input of a written-in-rust program. With HTML+JS you would hookup the heavy part of the application and plug the IO's exactly how you want them. Its closer to configuration, really, much like a shell script.

So there needs to be some glue language, and we need to support Javascript and its DOM operations in a way that is completely backwards compatible, and at least as fast (read: tighly coupled) as it is now. And we want to limit the attack surface. There is no other choice than that Javascript will be that glue language.

But its fitting, because Javascript like BASH is a language whose strongest competitive advantage is compatibility. Like BASH it will be the glue language and shell of a platform.

The web APIs are described using the Web IDL and I believe that could be translated to C++ , Haskell and pretty much any language with more or less effort. In fact I think there are bindings for some languages such Python and Objective C though they are not open. I see no reason why a WASM interface could not be exposed (the code itself could be developed in C/C++ and compiled to WASM)for the web APIs and exposed to the client.

https://developer.apple.com/library/content/documentation/Co...

https://www.gnu.org/software/pythonwebkit/

Supposedly they are adding things like polymorphic inline cache, garbage collection, threads, etc, that would make it more like a VM. Perhaps enough that Python, PHP, Ruby, or similar languages could run in WASM without downloading the whole runtime. That plus native DOM access might make the front end web as diverse as the back end web.

I'm curious whether the fragmentation that would bring on is a net add, or a net drain on the web as a whole.

I wouldn't say that fragmentation on the backend is a net drain as a whole...
What do you mean by 'first class support' of WASM in C/C++? Is it somehow possible to produce wasm binaries without utilizing emscripten?
Yes, llvm has built in wasm support for a while now.
The plan for emscripten is actually to replace its own wasm compiler with LLVM, and possibly drop its asm.js compiler in favor of running wasm2asm on LLVM's wasm output: https://github.com/kripken/emscripten/issues/5827

Aside from keeping emscripten's code smaller / more maintainable and allowing the team to focus more on its role as high-level tooling, this should improve the size and performance of emscripten output since IIRC it's currently missing out on a lot of optimization opportunity by producing wasm as transpiled asm.js.

> IIRC it's currently missing out on a lot of optimization opportunity by producing wasm as transpiled asm.js.

That's actually not true: the asm.js => wasm path emits better code (smaller, faster) than the wasm backend path currently.

However, the wasm backend path is being improved, and should eventually get to parity.

Ah okay, interesting. Is it because wasm doesn't yet add any new functionality over asm.js that using asm.js as an intermediary step isn't inherently worse?

In that case, it sounds like the LLVM backend will only yield clear user-facing benefits when new features like pthreads are introduced?

Well, the "asm.js to wasm" path actually isn't pure asm.js anymore. We added i64 support and other things a while back, as intrinsics. So the asm2wasm path isn't limited by asm.js. It's weird ;) but it produces good code...

The wasm backend does have other benefits, which is why we'd like to move emscripten to use it by default:

* It uses LLVM's default legalization code, so it can handle LLVM IR from more sources (i.e. not just C and C++ from clang).

* We can stop maintaining the out-of-tree LLVM that asm2wasm depends on.

The LLVM wasm backend isn't ready yet (larger output code, slower compile times, a few missing features) but it's getting there.

Incidentally, that's how this target works in Rust; we also have an emscripten-based target.