Skip to content

Commit deee38e

Browse files
committed
Document GraalWasm's interop and options, cleanup README
1 parent c06c8de commit deee38e

File tree

6 files changed

+681
-431
lines changed

6 files changed

+681
-431
lines changed

Diff for: docs/reference-manual/wasm/README.md

+215-94
Original file line numberDiff line numberDiff line change
@@ -7,102 +7,223 @@ permalink: /reference-manual/wasm/
77

88
# GraalWasm
99

10-
GraalWasm is an open source WebAssembly runtime.
11-
It runs WebAssembly programs in the binary format and can be used to embed and leverage WebAssembly modules in Java applications.
12-
GraalWasm is under active development and is tracking a number of WebAssembly extensions.
13-
14-
## Running WebAssembly Embedded in Java
15-
16-
Compiled WebAssembly binary code can be accessed programmatically with [GraalVM SDK Polyglot API](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/package-summary.html), which allows embedding WebAssembly into user applications.
17-
18-
The example below demonstrates how to compile a C function to WebAssembly and run it embedded in a Java application.
19-
To run the demo, you need the following:
20-
- [GraalVM JDK](https://www.graalvm.org/downloads/)
21-
- [Emscripten compiler frontend](https://emscripten.org/docs/tools_reference/emcc.html)
22-
- [Maven](https://maven.apache.org/)
23-
24-
### Demo Part
25-
26-
1. Put the following C program in a file named _floyd.c_:
27-
```c
28-
#include <stdio.h>
29-
30-
void floyd() {
31-
int number = 1;
32-
int rows = 10;
33-
for (int i = 1; i <= rows; i++) {
34-
for (int j = 1; j <= i; j++) {
35-
printf("%d ", number);
36-
++number;
37-
}
38-
printf(".\n");
39-
}
40-
}
41-
42-
int main() {
43-
floyd();
44-
return 0;
45-
}
46-
```
47-
Note that `floyd` is defined as a separate function and can be exported.
48-
49-
2. Compile the C code using the most recent version of the [Emscripten compiler frontend](https://emscripten.org/docs/tools_reference/emcc.html):
50-
```bash
51-
emcc --no-entry -s EXPORTED_FUNCTIONS=_floyd -o floyd.wasm floyd.c
52-
```
53-
> The exported functions must be prefixed by `_`. If you reference that function in, for example, the Java code, the exported name should not contain the underscore.
54-
55-
It produces a standalone file _floyd.wasm_ in the current working directory.
56-
57-
3. Add dependencies. The GraalVM SDK Polyglot API is not available by default, but can be easily added as a Maven dependency to your Java project.
58-
The GraalWasm artifact should be on the Java module or class path too. Add the following set of dependencies to the project configuration file (_pom.xml_ in case of Maven).
59-
60-
- To enable the GraalVM polyglot runtime:
61-
```xml
62-
<dependency>
63-
<groupId>org.graalvm.polyglot</groupId>
64-
<artifactId>polyglot</artifactId>
65-
<version>${graalvm.polyglot.version}</version>
66-
</dependency>
67-
```
68-
- To enable Wasm:
69-
```xml
70-
<dependency>
71-
<groupId>org.graalvm.polyglot</groupId>
72-
<artifactId>wasm</artifactId>
73-
<version>${graalvm.polyglot.version}</version>
74-
<type>pom</type>
75-
</dependency>
76-
```
77-
78-
4. Now you can embed this WebAssembly function in a Java application, for example:
79-
80-
```java
81-
import org.graalvm.polyglot.*;
82-
import org.graalvm.polyglot.io.ByteSequence;
83-
84-
// Load the WebAssembly contents into a byte array
85-
byte[] binary = Files.readAllBytes(Path.of("path", "to", "wasm", "file", "floyd.wasm"));
86-
87-
// Setup context
88-
Context.Builder contextBuilder = Context.newBuilder("wasm").option("wasm.Builtins", "wasi_snapshot_preview1");
89-
Source.Builder sourceBuilder = Source.newBuilder("wasm", ByteSequence.create(binary), "example");
90-
Source source = sourceBuilder.build();
91-
Context context = contextBuilder.build();
92-
93-
// Evaluate the WebAssembly module
94-
context.eval(source);
95-
96-
// Execute the floyd function
97-
context.getBindings("wasm").getMember("example").getMember("_initialize").executeVoid();
98-
Value mainFunction =context.getBindings("wasm").getMember("example").getMember("floyd");
99-
mainFunction.execute();
100-
context.close();
101-
```
102-
103-
5. Compile and run this Java application with Maven as usual.
10+
GraalWasm is an open-source WebAssembly runtime.
11+
It runs WebAssembly programs in binary format and can be used to embed and leverage WebAssembly modules in Java applications.
12+
GraalWasm is under active development and implements a number of WebAssembly extensions.
13+
14+
## WebAssembly Module System
15+
16+
Using GraalWasm, you can load WebAssembly modules in your application, access them from Java, and make them interoperate with other Graal languages.
17+
To proficiently use GraalWasm, it is important to first understand how GraalWasm maps WebAssembly's module system onto the Polyglot API.
18+
19+
GraalWasm uses the binary format of WebAssembly modules as its language.
20+
A valid [Source](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Source.html) that you can evaluate using GraalWasm is always a single WebAssembly module in the [binary format](https://webassembly.github.io/spec/core/binary/index.html).
21+
22+
Here is one way you can build a WebAssembly `Source`:
23+
24+
```java
25+
Source source = Source.newBuilder("wasm", new File("example.wasm")).name("example").build();
26+
```
27+
28+
When you evaluate a WebAssembly `Source`, the module is parsed, and validated, and a module instance is returned as the resulting value.
29+
The module instance can also later be retrieved from the top-level bindings.
30+
The name of the binding in the top-level scope is the same as the name of the `Source` that was evaluated.
31+
32+
```java
33+
// Evaluate the Source named "example".
34+
Value exampleModule = context.eval(source);
35+
// It is now accessible under the binding name "example".
36+
assert context.getBindings("wasm").getMember("example") == exampleModule;
37+
```
38+
39+
[Source names](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Source.html#getName()) are important in GraalWasm because they are also used to resolve module imports.
40+
If a module tries to import a symbol from module `foo`, then GraalWasm looks for that symbol in the module whose `Source` was named `foo`.
41+
These imports are not resolved until when a WebAssembly module instance's members are accessed or executed for the first time in a given context.
42+
43+
### Module Instance Objects
44+
45+
By evaluating WebAssembly modules through the Polyglot API, you get access to module instance objects.
46+
Module instance objects expose members for every symbol that was exported from the WebAssembly module.
47+
You can get a list of all exported symbols using [getMemberKeys](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html#getMemberKeys()), access individual exports using [getMember](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html#getMember(java.lang.String)) and, in the case of mutable globals, use [putMember](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html#putMember(java.lang.String,java.lang.Object)) to set their values.
48+
49+
Here is how the various kinds of WebAssembly exports map to polyglot values:
50+
51+
* Functions
52+
53+
Functions are exported as executable values, which you can call using [execute](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html#execute(java.lang.Object...)).
54+
Function arguments and return values are mapped between WebAssembly value types and polyglot values using the [type mapping](#type-mapping).
55+
If a function returns multiple values, these are wrapped in an interop array.
56+
57+
* Globals
58+
59+
When you access an exported global using `getMember`, you get the global's value, mapped using the [type mapping](#type-mapping).
60+
If the global is mutable, you can also update its value using `putMember`.
61+
Currently, setting globals works only for numeric types, whose value is mapped according to the [type mapping](#type-mapping).
62+
63+
* Memories
64+
65+
Exported memories implement both the array interface and the buffer interface.
66+
The array interface lets you view the memory as an array of bytes using [getArrayElement](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html#getArrayElement(long)) and [setArrayElement](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html#setArrayElement(long,java.lang.Object)).
67+
The buffer interface lets you do bulk copies of memory using [readBuffer](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html#readBuffer(long,byte%5B%5D,int,int)) and read and write the Java primitive types from and to the memory using the `readBuffer*` and `writeBuffer*` methods.
68+
69+
* Tables
70+
71+
Exported tables are opaque and cannot be queried or modified.
72+
73+
## Type Mapping
74+
75+
Whenever a WebAssembly value is passed either to Java code or to another Graal language, via a function call, return value, or exported global access, it is mapped to a polyglot value.
76+
The tables below show how this mapping works.
77+
WebAssembly is a statically-typed language and all values (locals, function arguments, return values) have a static type.
78+
Based on this type, GraalWasm interprets a polyglot value as a value of this type or reports a type error if the types do not match.
79+
80+
### WebAssembly Values as Polyglot Values
81+
82+
This table describes for each WebAssembly value type which polyglot interfaces the resulting value implements.
83+
84+
| WebAssembly Type | Polyglot Interface |
85+
|:-----------------|------------------------------|
86+
| `i32` | Number that fits in `int` |
87+
| `i64` | Number that fits in `long` |
88+
| `f32` | Number that fits in `float` |
89+
| `f64` | Number that fits in `double` |
90+
| `v128` | Read-only buffer of 16 bytes |
91+
| `funcref` | Executable object |
92+
| `externref` | Returned verbatim |
93+
94+
### Passing Arguments to WebAssembly Functions
95+
96+
When calling an exported WebAssembly function, its exact type signature must be respected.
97+
The table below gives the expected argument type for every possible WebAssembly parameter type.
98+
99+
| WebAssembly Parameter Type | Expected Argument Type |
100+
|:---------------------------|----------------------------------------------------------------------------------|
101+
| `i32` | `int` |
102+
| `i64` | `long` |
103+
| `f32` | `float` |
104+
| `f64` | `double` |
105+
| `v128` | Existing `v128` value received from WebAssembly |
106+
| `funcref` | WebAssembly's `ref.null` or an exported WebAssembly function |
107+
| `externref` | Can be anything (only WebAssembly's `ref.null` is seen as null by `ref.is_null`) |
108+
109+
## Options
110+
111+
GraalWasm can be configured with several options.
112+
When using the [Polyglot API](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/package-summary.html), options are passed programmatically to the [Context](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html) object:
113+
114+
```java
115+
Context.newBuilder("wasm").option("wasm.Builtins", "wasi_snapshot_preview1").build();
116+
```
117+
118+
See the [Polyglot Programming](https://github.com/oracle/graal/blob/master/docs/reference-manual/polyglot-programming.md#passing-options-programmatically) reference for more information on how to set options programmatically.
119+
120+
The available options are divided into stable and experimental options.
121+
Experimental options are provided with no guarantee of future support and can change from version to version.
122+
If an experimental option is used with the `wasm` launcher, the `--experimental-options` option has to be provided.
123+
When using a `Context`, the method [allowExperimentalOptions(true)](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#allowExperimentalOptions(boolean)) has to be called on the [Context.Builder](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html).
124+
125+
### Stable Options
126+
127+
The following stable options are provided:
128+
129+
* `--wasm.Builtins`: Exposes some of the GraalWasm-provided built-in modules.
130+
The syntax for the value is `[<linkingName>:]<builtinModuleName>,[<linkingName>:]<builtinModuleName>,...`.
131+
The requested modules are comma-separated.
132+
Every module may optionally be prefixed with a colon-separated linking name.
133+
If a linking name is given, the module is exported under the given linking name.
134+
Otherwise, the module is exported under its built-in module name.
135+
136+
The provided built-in modules are:
137+
* `spectest`: A module of simple functions useful for writing test cases.
138+
This module implements the same interface as the [spectest module of the WebAssembly reference interpreter](https://github.com/WebAssembly/spec/blob/main/interpreter/host/spectest.ml).
139+
Using it enables the execution of the [core WebAssembly specification tests](https://github.com/WebAssembly/spec/tree/main/test/core).
140+
* `wasi_snapshot_preview1`: GraalWasm's implementation of the [WebAssembly System Interface Snapshot Preview 1](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md).
141+
Covers most of the documented API, except socket and signal support.
142+
143+
* `--wasm.WasiMapDirs`: A list of pre-opened directories that should be accessible through the WebAssembly System Interface API.
144+
The syntax for the value is `[<virtualDir>::]<hostDir>,[<virtualDir>::]<hostDir>,...`.
145+
The pre-opened directories are comma-separated.
146+
Every directory may optionally be prefixed with a double-colon-separated virtual path.
147+
Inside the WebAssembly module, the directory is available at the virtual path.
148+
If the virtual path is omitted, the pre-opened directory will be on the same path as on the host filesystem.
149+
150+
This option must be set to allow modules that use WASI to access the filesystem.
151+
Access will be granted only to the contents of these pre-opened directories.
152+
153+
### Experimental Options
154+
155+
Note that these options are experimental and are not guaranteed to be maintained or supported in the future.
156+
To use them, the `--experimental-options` option is required, or experimental options have to be enabled on the `Context`, see [above](#graalwasm-engine-options).
157+
158+
The options below correspond to feature proposals that add new features to the WebAssembly standard.
159+
The accepted values are `true` for enabling a feature and `false` for disabling a feature.
160+
Features that have already been merged into the WebAssembly spec are enabled by default in GraalWasm.
161+
Features that are not yet merged into the spec are disabled by default.
162+
Users can override the defaults to experiment with upcoming features or opt out of standardized features.
163+
164+
* `--wasm.BulkMemoryAndRefTypes`: Enable support for the [bulk memory operations feature](https://github.com/WebAssembly/spec/blob/master/proposals/bulk-memory-operations/Overview.md) and [reference types feature](https://github.com/WebAssembly/spec/blob/master/proposals/reference-types/Overview.md), exposing instructions for efficient memory initialization and adding support for first-class opaque references.
165+
Defaults to `true`.
166+
167+
* `--wasm.ExtendedConstExpressions`: Enable support for the [extended constant expressions feature](https://github.com/WebAssembly/extended-const/blob/main/proposals/extended-const/Overview.md), adding limited support for arithmetic instructions inside constant expressions.
168+
Defaults to `false`.
169+
170+
* `--wasm.Memory64`: Enable support for the [Memory64 feature](https://github.com/WebAssembly/memory64/blob/main/proposals/memory64/Overview.md), letting memories be larger than 4 GiB.
171+
Defaults to `false`.
172+
173+
* `--wasm.MultiMemory`: Enable support for the [multiple memories feature](https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md), allowing modules to have multiple memories.
174+
Defaults to `false`.
175+
176+
* `--wasm.MultiValue`: Enable support for the [multi-value feature](https://github.com/WebAssembly/spec/blob/master/proposals/multi-value/Overview.md), letting functions return multiple values.
177+
Defaults to `true`.
178+
179+
* `--wasm.SaturatingFloatToInt`: Enable support for the [non-trapping float-to-int conversions feature](https://github.com/WebAssembly/spec/blob/master/proposals/nontrapping-float-to-int-conversion/Overview.md), adding float-to-int conversion instructions that saturate instead of failing with a trap.
180+
Defaults to `true`.
181+
182+
* `--wasm.SignExtensionOps`: Enable support for the [sign-extension operators feature](https://github.com/WebAssembly/spec/blob/master/proposals/sign-extension-ops/Overview.md), adding instructions for extending signed integer values.
183+
Defaults to `true`.
184+
185+
* `--wasm.SIMD`: Enable support for the [fixed-width SIMD feature](https://github.com/WebAssembly/spec/tree/main/proposals/simd), introducing a new value type, `v128`, and associated instructions for SIMD arithmetic.
186+
Defaults to `true`.
187+
188+
* `--wasm.Threads`: Enable support for the [threading feature](https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md), letting WebAssembly modules use new instructions for atomic memory access.
189+
Defaults to `false`.
190+
191+
## Using the GraalWasm Launcher
192+
193+
GraalWasm standalones provide the `wasm` launcher, which you can use to execute programs compiled as WebAssembly binary modules.
194+
195+
```
196+
wasm [OPTION...] [--entry-point=FN] FILE [ARG...]
197+
```
198+
199+
* `[OPTION...]`
200+
201+
The options consist of GraalWasm engine options, prefixed with `--wasm.`, for example `--wasm.WasiMapDirs=preopened-dir`, and any other polyglot engine options.
202+
When using the `wasm` launcher, the `--wasm.Builtins=wasi_snapshot_preview1` option is set by default so that you can directly execute modules compiled against the [WebAssembly System Interface Snapshot Preview 1](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md).
203+
204+
The available options are documented in [Options](#options).
205+
You can also get a full list of GraalWasm engine options by passing the `--help:wasm` option to the `wasm` launcher.
206+
To include internal options, use `--help:wasm:internal`.
207+
Note that those lists both include stable, supported options, and experimental options.
208+
209+
* `[--entry-point=FN]`
210+
211+
You can specify the `--entry-point` option to choose which exported function is to be used as the module's entry point, for example `--entry-point=my_custom_main_fn`.
212+
If the `--entry-point` option is missing, GraalWasm will try to auto-detect the entry point.
213+
It will first look for an exported function named `_start` and then for an exported function named `_main`.
214+
The first such function found will be executed as the entry point by the `wasm` launcher.
215+
216+
* `FILE`
217+
218+
This is the path to the binary module that will be executed.
219+
220+
* `[ARG...]`
221+
222+
Program arguments that are accessible to the program through the WASI [args_get](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#-args_getargv-pointerpointeru8-argv_buf-pointeru8---result-errno) and [args_sizes_get](https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#-args_sizes_get---resultsize-size-errno) functions.
104223

105224
### Related Documentation
106225

226+
- [Getting Started with GraalWasm](https://www.graalvm.org/webassembly/#getting-started)
227+
- [Embed C in Java Using GraalWasm](guides/embed-c-in-java.md)
107228
- [Embedding Languages documentation](../embedding/embed-languages.md)
108229
- [GraalWasm](https://github.com/oracle/graal/tree/master/wasm)

0 commit comments

Comments
 (0)