Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions docs/blog/2026-10-30-endive-1.2.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
---
slug: endive-1.2.0
title: 'Endive 1.2.0: SIMD in the Interpreter, GC-Friendly Native Memory, and Components on the Horizon'
authors: [andreaTP]
tags: [wasm, endive, release, redline]
---

**Endive 1.2.0** is out. Modules that use SIMD now run in the interpreter on any Java from 11 up, with
nothing to add or configure. `redline` releases native memory once the Java objects using it become
unreachable, so closing an instance is optional. Atomics behave the same across memory implementations
and no longer collapse on JDK 25. And next door, Component Model support is taking shape.

<!-- truncate -->

## SIMD in the Interpreter, from Java 11 Up

All 236 instructions of the SIMD proposal are now part of the core interpreter: no extra module, no JVM
flag, no machine factory to wire. The implementation is plain Java with no dependency on the incubating
Vector API, so one jar behaves identically on every JDK, and it passes the WebAssembly SIMD
specification tests.

We measured libsodium and OpenSSL, each built with and without SIMD: wherever the C compiler vectorised
a kernel, the SIMD build runs faster in the interpreter, because there are fewer instructions to
dispatch. The plain Java implementation also keeps pace with one built on the Vector API, which is why
it is the only one we ship. The numbers are in the
[pull request](https://github.com/bytecodealliance/endive/pull/205).

The bytecode compilers and `redline` don't support SIMD yet: compiling a module that uses it fails, so
such modules need the interpreter for now. Compiler support is next. SIMD execution relies on
validation, so keep it enabled for modules that use `v128`.

Upgrading from `run.endive:simd`? Drop the dependency and the
`withMachineFactory(SimdInterpreterMachine::new)` call.

## `redline`: GC-Friendly Native Memory

[`redline`](/docs/experimental/redline) compiles your Wasm module to native code with
[Cranelift](https://cranelift.dev/) at build time and runs it through Panama FFM or jffi.

- **Native memory follows its Java objects.** Code, linear memories, tables and globals live off-heap,
and are released once the Java objects that use them become unreachable. `close()` is optional. The
collector can't see off-heap bytes, so `redline` requests a collection as its native footprint grows.
The [documentation](/docs/experimental/redline#native-memory) covers the threshold and how it
interacts with your GC flags. In the measurement that accompanies the change, 200 instances of a
Javy module that were never closed were all reclaimed, at the same peak memory as closing each one.
- **No compiler at runtime.** The trampolines between Java and native code are generated at build time
with the rest of the module. The runners only load and link precompiled code, and Cranelift is not
one of their dependencies.
- **One watchdog.** `Thread.interrupt()` reaches running native code through a single watchdog thread
shared by every instance.
- **`call_indirect` across instances.** A function placed in a table by one instance and called
through `call_indirect` by another now runs with its own memory, globals and tables. This is how
`wit-component` lays out every component with imports: a shim module calls the host through a table
that a separate fixup module fills. Host reads and writes of a native memory also got cheaper, as the
memory layouts are built once.
- **Correctness.** Memory growth seen across instances and host imports, host-side atomics,
`wait`/`notify`, and traps raised by the runner got a round of fixes in both runners, with new tests.

[CPython compiled to Wasm](https://github.com/trinodb/trino-wasm-python) is one of the modules we
exercised it on.

### Before you upgrade

- The native code format is now version 5. Recompile modules built with an earlier version.
- `close()` stops an instance and frees nothing: the garbage collector reclaims the memory.
`-XX:+DisableExplicitGC` turns off the collections `redline` requests.
- `redline-runner-jffi-experimental` no longer brings in jffi, so its version can follow the rest of
your application. Add `com.github.jnr:jffi` and its `native` classifier next to the runner.
- Instances nested through host imports on one thread share one stack budget, and `withMemoryLimits`
rejects limits that would change whether a memory is shared.
- Like any `Instance`, a native instance is not thread-safe: use it from one thread at a time
([#211](https://github.com/bytecodealliance/endive/issues/211)).
- Modules using exception handling: an `exnref` is now a `WasmException` object. `apply()` throws on
exnref signatures, use `applyWithRefs()`; `Instance.exn()` and `registerException()` are deprecated
and throw; and build-time compiled output from 1.1.0 must be regenerated.

## Atomics and Heap

- **JDK 25.** `ByteArrayMemory` asked the JVM on every atomic load and store whether it supports volatile
access on array views. On JDK 21 the answer is cheap; on JDK 25 it is `false` and expensive, enough to
make the multi-threaded sieve benchmark run two orders of magnitude slower than on JDK 21. The answer
is now resolved once. Wide atomics on `ByteArrayMemory` still take a lock on JDK 25, since its array
views no longer support them lock-free.
- **Uniform atomics.** In both memory implementations, atomics work on shared and non-shared memories
alike, and overlapping accesses of different widths exclude each other. When hardware atomics aren't
available, the fallback takes one of a fixed set of striped locks, with no allocation per operation.
- **Leaner compiled modules.** After compiling, the parsed bodies of compiled functions are only useful
to the interpreter; in a server holding many modules they were most of the retained heap.
`MachineFactoryCompiler.Builder.compileModule()` returns a `CompiledModule` that keeps only the
bodies the interpreter may still run, so the rest can be garbage collected. `compile()` is unchanged,
and nothing is dropped when the reachable set can't be determined or the result comes from the cache.

```java
var compiled = MachineFactoryCompiler.builder(module).compileModule();
var instance = Instance.builder(compiled).build();
```

## Conformance

Exception handling (`exnref`, `throw_ref`, `catch_ref`), tail calls, and the interpreter's `v128` locals
and store address computation all moved closer to the specification. The
[release notes](https://github.com/bytecodealliance/endive/releases/tag/1.2.0) list every change.

## On the Horizon

**Component Model.** Support is taking shape in [endive-cm](https://github.com/roastedroot/endive-cm),
a companion repository built on Endive: the component type model, a binary parser, Canonical ABI
lifting and lowering, a `bindgen` annotation processor that turns WIT into Java, component
instantiation and linking, and WASI 0.2 host implementations of `wasi:io`, `wasi:clocks`, `wasi:cli`,
`wasi:filesystem` and `wasi:random`, with `wasi:sockets` in progress. It is tested against the official
Component Model test suite and a corpus of components built with real toolchains.

**Java 11.** We intend to drop Java 11. Supporting it costs more with every release: Jackson 3 and other
dependencies have moved on, and the build relies on forks and Maven profiles to keep up. We asked the
projects that depend on Endive, and Trino, JRuby, Apache Camel, Microcks and Confidence all run Java 17
or later. If you are on Java 11, tell us on
[#250](https://github.com/bytecodealliance/endive/issues/250): concrete use cases will shape the
transition.

## Thanks

Much of this release arrived as pull requests from the community, often from people running Endive in
production, complete with reproducers, measurements and regression tests. Thank you to everyone who
shipped code, filed an issue, tested a snapshot, or fixed a line in the docs. The
[adopters list](https://github.com/bytecodealliance/endive/blob/main/ADOPTERS.md) is the place to add
your project.

[Documentation](https://endive.run/docs/) | [GitHub](https://github.com/bytecodealliance/endive) |
[Join the conversation on Zulip](https://bytecodealliance.zulipchat.com/#narrow/stream/endive)
Loading