Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion docs/docs/advanced/cpu-limits.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var thread = new Thread() {
}
};
thread.start();
Thread.sleep(200);
thread.join(200);
thread.interrupt();
```

Expand All @@ -67,6 +67,7 @@ var future = service.submit(() -> function.apply());
try {
future.get(100, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
future.cancel(true);
// handle the failure
}
```
Expand Down
8 changes: 4 additions & 4 deletions docs/docs/advanced/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ title: Logging
---
# Logging

For maximum compatibility and to avoid external dependencies we use, by default, the JDK Platform Logging (JEP 264).
You can configure it by providing a `logging.properties` using the `java.util.logging.config.file` property and [here](https://docs.oracle.com/cd/E57471_01/bigData.100/data_processing_bdd/src/rdp_logging_config.html) you can find the possible configurations.
For maximum compatibility and to avoid external dependencies we use, by default, the JDK Platform Logging ([JEP 264](https://openjdk.org/jeps/264)).
The Platform Logging falls back to the [`java.util.logging` API](https://docs.oracle.com/en/java/javase/21/core/java-logging-overview.html) by default.
Comment thread
andreaTP marked this conversation as resolved.

For more advanced configuration scenarios we encourage you to provide an alternative, compatible, adapter:

- [slf4j](https://www.slf4j.org/manual.html#jep264)
- [log4j2](https://logging.apache.org/log4j/2.x/log4j-jpl.html)
- [SLF4J](https://www.slf4j.org/manual.html#jep264)
- [Log4j2](https://logging.apache.org/log4j/2.x/log4j-jpl.html)

It's also possible to provide a custom `run.endive.log.Logger` implementation if JDK Platform Logging is not available or doesn't fit.

Expand Down
6 changes: 5 additions & 1 deletion docs/docs/advanced/memory-customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ var instance = Instance.builder(module).withMemoryFactory(limits -> {
}).build();
```

> **NOTE:** Since Endive 1.1.0, an optimized memory implementation called `ByteArrayMemory` is also available. We recommend plugging this implementation on all recent OpenJDK systems for enhanced performance. On different Java runtimes (in particular, on Android VMs) you should stick to `ByteBufferMemory`.
:::note
Endive provides two built-in Memory implementations:
- `ByteArrayMemory`: An optimized memory implementation, recommended for recent OpenJDK systems
- `ByteBufferMemory`: Recommended for different Java runtimes (in particular, on Android VMs)
:::

<!--
```java
Expand Down
12 changes: 8 additions & 4 deletions docs/docs/advanced/simd.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
---
sidebar_position: 2
sidebar_label: Simd
title: Simd support
sidebar_label: SIMD
title: SIMD support
---

> **NOTE:** SIMD support is available only for Java 21+ and interpreter mode
:::info[Availability]
SIMD support is available only for Java 21+ and interpreter mode.
:::

If you are using a version of Java that supports [JEP 448 - Vector API](https://openjdk.org/jeps/448) you can leverage [Vector instructions](https://webassembly.github.io/spec/core/syntax/instructions.html#vector-instructions).

Expand Down Expand Up @@ -45,7 +47,9 @@ var module = Parser.parse(new File("your.wasm"));
var instance = Instance.builder(module).withMachineFactory(SimdInterpreterMachine::new).build();
```

> **_NOTE:_** SIMD support **REQUIRES** validation. Disabling validation (`WasmModule.builder().withValidation(false)`) is likely to produce incorrect results.
:::warning
SIMD support **REQUIRES** validation. Disabling validation (`WasmModule.builder().withValidation(false)`) is likely to produce incorrect results.
:::

<!--
```java
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/annotations/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ useful when you have many host functions.
@HostModule("demo")
public final class Demo {

public Demo() {};
public Demo() {}

@WasmExport
public long add(int a, int b) {
Expand Down Expand Up @@ -58,7 +58,7 @@ import run.endive.runtime.HostFunction;

// bug in JShell: https://github.com/jbangdev/jbang/issues/1854
public class Demo {
public Demo() {};
public Demo() {}

public HostFunction[] toHostFunctions() {
return new HostFunction[0];
Expand Down Expand Up @@ -108,7 +108,7 @@ This annotation generates several things, depending on the provided module:
- `ModuleExports`: Represents the Wasm module's exported functions, mapped to typed Java parameters and return values.
- `ModuleImports`: Represents the module's imported host functions and includes a convenient `toImportValues()` method to obtain ImportValues after implementing the interfaces.

You can find examples of how to use the generated code in the host-module/it folder of the repository.
You can find examples of how to use the generated code in the [`annotations/it` folder of the repository](https://github.com/bytecodealliance/endive/tree/main/annotations/it).

## Enabling the Annotation Processor

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/core/execution-modes.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ title: Execution modes
|---|---|---|---|---|---|
| **Interpreter** | 🐢 Slow | ✅ Supported | None | None - fully interpreted | Default mode; highly portable; suitable for development and environments requiring dynamic loading. |
| **Runtime Compilation** | 🐇 Fast | ✅ Supported | Requires reflection and ASM dependency | In-memory Java Bytecode | Enhanced performance; suitable when dynamic loading is needed and the usage of reflection is fine. |
| **Build time Compilation** | 🐇 Fast | ❌ Not Supported | Build-time tools(e.g., Maven or Gradle plugins) | Plain Java Bytecode | Optimal performance; no dynamic loading; ideal for production with static modules. |
| **Build time Compilation** | 🐇 Fast | ❌ Not Supported | Build-time tools (e.g., Maven or Gradle plugins) | Plain Java Bytecode | Optimal performance; no dynamic loading; ideal for production with static modules. |

## Summary

Expand Down
5 changes: 3 additions & 2 deletions docs/docs/core/host-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ We can do so by using a `Store`:

```java
import run.endive.wasm.Parser;
import run.endive.runtime.ImportValues;
import run.endive.runtime.Store;

// instantiate the store
Expand All @@ -124,4 +123,6 @@ logIt.apply();
// should print "Hello, World!" 10 times
```

> **_NOTE:_** For an easier way to write host function and interact with a wasm module, see [Annotations](../annotations/index.md).
:::tip
For an easier way to write host function and interact with a Wasm module, see [Annotations](../annotations/index.md).
:::
5 changes: 3 additions & 2 deletions docs/docs/core/memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,12 @@ import run.endive.runtime.Memory;

Memory memory = instance.memory();
String message = "Hello, World!";
int len = message.getBytes().length;
byte[] bytes = message.getBytes();
int len = bytes.length;
// allocate {len} bytes of memory, this returns a pointer to that memory
int ptr = (int) alloc.apply(len)[0];
// We can now write the message to the module's memory:
memory.writeString(ptr, message);
memory.write(ptr, bytes);
Comment thread
andreaTP marked this conversation as resolved.
```

Now we can call `countVowels` with this pointer to the string.
Expand Down
11 changes: 7 additions & 4 deletions docs/docs/examples/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ Compiling a Rust library to Wasm is easy and can be performed using standard `ru
rustc --target=wasm32-unknown-unknown --crate-type=cdylib
```

when you need to add support for wasi preview 1(typically when using CLIs) you can use:
when you need to add support for WASI preview 1 (typically when using CLIs) you can use:

```bash
rustc --target=wasm32-wasi --crate-type=bin
```

> **NOTE:** For production usage, make sure to produce an optimized Wasm module by using the standard compiler options `-C opt-level = 3`(speed) or `-C opt-level = "z"`(size)
:::tip
For production usage, make sure to produce an optimized Wasm module by using the standard compiler options `-C opt-level = 3` (speed) or `-C opt-level = "z"` (size).
:::

## Using in Endive

Expand Down Expand Up @@ -46,10 +48,11 @@ var countVowels = instance.export("count_vowels");

var memory = instance.memory();
var message = "Hello, World!";
var len = message.getBytes().length;
byte[] bytes = message.getBytes();
int len = bytes.length;
int ptr = (int) alloc.apply(len)[0];

memory.writeString(ptr, message);
memory.write(ptr, bytes);
Comment thread
andreaTP marked this conversation as resolved.

var result = countVowels.apply(ptr, len)[0];
System.out.println(result);
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/execution/build-time-compiler.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ The build time compiler has several advantages over the [Runtime Compiler](runti

- improved instance initialization time: the translation occurs at build time
- no reflection needed: easier to use with `native-image`
- fewer runtime dependencies: asm is only needed at build time
- fewer runtime dependencies: ASM is only needed at build time
- distribute Wasm modules as self-contained jars: making it a convenient way to distribute software that was not originally meant to run on the Java platform

You can use the compiler at build-time via Maven plug-in, Gradle plug-in, or plain CLI
You can use the compiler at build-time via Maven plug-in, Gradle plug-in, or plain CLI.

### Interpreter Fall Back

Expand All @@ -35,7 +35,7 @@ Since interpreted functions have worse performance, we want to make sure you are
WASM function size exceeds the Java method size limits and cannot be compiled to Java bytecode. It can only be run in the interpreter. Either reduce the size of the function or enable the interpreter fallback mode: WASM function index: 3938
```

If this happens you can configure your build tool, to just issue warning messages, or to be silent. Another way to silence the message is to configure the build too with an explicit list of functions that should be interpreted. Typically, you obtain the list of the functions by running the compiler once with `interpreterFallback` set to `WARN`
If this happens you can configure your build tool, to just issue warning messages, or to be silent. Another way to silence the message is to configure the build tool with an explicit list of functions that should be interpreted. Typically, you obtain the list of the functions by running the compiler once with `interpreterFallback` set to `WARN`

## Using Maven

Expand Down
12 changes: 6 additions & 6 deletions docs/docs/execution/compiler-cache.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ title: Runtime Compiler Cache

# Overview of the Runtime Compiler Cache

:::warning[Security Consideration]
The directory cache stores compiled bytecode on disk without integrity verification. Ensure the cache directory has restrictive permissions (`chmod 700`) and is not writable by untrusted users. Do not share caches across trust boundaries.
:::

Comment thread
andreaTP marked this conversation as resolved.
The runtime compiler cache lets the Endive runtime compiler store the results of compiling WASM modules to Java bytecode. Subsequent executions can skip compilation and start faster.

Use the experimental directory-based cache, or implement the simple `run.endive.compiler.Cache` interface:
Expand All @@ -25,8 +21,12 @@ The compiler uses the module digest (default SHA-256) as the cache key. For exam

## The Directory Cache

:::warning[Security Consideration]
The directory cache stores compiled bytecode on disk without integrity verification. Ensure the cache directory has restrictive permissions (`chmod 700`) and is not writable by untrusted users. Do not share caches across trust boundaries.
:::

The directory cache stores entries as files under a configured directory. For example,
ff the cache directory is `/cache`, and you store the following cache key:
if the cache directory is `/cache`, and you store the following cache key:

`sha-256:KRgyTkCm43c34ksqtA8gmdDw4YCfquC2G0qfIFCpb+w=`

Expand All @@ -38,7 +38,7 @@ It transforms the key to:
* translate characters to be file-system-friendly
* use a two-character subdirectory prefix to avoid directory scaling issues

The implementation uses file system atomic moves (write to a temp file, then move to the final location). This makes the cache thread safe and safe to share across processes and avoids partial-write failures. Temp files are written under `/cache/.tmp`. Partially written temp files may be left after a crash; there is no automatic cleanup or eviction. The cache size is not limiteddelete files manually to free disk space.
The implementation uses file system atomic moves (write to a temp file, then move to the final location). This makes the cache thread-safe and safe to share across processes and avoids partial-write failures. Temp files are written under `/cache/.tmp`. Partially written temp files may be left after a crash; there is no automatic cleanup or eviction. The cache size is not limiteddelete files manually to free disk space.

### Using the Directory Cache

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/execution/runtime-compiler.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Add the following dependency:

### Code Changes

You enable the runtime compiler by configuring the instance to use `CompilerMachine::new` as the machine factory instead
You enable the runtime compiler by configuring the instance to use `MachineFactoryCompiler::compile` as the machine factory instead
of the default `InterpreterMachine`.

<!--
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/experimental/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The experimental CLI uses `inheritSystem()` by default, granting the Wasm module
The experimental Endive CLI is available for download on Maven at the link:

```
https://repo1.maven.org/maven2/run/endive/cli/<version>/cli-<version>.sh
https://repo1.maven.org/maven2/run/endive/cli-experimental/<version>/cli-experimental-<version>.sh
```

you can download the latest version and use it locally by typing:
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/experimental/why.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ title: Why

Endive is a young project and we acknowledge that we are exploring and spearheading in many aspects the usage of Web Assembly on the JVM.

Since there is(always) some degree of experimentation going on, and we want to have feedback by the community and early users, we decide to publish also `experimental` modules; everyone is welcome to try things out and report back the experience.
Since there is (always) some degree of experimentation going on, and we want to have feedback by the community and early users, we decide to publish also `experimental` modules; everyone is welcome to try things out and report back the experience.

Please note that if "something works" for you, its very unlikely that it will be removed completely, in most cases, expect slight public API changes or module renames to happen.

Expand Down
4 changes: 3 additions & 1 deletion docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,6 @@ docs.FileOps.writeResult("docs", "index.md.result", "" + result);
```
-->

> *Note*: Functions in Wasm can return multiple values, hence the array. This function only returns one value, so we take the first value.
:::note
Functions in Wasm can return multiple values, hence the array. This function only returns one value, so we take the first value.
:::
10 changes: 5 additions & 5 deletions docs/docs/security/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ HostFunction readMemory = (Instance instance, long... args) -> {

// Validate bounds BEFORE accessing memory
var memory = instance.memory();
if (offset < 0 || length < 0 || offset + length > memory.pages() * 65536) {
if (offset < 0 || length < 0 || Math.addExact(offset, length) > memory.pages() * 65536) {
Comment thread
andreaTP marked this conversation as resolved.
throw new TrapException("out of bounds memory access");
}

Expand All @@ -33,7 +33,7 @@ HostFunction readMemory = (Instance instance, long... args) -> {

**Key rules:**
- Validate all memory offsets and lengths before reading/writing
- Never use Wasm-provided values as array indices without bounds checking
- Never use Wasm-provided values as array indices without bounds checking; keep overflow in mind or use overflow-safe methods such as `Math#addExact` or `Objects#checkFromIndexSize`
- Be cautious with string decoding — enforce maximum lengths
- Avoid exposing file paths, SQL queries, or shell commands derived from Wasm input

Expand All @@ -47,8 +47,8 @@ WASI file access does not enforce path sandboxing by default. Passing the host f

```java title="Example"
var options = WasiOptions.builder()
// Use ZeroFS to restrict access to specific directories
.withDirectory("/guest/data", Path.of("/host/sandboxed/data"))
// Use ZeroFs to restrict access to specific directories
.withDirectory("/guest/data", zeroFs.getPath("/host/sandboxed/data"))
Comment thread
andreaTP marked this conversation as resolved.
.withStdout(myStdout)
.withStderr(myStderr)
.build();
Expand Down Expand Up @@ -80,7 +80,7 @@ See [CPU Limits](/docs/advanced/cpu-limits) for more patterns.
The runtime and build-time compilers translate Wasm to JVM bytecode for performance. When running untrusted modules:

- **Prefer the interpreter** for maximum sandbox assurance — it doesn't generate JVM bytecode
- **Protect compiler cache directories** with restrictive permissions (`chmod 700`) if using the directory cache
- **Protect compiler cache directories** with restrictive permissions (`chmod 700`) if using the [directory cache](/docs/execution/compiler-cache/#the-directory-cache)
- **Set JVM heap limits** when compiling large untrusted modules to prevent resource exhaustion

## Dependency Supply Chain
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/security/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ The critical trust boundary is between **Wasm guest code** and **host functions*
- **CPU limits**: Wasm modules can execute infinite loops. The host must enforce timeouts (see [CPU Limits](/docs/advanced/cpu-limits)).
- **Memory growth limits**: Modules can request memory growth up to the declared maximum. The host should set appropriate limits.
- **Post-compilation verification**: The build-time and runtime compilers translate Wasm to JVM bytecode without a separate verification pass. For maximum assurance with untrusted code, prefer the interpreter.
- **Cache integrity**: The directory-based compiler cache does not verify bytecode integrity on load. Protect cache directories with restrictive permissions.
- **Cache integrity**: The [directory-based compiler cache](/docs/execution/compiler-cache/#the-directory-cache) does not verify bytecode integrity on load. Protect cache directories with restrictive permissions.

## WASI and Capability-Based Security

When using WASI, the host controls what capabilities the guest receives:

- **Filesystem access** is opt-in. Use a virtual filesystem (e.g., ZeroFS) to restrict access to specific directories.
- **Filesystem access** is opt-in. Use a virtual filesystem (e.g., [ZeroFs](https://github.com/roastedroot/zerofs)) to restrict access to specific directories.
- **Environment variables** and **command-line arguments** are explicitly passed by the host.
- **Standard I/O** streams are host-controlled.

Expand Down
Loading
Loading