GraalVM Implementation of WebAssembly

GraalVM can run programs compiled to WebAssembly. It can interpret and compile WebAssembly code in the binary format or embed it into other programs. The support for WebAssembly is in the early stages of its development.

Installing Wasm #

The support is not available by default, but you can add it to GraalVM using the GraalVM Updater tool:

gu install wasm

The above command will install a community version of a component from the GitHub catalog. For GraalVM Enterprise users, the manual component installation is required.

Then wasm launcher, which can run compiled WebAssembly binary code, becomes available.

Running WebAssembly Programs #

You can run a program written in the language that compiles to WebAssembly on GraalVM. For example, put the following C program in a file named floyd.c:

#include <stdio.h>

int main() {
  int number = 1;
  int rows = 10;
  for (int i = 1; i <= rows; i++) {
    for (int j = 1; j <= i; j++) {
      printf("%d ", number);
      ++number;
    }
    printf(".\n");
  }
  return 0;
}

Compile it using the most recent Emscripten compiler frontend version. It should produce a standalone floyd.wasm file in the current working directory:

emcc -o floyd.wasm floyd.c

Then you can run the compiled WebAssembly binary on GraalVM as follows:

wasm --Builtins=wasi_snapshot_preview1 floyd.wasm

In this example, the flag --Builtins specifies builtin modules that the Emscripten toolchain requires.

Embedding WebAssembly Programs #

The compiled WebAssembly binary code can be accessed programmatically with GraalVM Polyglot API, which allows embedding GraalVM WebAssembly into user programs. Here is a simple example of how to call WebAssembly code from a Java application:

import org.graalvm.polyglot.*;
import org.graalvm.polyglot.io.ByteSequence;
//Load the WASM contents into a byte array
byte[] binary = readBytes("example.wasm");
Context.Builder contextBuilder = Context.newBuilder("wasm");
Source.Builder sourceBuilder = Source.newBuilder("wasm", ByteSequence.create(binary), "example");
Source source = sourceBuilder.build();
Context context = contextBuilder.build();

context.eval(source);

Value mainFunction = context.getBindings("wasm").getMember("main").getMember("_start");
mainFunction.execute();

For more polyglot examples, visit the Polyglot Programming page.