Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure and improve the docs #679

Merged
merged 22 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
54 changes: 54 additions & 0 deletions docs/docs/examples/1-rust.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
sidebar_position: 1
sidebar_label: Rust
title: Using Rust with Chicory
---
## Compile Rust to Wasm

Compiling a Rust library to Wasm is easy and can be performed using standard `rustc` options:

```bash
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:

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

## Using in Chicory

<!--
```java
//DEPS com.dylibso.chicory:docs-lib:999-SNAPSHOT
//DEPS com.dylibso.chicory:runtime:999-SNAPSHOT

docs.FileOps.copyFromWasmCorpus("count_vowels.rs.wasm", "count_vowels.rs.wasm");

System.setOut(new PrintStream(
new BufferedOutputStream(
new FileOutputStream("docs/examples/1-rust.md.result"))));
```
-->

```java
import com.dylibso.chicory.wasm.Parser;
import com.dylibso.chicory.runtime.Instance;

var instance = Instance.builder(Parser.parse(new File("count_vowels.rs.wasm"))).build();

var alloc = instance.export("alloc");
var dealloc = instance.export("dealloc");
var countVowels = instance.export("count_vowels");

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

memory.writeString(ptr, message);

var result = countVowels.apply(ptr, len)[0];
System.out.println(result);
```
2 changes: 2 additions & 0 deletions docs/docs/examples/_category_.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
label: Examples
position: 30
24 changes: 24 additions & 0 deletions docs/docs/experimental/1-why.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
sidebar_position: 1
sidebar_label: Why
title: Why
---
# Why?

Chicory 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.

Please note that if "something works" for you, its very unlekely that it will be removed completely, in most cases, expect slight public API changes or modules rename to happen.
andreaTP marked this conversation as resolved.
Show resolved Hide resolved

The goal of having `experimental` modules is because they are not stabilized, we are not 100% confident in the design and we want to be able to perform breaking changes without respecting SemVer.

This includes renaming artifactIDs, classes, methods and rework their usage according to the feedback and development progress.
andreaTP marked this conversation as resolved.
Show resolved Hide resolved

<!--
```java
//DEPS com.dylibso.chicory:docs-lib:999-SNAPSHOT

docs.FileOps.writeResult("docs/experimental", "1-why.md.result", "empty");
```
-->
123 changes: 123 additions & 0 deletions docs/docs/experimental/2-host-module-annot.md
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's name this file host-module-annotations or just host-modules. The abbreviation looks strange.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
sidebar_position: 2
sidebar_label: Annotations
title: Annotations
---
# Host Modules

Instead of writing host functions by hand, you can write a class containing annotated methods
and let the Chicory annotation processor generate the host functions for you. This is especially
useful when you have many host functions.

<!--
```java
//DEPS com.dylibso.chicory:docs-lib:999-SNAPSHOT
//DEPS com.dylibso.chicory:runtime:999-SNAPSHOT
```
-->

```java
@HostModule("demo")
public final class Demo {

public Demo() {};

@WasmExport
public long add(int a, int b) {
return a + b;
}

@WasmExport // the Wasm name is random_get
public void randomGet(Memory memory, int ptr, int len) {
byte[] data = new byte[len];
random.nextBytes(data);
memory.write(ptr, data);
}

public HostFunction[] toHostFunctions() {
return Demo_ModuleFactory.toHostFunctions(this);
}
}
```

The `@HostModule` annotation marks the class as a host module and specifies the module name for
all the host functions. The `@WasmExport` annotation marks a method as host function and optionally
specifies the name of the function. If the name is not specified, then the Java method name is
converted from camel case to snake case, as is a common convention in Wasm.

The `Demo_ModuleFactory` class in `toHostFunctions()` is generated by the annotation processor.

Host functions must be instance methods of the class. Static methods are not supported.
This is because host functions will typically interact with instance state in the host class.

To use the host module, you need to instantiate the host module and fetch the host functions:

<!--
```java
import com.dylibso.chicory.runtime.HostFunction;

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

public HostFunction[] toHostFunctions() {
return new HostFunction[0];
}
}
```
-->

```java
import com.dylibso.chicory.runtime.ImportValues;

var demo = new Demo();
var imports = ImportValues.builder().addFunction(demo.toHostFunctions()).build();
```

### Type conversions

The following conversions are supported:

| Java Type | Wasm Type |
|-------------------|------------|
| `int` | `i32` |
| `long` | `i64` |
| `float` | `f32` |
| `double` | `f64` |

### Enabling the Annotation Processor

In order to use host modules, you need to import the relevant annotations, e.g. in Maven:

```xml
<dependency>
<groupId>com.dylibso.chicory</groupId>
<artifactId>host-module-annotations-experimental</artifactId>
<version>latest-release</version>
</dependency>
```

and configure the Java compiler to include the Chicory `host-module-processor-experimental` as an annotation processor.
Exactly how this is done depends on the build system you are using, for instance, with Maven:

```xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>com.dylibso.chicory</groupId>
<artifactId>host-module-processor-experimental</artifactId>
<version>latest-release</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
```

<!--
```java
docs.FileOps.writeResult("docs/experimental", "2-host-module-annot.md.result", "empty");
```
-->
141 changes: 141 additions & 0 deletions docs/docs/experimental/3-aot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
---
sidebar_position: 3
sidebar_label: AOT compilation
title: AOT compilation
---
## Runtime AOT

<!--
```java
//DEPS com.dylibso.chicory:docs-lib:999-SNAPSHOT
//DEPS com.dylibso.chicory:aot-experimental:999-SNAPSHOT

import com.dylibso.chicory.wasm.Parser;
import com.dylibso.chicory.runtime.Instance;
import com.dylibso.chicory.runtime.Machine;

docs.FileOps.copyFromWasmCorpus("count_vowels.rs.wasm", "your.wasm");
```
-->

The Ahead-of-Time compiler backend is a drop-in replacement for the interpreter, and it passes 100% of the same
spec tests that the interpreter already supports.

You can instantiate a module using the AoT by explicitly providing a `MachineFactory`.
The default `Machine` implementation is the `InterpreterMachine`.

You can opt in to the AoT mode by writing:

```java
import com.dylibso.chicory.experimental.aot.AotMachine;

var module = Parser.parse(new File("your.wasm"));
var instance = Instance.builder(module).withMachineFactory(AotMachine::new).build();
```

after you add the dependency:

```xml
<dependency>
<groupId>com.dylibso.chicory</groupId>
<artifactId>aot-experimental</artifactId>
</dependency>
```

This will translate every module you instantiate into Java bytecode on-the-fly and in-memory.
The resulting code is usually expected to evaluate (much)faster and consume less memory.

Please note that compiling and executing AoT modules at runtime requires:
- an external dependency on [ASM](https://asm.ow2.io/)
- the usage of runtime reflection

This is usually fine when running on a standard JVM, but it involve some additional configuration when using tools like `native-image`.

## Pre-compiled AOT

You can use the AOT compiler at build-time, by leveraging a [Maven plug-in][aot-maven-plugin] to overcome the usage of reflection and external dependencies of the "Runtime AOT".
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The aot-maven-plugin link doesn't work (no suggestion since I'm not sure what you intended)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed


This mode of execution reduces startup time and will remove the need for distributing
the original Wasm binary.

Key advantages are:

- improved startup time because the translation occurs only once, when you are packaging your application
- 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
- same performance properties as the in-memory compiler (in fact, the compilation backend is the same)

Example configuration of the Maven plug-in:

```xml
<build>
<plugins>
<plugin>
<groupId>com.dylibso.chicory</groupId>
<artifactId>aot-maven-plugin-experimental</artifactId>
<executions>
<execution>
<id>aot-gen</id>
<goals>
<goal>wasm-aot-gen</goal>
</goals>
<configuration>
<!-- Translate the Wasm binary `wat2wasm` into bytecode -->
<wasmFile>src/main/resources/add.wasm</wasmFile>
<!-- Generate the following class file as a result -->
<name>org.acme.wasm.AddModule</name>
andreaTP marked this conversation as resolved.
Show resolved Hide resolved
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
```

In the codebase you can use the generated module by configuring appropriately the `MachineFactory`:

<!--
```java
class AddModule {
public static Machine create(Instance instance) {
return null;
}
}
```
-->

```java
var module = Parser.parse(new File("your.wasm"));
var instance = Instance.builder(module).withMachineFactory(AddModule::create).build();
andreaTP marked this conversation as resolved.
Show resolved Hide resolved
```

#### IDE shortcomings

In some IDEs the sources generated under the standard folder `target/generated-sources` are not automatically recognized.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which IDEs? This works correctly in IntelliJ.

There are sometimes issues with needing to force refresh or ignore/uniginore the modules when doing development of Chicory itself after switching branches/etc., but this shouldn't be a problem for normal users of Chicory.

Even when developing Chicory, the generates-sources/chicory-aot directory gets registered automatically for me in the wabt module, once everything "stabilizes".

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a known issue in VSCode and Eclipse, I added the note as I've been requested a fix a few times here and in various other projects.

It's unnecessary, but doesn't hurt either in IntelliJ.

To overcome this limitation you can use an additional Maven Plugin for a smoother IDE experience:

```xml
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>addSource</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.basedir}/target/generated-sources/chicory-aot</source>
</sources>
andreaTP marked this conversation as resolved.
Show resolved Hide resolved
</configuration>
</execution>
</executions>
</plugin>
```

<!--
```java
docs.FileOps.writeResult("docs/experimental", "3-aot.md.result", "empty");
```
-->
29 changes: 29 additions & 0 deletions docs/docs/experimental/4-cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
sidebar_position: 4
sidebar_label: CLI
title: CLI
---
# Install and use the CLI

The experimental Chicory CLI is available for download on Maven at the link:

```
https://repo1.maven.org/maven2/com/dylibso/chicory/cli/<version>/cli-<version>.sh
```

you can download the latest version and use it locally by typing:

```bash
export VERSION=$(wget -q -O - https://api.github.com/repos/dylibso/chicory/tags --header "Accept: application/json" | jq -r '.[0].name')
wget -O chicory https://repo1.maven.org/maven2/com/dylibso/chicory/cli/${VERSION}/cli-${VERSION}.sh
andreaTP marked this conversation as resolved.
Show resolved Hide resolved
chmod a+x chicory
./chicory
```

<!--
```java
//DEPS com.dylibso.chicory:docs-lib:999-SNAPSHOT

docs.FileOps.writeResult("docs/experimental", "4-cli.md.result", "empty");
```
-->
2 changes: 2 additions & 0 deletions docs/docs/experimental/_category_.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
label: Experimental
position: 20
Loading
Loading