OCaml 5.x code using effect handlers can be compiled in two different ways: one can either enable the CPS transformation from js_of_ocaml or emit code requiring the JavaScript-Promise Integration extension.
Previously, wasm_of_ocaml also required the experimental stringref proposal to convert strings between OCaml and JavaScript. The stringref proposal may however be superseeded by the newer JS-string-builtins proposal, which is being implemented in both Chrome and Firefox. With the JavaScript string situation up in the air, for now wasm_of_ocaml instead uses the TextEncoder/TextDecoder API on the JavaScript side to convert JavaScript to or from UTF-8 by writing strings to or reading them from a buffer in Wasm linear memory as an intermediate state.
Since September @vouillon has continued extending and improving wasm_of_ocaml:
Our loops included all the code that follows, and the V8 engine used jump offsets to estimate the cost of a loop. So, it could widely overestimate the cost of loops at toplevel and produce optimised top-level code which is run only once. Since this code can be very large, this could take several minutes. Now, the code which is not involved in a loop is moved after the loop if it exceeds a size threshold.
In addition, @vouillon also contributed with a couple of broader Wasm community improvements:
Making binaryen more effective at cancelling out a boxing followed by an unboxing: WebAssembly/binaryen#5952 and
Improved the performance of Wasm exceptions in V8, the JavaScript / Wasm engine used by Chrome. After a number of optimisations, like using a cache to find which Wasm code correponds to a code pointer, they are about a order of magnitude faster. As a consequence the Boyer benchmark runs about 5 time faster.
Finally, he prepared and gave two presentations about wasm_of_ocaml:
A general wasm_of_ocaml talk at the WebAssembly Community Group meeting on October 12. In particular, he presented a number of performance measurements.
For a start wasm_of_ocaml has gone for building an almost drop-in replacement for js_of_ocaml. This lets us reuse and rely on a number of things in JavaScript (math function, string/float coersions, JS weak pointers, …) to get off the ground. For a non-web-hosted Wasm engine these will naturally have to be changed.
This biggest blocker is that none of the stand-alone “no-JS” engines support the WasmGC extension that both wasocaml and wasm_of_ocaml rely on, AFAIK.
There’s a (slightly out-of-date) extension overview available at Roadmap - WebAssembly.
If someone is aware of WasmGC progress in other such engines, please share!
That’s great news! I had the impression that one of the limitations of js_of_ocaml is the support of libraries written in C. If I understand correctly, js_of_ocaml required a stubbed version written in JavaScript to work. With a compilation from Ocaml to WebAssembly, and other existing compilers from C to WebAssembly, would this mean we could run in the browser OCaml programs relying on some external C libraries?
With a compilation from Ocaml to WebAssembly, and other existing compilers from C to WebAssembly, would this mean we could run in the browser OCaml programs relying on some external C libraries?
Thanks to recent changes in clang, I can tell it will be possible with Wasocaml without requiring any change (or almost no change ). We will provide alternative headers of the native FFI where current macros will be replaced by hand-written Wasm. The only limitation to expect is that Field won’t be usable as an l-value anymore. We’ll provide a Set_field one or equivalent.
Out of curiosity, is providing a Set_field (distinguishing direct assignment to a field from Store_field/caml_modify) because wasocaml benefits from this distinction, or just because it allows the C code to be more easily shared between wasocaml and the native C runtime?
I have not tried it but it should indeed be possible to link the code generated by Wasm_of_ocaml with a C library compiled to Wasm. You still need to write stubs to convert between OCaml values and C values.
As @zapashcanon is saying, with LLVM 17, it should be possible to reuse existing stubs written in C with minimal changes by compiling them with an alternative set of macros. We probably need some small changes in Wasm_of_ocaml as well for this to work, since LLVM only supports the reference type externref but we are using type (ref eq) for OCaml values, so some conversions have to be performed when calling the C stub functions.
@dra27 Field accesses have to be implemented by function calls, And there is no way to define a macro so that Field(x,n)=e is rewritten into set_field(x,n,e).
That’s not quite what I meant - I was wondering whether the intention was to upstream something like #define Set_field(x, n, e) Field(x, n) = e so that it could be overridden to be a function call?
If the block has not been initialized yet, it is not safe to use Store_field. When the block has been allocated with caml_alloc_small, one currently needs to perform direct assignments Field(v, n) = v. If the block has been allocated with caml_alloc_shr, one currently needs to use caml_initialize. One needs an alternative to this function as well.
@dra27 Yes, it would make a lot of change to upstream these macros for compatibility.