Skip to main content

Endive 1.1.0: Native Speed, Signed Modules, and the End of Summer

· 5 min read
Andrea Peruffo
Principal Software Engineer @ IBM

The evenings are getting shorter here, which is usually when we take stock of a summer's work. Endive 1.1.0 is out, the first feature release since Endive 1.0, and two things in it are genuinely new. redline compiles your Wasm module all the way down to native machine code. inlay gets that module into your build with a locked digest and a verified signature. Behind them sits a long, quiet list of refinements to conformance, error handling and concurrency.

redline: Native Speed, Zero Native Dependencies

redline compiles your Wasm module to native machine code with Cranelift instead of to JVM bytecode. It started life as a separate prototype and now lives in the Endive tree, cleaned up and harmonized with the rest of the project.

Here is how it works. Cranelift is written in Rust, and Rust compiles to Wasm, so we compile Cranelift itself to a .wasm module and run it on Endive at build time. Your module goes in, native code for six platforms comes out (Linux, macOS and Windows, each on x86_64 and aarch64), and it is bundled into your jar as a resource. At runtime the right one is picked and called through Panama FFM on Java 25 or later, or through jffi on Java 11 or later. There is no JNI, no native toolchain to install, and no platform specific artifact for you to publish.

The reason to reach for it is speed. On real modules like SQLite and the Prism Ruby parser we measured several times the throughput of the bytecode compiler, with the largest gains on compute heavy code. Those numbers, and how we arrived at them, are in the original introduction.

Enable it on the compiler plugin and add a runner:

<configuration>
<name>org.acme.wasm.MyModule</name>
<wasmFile>src/main/resources/my.wasm</wasmFile>
<redlineExperimental>true</redlineExperimental>
</configuration>
<dependency>
<groupId>run.endive</groupId>
<artifactId>redline-runner-experimental</artifactId>
<version>${endive.version}</version>
</dependency>

This is the first release of an entirely new compiler. It handles the use cases we set out to cover, the core specification along with bulk memory, tail calls, threads and atomics, and reference type instructions, and there is more ground ahead before it is on par with the rest of the project: newer proposals such as GC, exception handling and SIMD are still to come, and the API is experimental while we collect feedback from early adopters. That gap has been closing fast, and every week of this summer moved it a little further.

Bytecode is always generated alongside the native code and takes over wherever native code is not available, so your module runs on any platform. The documentation has the feature matrix, the supported platforms, and the handful of details worth reading before you turn it on.

inlay: Wasm Dependencies, Supply Chain Security Included

Running Wasm on the JVM is a solved problem. Getting the right .wasm file into your build reliably was not. Across our own projects we had tried committing binaries to git, downloading tarballs from releases, and building from source on every CI run. All of them work until they do not, and none of them offer integrity checking.

inlay is a Maven plugin that fetches Wasm modules from OCI registries, which is where the Wasm ecosystem has converged. It writes a wkg.lock file in the Bytecode Alliance wkg format, pinning every module by digest, so every developer and CI node builds from the exact same bytes. It verifies sigstore signatures inline after each fetch, and fails the build when the identity does not match. It caches by digest in ~/.cache/inlay/, so mvn clean does not cost you a download.

<module>
<imageRef>ghcr.io/roastedroot/sqlite4j-wasm:3.51.0</imageRef>
<outputFile>${project.build.directory}/wasm/libsqlite3.wasm</outputFile>
<sigstoreIssuer>https://token.actions.githubusercontent.com</sigstoreIssuer>
<sigstoreIdentity>https://github.com/roastedroot/*</sigstoreIdentity>
</module>

It binds to generate-sources, so it composes with the Endive compiler plugin: mvn compile fetches the module and compiles it, and there is nothing else in the pipeline.

The wkg.lock format is defined by a Rust crate, so rather than reimplement the parser we compiled that crate to Wasm and run it on Endive, the same way we run the Cranelift bridge and wasm-tools. Endive itself now uses inlay to fetch wasm-tools for its own build, so the plugin is already carrying its share of the load.

The Unglamorous Half

The rest of the release went into the kind of work that never makes a headline. Conformance moved closer to the specification across the parser, the validator and the compiler, so more modules behave exactly as their toolchain intended. Failures became more predictable, arriving as exceptions a host can catch and act on regardless of how the JVM was started. Concurrency got its share too, in the atomics behind the threads proposal and in how little memory instantiation now allocates, which counts most when many instances are live at once. None of it asks anything of you, it just means fewer surprises in the places you would rather not think about. The release notes have the individual commits.

Thanks

This release is the work of a lot of people who are not us, and much of it arrived as pull requests from the community, complete with regression tests. Thank you to everyone who shipped code, filed an issue with a reproducer, tested a snapshot, or fixed a link in the docs. The adopters list keeps growing, and it is the clearest sign that this is solving real problems.

Documentation | GitHub

Summer is closing, the pace is not. Enjoy the last of the long evenings, and tell us what you are building. Join the conversation on Zulip.