WebAssembly Support for OCaml: Introducing Wasm_of_Ocaml

by Isabella Leandersson on Nov 1st, 2023

OCaml is constantly evolving. Developers collaborate to bring support for new features, improve workflows, and resolve pain points. To this end, the OCaml-Wasm GitHub organisation was recently established. Its goal is to bring WebAssembly support to OCaml.

WebAssembly, more commonly known as Wasm, is a low-level virtual machine that is both language- and platform-independent. In essence, Wasm is a binary format designed as a portable compilation target for programming languages. It enables deployment on a variety of platforms like web browsers, cloud, blockchain, and mobile.

Wasm makes no assumptions about language features or operations. As a result, Wasm is technically compatible with any programming language since its code can be interpreted as virtual hardware.

Why WebAssembly

You might be wondering why you should care about Wasm support in OCaml. Well, Wasm has several advantages that make it popular with developers and organisations all over the world. Briefly, they are:

  • Security: Wasm has a fully formalised type system and semantics. Wasm engines validate (type check) code and execute it in a memory-safe, isolated environment known as a sandbox. Wasm code performs predictably, with no crashes or unexpected actions, and within restrictions that limit access to the user's local resources.
  • Speed: Wasm can take advantage of language implementation techniques like just-in-time (JIT) and ahead-of-time (AOT) compilation, alongside other capabilities common to contemporary hardware. It allows Wasm code to perform at near-native code levels of performance.
  • Openness: Wasm is an open standard, meaning that it and all its documentation are openly and freely accessible to developers. Anyone can influence the evolution of Wasm by participating in the W3C Community Group.
  • Language Neutrality: As previously mentioned Wasm works by abstracting hardware and doesn't make any assumptions about language features. It makes Wasm language-neutral, meaning it does not privilege any language, programming, or object model above another.
  • Platform Independence: Wasm can be built and deployed on different platforms regardless of the OS, hardware, or programming language as long as the Wasm virtual machine is supported.
  • Browser Support: Wasm is supported by all major browsers including Chrome, Mozilla Firefox, and Safari.

Who is Using Wasm?

Currently, several companies and organisations use Wasm. For example, the cross-platform game engine Unity is using Wasm to reduce code size, manage memory, and improve load times. Fastly also uses Wasm. Fastly is a company that offers numerous Network Services for their Compute@Edge platform. Figma, an online collaborative design platform, also uses Wasm to cut their loading times. These are just a few examples of how Wasm is being used to great effect, illustrating the potential and desirability of Wasm.

Future Features

The current Wasm core specification, whilst very useful for performance-critical tasks deployed on the cloud, is still quite simplistic. Users need to go through JavaScript to manipulate the DOM and also need to explicitly keep track of pointers to JavaScript values. Consequently, it is currently not feasible to write large web applications in Wasm.

That is all about to change as there are multiple proposals to bring new features to Wasm. The most relevant to OCaml is the Garbage Collection proposal which will provide heap-allocated data structures that are garbage collected and can directly contain references to foreign values. It is being implemented together with the typed function references proposal. They are expected to ship in November on both Chrome and Firefox. Another proposal includes support for tail calls. These forward-looking features will make Wasm applicable for an even wider range of uses.

WebAssembly and OCaml

With all these benefits and future potential, it's not hard to see why the community is eager to see support for Wasm in OCaml. Using Wasm as a compilation target will allow for faster web performance (in comparison to JavaScript) as well as potentially unlocking new platforms on which to run OCaml. The OCaml-Wasm organisation is bringing previous efforts together to collaborate on implementing WebAssembly for OCaml.

There are two main prongs of the effort at the moment. One is wasocaml, an experimental compiler backend that targets Wasm using the Flambda intermediate representation of the OCaml compiler. Engineers at OCamlPro are behind this approach and you can check out the repo here.

The other approach uses a toolchain to compile OCaml to Wasm based on the tried-and-tested js_of_ocaml method. Called wasm_of_ocaml, this toolchain takes OCaml bytecode as input and emits Wasm.

It is relevant to mention two other methods created to run OCaml programs using Wasm runtimes. These methods are appropriate for use cases where the speed of generated code is less of a concern, and differ from wasocaml and wasm_of_ocaml by being mainly intended for server-side applications. Both ocamlrun-wasm and wasicaml are ports of the OCaml bytecode interpreter to Wasm. Wasicaml also has a compiler mode that parses bytecode executable and translates it to Wasm in a similar way to wasm_of_ocaml, but simpler.

Since wasm_of_ocaml was and continues to be developed mainly by Tarides engineers, this article will focus on this tool. To get more information about wasocaml, visit OCamlPro's blog.

Wasm_of_OCaml

As previously mentioned, wasm_of_ocaml is designed to use OCaml bytecode as its input to emit Wasm code. It uses the same approach as the popular js_of_ocaml, which in turn compiles OCaml bytecode to JavaScript. wasm_of_ocaml also aims to make it possible to compile programs made for js_of_ocaml in wasm_of_ocaml with minimal changes. Both js_of_ocaml and wasm_of_ocaml are the brainchildren of Jérôme Vouillon, currently a principal software engineer at Tarides.

Recently, there have been significant strides towards implementing runtime bindings in wasm_of_ocaml. The toolchain can now compile ocamlc into Wasm and run the Bonsai tests and examples. The first benchmarks are encouraging, with compiled programs typically running an average of 30% faster than their js_of_ocaml equivalents.

With a large part of the OCaml runtime already implemented, there are several additional PRs in the works to get Wasm supported in dune, gen_js_api, and Brr. On the whole, wasm_of_ocaml is getting impressively close to completion thanks to the sustained efforts of Jérôme.

The process is not entirely without challenges, and some adaptations have had to be made for OCaml and Wasm to be compatible. For example, although wasm_of_ocaml builds on the Js_of_ocaml compiler to target Wasm, it still needed some extra adjustments regarding closures. JavaScript supports closures whereas Wasm doesn't, so wasm_of_ocaml adds a closure conversion phase to eliminate closures and instead target Wasm's closed functions.

There is also the need to consider support for effects, a feature new to OCaml since the OCaml 5 release. Algebraic effects, which permit non-local control flow in a program and are useful for implementing concurrency, are supported in js_of_ocaml through a static analysis guided selective Continuation-Passing Style (CPS) transformation. Wasm_of_ocaml supports effect handlers in two ways, one of which is via a CPS transformation like in js_of_ocaml. A CPS transformation introduces overhead however, and the feature is opt-in only. The second way is through the Javascript Promise Integration proposal, which introduces less overhead than the CPS transformation at the cost of running another extension. Interestingly, a paper proposing support for effect handlers in Wasm and a stack switching proposal present other paths to addressing effect handlers in Wasm.

Next Steps & Feedback

It is incredibly helpful for the team to get feedback from people who try wasm_of_ocaml. You can contribute to the effort on the repo, which also has instructions for how to install and use the toolchain.

Don't hesitate to contact us if you have any questions or comments. The Discuss Forum is another great place to ask questions or share your thoughts. We look forward to seeing you around the OCaml community!