Skip to main content

Chicory Integration

Chicory is a zero-dependency, pure Java WebAssembly runtime.

Key Features:

  • Compatible with Android API 33+ and JVM JDK 17+.
  • Simple JVM-only runtime with minimal dependencies.
  • Supports single-threaded execution only.

This integration allows you to run WebAssembly binaries that use either WASI Preview 1 or Emscripten functions on the JVM with Chicory.

Compatible with version 1.0.0 of Chicory.

WASI Preview 1 Bindings Integration

Check WASI Preview 1 to see the limitations of the WASI P1 implementation.

Installation

Add the required dependencies:

dependencies {
implementation("at.released.weh:bindings-chicory-wasip1:0.1")
implementation("com.dylibso.chicory:runtime:1.0.0")
}

Usage

Below is an example demonstrating the execution of helloworld.wasm, build using Emscripten with the STANDALONE_WASM flag.

import at.released.weh.bindings.chicory.exception.ProcExitException
import at.released.weh.bindings.chicory.wasip1.ChicoryWasiPreview1Builder
import at.released.weh.host.EmbedderHost
import com.dylibso.chicory.runtime.HostFunction
import com.dylibso.chicory.runtime.ImportValues
import com.dylibso.chicory.runtime.Instance
import com.dylibso.chicory.wasm.Parser
import com.dylibso.chicory.wasm.WasmModule
import kotlin.system.exitProcess

fun main() {
// Create Host and run code
EmbedderHost {
fileSystem {
addPreopenedDirectory(".", "/data")
}
}.use { executeCode(it) }
}

private fun executeCode(embedderHost: EmbedderHost) {
// Prepare WASI host imports
val wasiImports: List<HostFunction> = ChicoryWasiPreview1Builder {
host = embedderHost
}.build()

val hostImports = ImportValues.builder().withFunctions(wasiImports).build()

// Instantiate the WebAssembly module
val instance = Instance
.builder(File("helloworld_wasi.wasm"))
.withImportValues(hostImports)
.withInitialize(true)
.withStart(false)
.build()

// Execute code
try {
instance.export("_start").apply()
} catch (pre: ProcExitException) {
if (pre.exitCode != 0) {
exitProcess(pre.exitCode)
}
}
}

Chicory WASI Preview 1 implementation

Chicory includes its own implementation of the WASI Preview 1 interfaces. You can find documentation on how to use it here: https://chicory.dev/docs/usage/wasi/.

Emscripten bindings integration

Installation

Add the required dependencies:

dependencies {
implementation("at.released.weh:bindings-chicory-emscripten:0.1")
implementation("com.dylibso.chicory:runtime:1.0.0")
}

Usage

Below is an example demonstrating the execution of helloworld.wasm, prepared in the "Emscripten Example".

import at.released.weh.bindings.chicory.ChicoryEmscriptenHostInstaller
import at.released.weh.bindings.chicory.ChicoryEmscriptenHostInstaller.ChicoryEmscriptenSetupFinalizer
import at.released.weh.host.EmbedderHost
import com.dylibso.chicory.runtime.HostFunction
import com.dylibso.chicory.runtime.ImportValues
import com.dylibso.chicory.runtime.Instance
import com.dylibso.chicory.wasm.Parser

fun main() {
// Create Host and run code
EmbedderHost {
fileSystem {
unrestricted = true
}
}.use(::executeCode)
}

private fun executeCode(embedderHost: EmbedderHost) {
// Prepare WASI and Emscripten host imports
val installer = ChicoryEmscriptenHostInstaller {
host = embedderHost
}

val wasiFunctions: List<HostFunction> = installer.setupWasiPreview1HostFunctions()
val emscriptenFinalizer: ChicoryEmscriptenSetupFinalizer = installer.setupEmscriptenFunctions()

val hostImports = ImportValues.builder()
.withFunctions(emscriptenFinalizer.emscriptenFunctions + wasiFunctions)
.build()

// Instantiate the WebAssembly module
val instance = Instance
.builder(File("helloworld.wasm"))
.withImportValues(hostImports)
.withInitialize(true)
.withStart(false)
.build()

// Finalize initialization after module instantiation
val emscriptenRuntime = emscriptenFinalizer.finalize(instance)

// Initialize Emscripten runtime environment
emscriptenRuntime.initMainThread()

// Execute code
instance.export("main").apply(
/* argc */ 0,
/* argv */ 0,
)[0]
}

Other samples

You can also check out samples in the repository:

Runtime Optimizations

Chicory is also working on an Ahead-of-Time (AOT) compiler that translates WebAssembly into JVM code. To experiment with this feature, you can add the following dependency:

implementation("com.dylibso.chicory:aot-experimental:1.0.0")

And add Engine when building Module:

import com.dylibso.chicory.experimental.aot.AotMachine

val module = Module
.builder(File("helloworld.wasm"))
.withHostImports(hostImports)
.withInitialize(true)
.withStart(false)
.withMachineFactory(::AotMachine)
.build()

For the latest updates, check this link: chicory/aot.