That's a really indirect way, and it's not clear how much efficiency is lost in the process. It's not too far from claiming that $language can be used on a microcontroller, because $language exists on Linux, and the latter can run Linux even if via extremely slow emulation: https://news.ycombinator.com/item?id=19762928
Also related: https://news.ycombinator.com/item?id=22010159
https://kripken.github.io/blog/wasm/2020/07/27/wasmboxc.html
See also here, where wasm2c is the fastest wasm runtime:
https://00f.net/2023/01/04/webassembly-benchmark-2023/
There are of course cases that can be slower, like code that depends heavily on SIMD, as wasm support for SIMD is still being improved. But in general compiling to wasm as an intermediary IR and then using an optimizing compiler can lead to very fast code.
An exception to this principle is the linker: the Rust compiler relies on an external linker, and it may happen that the standard linker for a system only runs on that system itself. This is true on modern macOS and Windows. In this case it’s impossible to cross-compile for the target normally (at least without using a nondefault linker such as LLD). But even in that case, it’s possible to separate the compile and link steps, so you could compile an object file on another system, copy the object file to the target system, and run the linker from there. That would be inconvenient but good enough for bootstrapping purposes, so a translation layer still wouldn’t really help.
For Windows targets, you can also use Wine to accomplish cross compilation from Linux with the standard linker.
"Two results are shown for WasmBoxC, representing two implementations of memory sandboxing. The first is explicit sandboxing, in which each memory load and store is explicitly verified to be within the sandboxed memory using an explicit check (that is, an if statement is done before each memory access). This has 42% overhead.
The OS-based implementation uses the “signal handler trick” that wasm VMs use. This technique reserves lots of memory around the valid range and relies on CPU hardware to give us a signal if an access is out of bounds (for more background see section 3.1.4 in Tan, 2017). That is fully safe and has the benefit of avoiding explicit bounds checks. It has just 14% overhead! However, it cannot be used everywhere (it needs signals and CPU memory protection, and only works on 64-bit systems).
There are more options in between those 14% and 42% figures. Explicit and OS-based sandboxing preserve wasm semantics perfectly, that is, a trap will happen exactly when a wasm VM would have trapped. If we are willing to relax that (but we may not want to call it wasm if we do) then we can use masking sandboxing instead (see section 3.1.3 in Tan, 2017), which is 100% portable like explicit sandboxing and also prevents any accesses outside of the sandbox, and is somewhat faster at 29% overhead. Other sandboxing improvements are possible too - almost no effort has gone into this yet."
It sounds like this last one is the most relevant to porting code to obscure platforms (which usually means embedded these days). 29% overhead for verifiably safe sandboxing is a good trade-off, but when you don't actually need that sandboxing, I wouldn't call that insignificant. Especially on hardware that's slow by modern standards to begin with.
What I'm curious about is how hard it is to build a library target via this method and how much overhead there is in calling the generated code. Maybe someone who knows WebAssembly has some idea? Do call parameters need to get turned into JSON and back? Can I pass in a pointer to writable memory?
For memory access I can only describe how it works in the browser environment with Emscripten (for lack of experience with other WASM integrations): The WASM heap is exposed as a Javascript ArrayBuffer object (or more correctly that ArrayBuffer object is the WASM heap, created on the JS side and handed to the WASM side at startup), with per-primitive-type array views (for instance for byte access there's a global "HEAPU8: Uint8Array" object on the JS side).
Since WASM currently only has 32-bit pointers, pointers can be passed safely to the Javascript side as JS 'numbers' without loss of information. This 'number pointer' can then be used as array index to read and write data in the WASM heap from the JS side.
Don't know how it works in WASM engines outside the browser, but I suppose it's similar (e.g. a shared heap between the native side and WASM), except maybe that you can also pass 64-bit integers around without data loss.
But in no case there needs to be any JSON- or Protobuf-style 'parameter serialization' involved.
This old blog post might contain some more information: https://hacks.mozilla.org/2018/10/calls-between-javascript-a...
> Coremark 1.0: ~7% slower than native [0]