Announcing the first Java library to run WebAssembly: Wasmer JNI
This is a copy of an article I wrote for Wasmer.
WebAssembly is a portable binary format. That means the same file can run anywhere.
To uphold this bold statement, each language, platform and system must be able to run WebAssembly — as fast and safely as possible.
People who are familiar with Wasmer are used to this kind of announcement! Wasmer is written in Rust, and comes with an additional native C API. But you can use it in a lot of other languages. After having announced libraries to use Wasmer, and thus WebAssembly, in:
-
Go with the
wasmer
library (see Announcing the fastest WebAssembly runtime for Go:wasmer
, and even -
Postgres with the
wasmer
library (see Announcing the first Postgres extension to run WebAssembly),
…we are jazzed to announce that Wasmer has now landed in Java!
Let’s discover the Wasmer JNI library together.
Installation
The Wasmer JNI (Java Native Interface) library is based on the Wasmer runtime, which is written in Rust, and is compiled to a shared library. For your convenience, we produce one JAR (Java Archive) per architecture and platform. By now, the following are supported, consistently tested, and pre-packaged (available in Bintray and Github Releases):
-
amd64-darwin
for macOS, x86 64bits, -
amd64-linux
for Linux, x86 64 bits, -
amd64-windows
for Windows, x86 64 bits.
More architectures and more platforms will be added in the near future. If you need a specific one, feel free to ask! However, it is possible to produce your own JAR for your own platform and architecture.
The JAR files are named as follows:
wasmer-jni-$(architecture)-$(os)-$(version).jar
. Thus, to include
Wasmer JNI as a dependency of your project (assuming you use
Gradle), write for instance:
dependencies {
implementation "org.wasmer:wasmer-jni-amd64-linux:0.2.0"
}
JAR are hosted on the Bintray/JCenter repository under the
[wasmer-jni](https://bintray.com/wasmer/wasmer-jni/wasmer-jni)
project. They are also attached to our Github releases as
assets.
Calling a WebAssembly function from Java
As usual, let’s start with a simple Rust program that we will compile to WebAssembly, and then execute from Java.
pub extern
After compilation to WebAssembly, we get a file like this
one,
named simple.wasm
.
The following Java program executes the sum
exported function by
passing 5
and 37
as arguments:
;
;
;
;
Great! We have successfully executed a Rust program, compiled to WebAssembly, in Java. As you can see, it is pretty straightforward. The API is very similar to the standard JavaScript API, or the other API we have designed for PHP, Python, Go, Ruby etc.
The assiduous reader might have noticed the [0]
in .apply(5, 37)[0]
pattern. A WebAssembly function can return zero to many values, and in
this case, we are reading the first one.
Note: Java values passed to WebAssembly exported functions are automatically downcasted to WebAssembly values. Types are inferred at runtime, and casting is done automatically. Thus, a WebAssembly function acts as any regular Java function.
Technically, an exported function is a functional interface as defined
by the Java Language Specification (i.e. it is a
[FunctionalInterface](https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html)
).
Thus, it is possible to write the following code where sum
is an
actual function (of kind org.wasmer.exports.Function
):
;
;
;
;
;
But a WebAssembly module not only exports functions, it also exports memory.
Reading the memory
A WebAssembly instance has one or more linear memories, a contiguous and
byte-addressable range of memory spanning from offset 0 and extending up
to a varying memory size, represented by the org.wasmer.Memory
class.
Let’s see how to use it. Consider the following Rust program:
pub extern
The return_hello
function returns a pointer to the statically
allocated string. The string exists in the linear memory of the
WebAssembly module. It is then possible to read it in Java:
;
;
;
;
;
;
As we can see, the Memory
API provides a buffer
method. It returns a
direct byte
buffer
(of kind java.nio.ByteBuffer
) view of the memory. It’s a standard API
for any Java developer. We think it’s best to not reinvent the wheel and
use standard API as much as possible.
The WebAssembly memory is dissociated from the JVM memory, and thus from the garbage collector.
You can read the Greet Example to see a more in-depth usage of the
Memory
API.
More documentation
The project comes with a Makefile
. The make javadoc
command will
generate a traditional local Javadoc for you, in the
build/docs/javadoc/index.html
file.
In addition, the project’s README.md
file has an API of
the wasmer
library
Section.
Finally, the project comes with a set of
examples.
Use the make run-example EXAMPLE=Simple
to run the
SimpleExample.java
example for instance.
Performance
WebAssembly aims at being safe, but also fast. Since Wasmer JNI is the first Java library to execute WebAssembly, we can’t compare to prior works in the Java ecosystem. However, you might know that Wasmer comes with 3 backends: Singlepass, Cranelift and LLVM. We’ve even written an article about it: A WebAssembly Compiler tale. The Wasmer JNI library uses the Cranelift backend for the moment, which offers the best compromise between compilation-time and execution-time.
Credits
Asami (d0iasm on Twitter) has improved this project during its internship at Wasmer under my guidance. She finished the internship before the release of the Wasmer JNI project, but she deserves credits for pushing the project forward! Good work Asami!
This is an opportunity to remind everyone that we hire anywhere in the world. Asami was working from Japan while I am working from Switzerland, and the rest of the team is from US, Spain, China etc. Feel free to contact me (@mnt_io or @syrusakbary on Twitter) if you want to join us on this big adventure!
Conclusion
Wasmer JNI is a library to execute WebAssembly directly in Java. It
embeds the WebAssembly runtime
Wasmer. The first releases provide
the core API with Module
, Instance
, and Memory
. It comes
pre-packaged as a JAR, one per architecture and per platform.
The source code is open and hosted on Github at wasmerio/java-ext-wasm. We are constantly improving the project, so if you have feedback, issues, or feature requests please open an issue in the repository, or reach us on Twitter at @wasmerio or @mnt_io.
We look forward to see what you build with this!