This adds a new top-level type FSConfig, which is configured via
`ModuleConfig.WithFSConfig(fcfg)`. This implements read-only and
read-write directory mounts, something not formally supported before. It
also implements `WithFS` which adapts a normal `fs.FS`. For convenience,
we retain the old `ModuleConfig.WithFS` signature so as to not affect
existing users much. A new configuration for our emerging raw
filesystem, `FSConfig.WithSysfs()` will happen later without breaking
this API.
Here's an example:
```
moduleConfig = wazero.NewModuleConfig().
// Make the current directory read-only accessible to the guest.
WithReadOnlyDirMount(".", "/")
// Make "/tmp/wasm" accessible to the guest as "/tmp".
WithDirMount("/tmp/wasm", "/tmp")
```
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Formerly, we introduced `wazero.Namespace` to help avoid module name or import conflicts while still sharing the runtime's compilation cache. Now that we've introduced `CompilationCache` `wazero.Namespace` is no longer necessary. By removing it, we reduce the conceptual load on end users as well internal complexity. Since most users don't use namespace, the change isn't very impactful.
Users who are only trying to avoid module name conflict can generate a name like below instead of using multiple runtimes:
```go
moduleName := fmt.Sprintf("%d", atomic.AddUint64(&m.instanceCounter, 1))
module, err := runtime.InstantiateModule(ctx, compiled, config.WithName(moduleName))
```
For `HostModuleBuilder` users, we no longer take `Namespace` as the last parameter of `Instantiate` method:
```diff
// log to the console.
_, err := r.NewHostModuleBuilder("env").
NewFunctionBuilder().WithFunc(logString).Export("log").
- Instantiate(ctx, r)
+ Instantiate(ctx)
if err != nil {
log.Panicln(err)
}
```
The following is an example diff a use of namespace can use to keep compilation cache while also ensuring their modules don't conflict:
```diff
func useMultipleRuntimes(ctx context.Context, cache) {
- r := wazero.NewRuntime(ctx)
+ cache := wazero.NewCompilationCache()
for i := 0; i < N; i++ {
- // Create a new namespace to instantiate modules into.
- ns := r.NewNamespace(ctx) // Note: this is closed when the Runtime is
+ r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig().WithCompilationCache(cache))
// Instantiate a new "env" module which exports a stateful function.
_, err := r.NewHostModuleBuilder("env").
```
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This introduces the new API wazero.Cache interface which can be passed to wazero.RuntimeConfig.
Users can configure this to share the underlying compilation cache across multiple wazero.Runtime.
And along the way, this deletes the experimental file cache API as it's replaced by this new API.
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Co-authored-by: Crypt Keeper <64215+codefromthecrypt@users.noreply.github.com>
This consolidates internal code to syscallfs, which removes the fs.FS
specific path rules, except when adapting one to syscallfs. For example,
this allows the underlying filesystem to decide if relative paths are
supported or not, as well any EINVAL related concerns.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This adds ExportedFunctionDefinitions and ExportedMemoryDefinitions to
api.Module so that those who can't access CompileModule can see them.
Fixes#839
Signed-off-by: Adrian Cole <adrian@tetrate.io>
We originally exported WASI errno as we originally supported invoking
host functions directly (e.g. without a guest). This was an invalid call
pattern, and we removed that. However, we left the errnos exported even
though the caller of a guest won't ever see them. This prevented us from
re-using them cleanly in features such as logging.
This moves all constants including function names and flag enums
internal so that there is less duplication between logging and
implementation of wasi functions. This also helps in reference searches,
as we can analyze uses of a particular function name.
The only constant left exported is the module name, as there's a use
case for that (overriding implementations via FunctionBuilder).
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This adds writefs.FS, allowing functions to create and delete files.
This begins by implementing them on `GOARCH=js GOOS=wasm`. The current
status is a lot farther than before, even if completing write on WASI is
left for a later PR (possibly by another volunteer).
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This changes the listener signature to accept context and calling
module, so that all possible parameters and results can be logged. This
also changes the logging listener to make parameters visible when
logging results.
This infrastructure supports some helpful use cases, such as logging
WASI result parameters, such as the prestat path, which is only knowable
after the function has been called. The context parameter supposed
reading results of gojs functions, which are stored host-side in a go
context object.
Future pull requests will complete this as well backfill unit tests.
This is raised independently mainly to keep the PR size down of the
upcoming filesystem logger.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This removes ProxyFunc, which was an internal experiment to make
functions that use memory to store parameters or results easier to see.
The main issue with the approach was instantiation performance, as it
needs to dynamically generate functions. Another approach to visibility
can happen later, for example via internal logging hooks.
Notably, this fixed the performance regression after switching WASI to ProxyFunc:
```
name old time/op new time/op delta
Allocation/Compile-16 39.8ms ± 0% 39.5ms ± 0% -0.62% (p=0.016 n=4+5)
Allocation/Instantiate-16 1.74ms ± 4% 0.86ms ± 1% -50.19% (p=0.008 n=5+5)
Allocation/Call-16 4.25µs ± 1% 4.21µs ± 2% ~ (p=0.151 n=5+5)
name old alloc/op new alloc/op delta
Allocation/Compile-16 20.3MB ± 0% 20.3MB ± 0% ~ (p=0.841 n=5+5)
Allocation/Instantiate-16 1.04MB ± 0% 0.56MB ± 0% -45.88% (p=0.008 n=5+5)
Allocation/Call-16 48.0B ± 0% 48.0B ± 0% ~ (all equal)
name old allocs/op new allocs/op delta
Allocation/Compile-16 432k ± 0% 432k ± 0% ~ (p=0.833 n=5+5)
Allocation/Instantiate-16 16.6k ± 0% 6.7k ± 0% -59.34% (p=0.008 n=5+5)
Allocation/Call-16 5.00 ± 0% 5.00 ± 0% ~ (all equal)
```
Since we also removed it from `GOARCH=wasm GOOS=js`, we experienced a performance
benefit there as well:
```
name old time/op new time/op delta
_main/gojs.Run-16 13.7ms ± 1% 12.2ms ± 3% -10.76% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
_main/gojs.Run-16 25.4MB ± 0% 25.0MB ± 0% -1.66% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
_main/gojs.Run-16 166k ± 0% 158k ± 0% -4.79% (p=0.016 n=4+5)
```
Signed-off-by: Adrian Cole <adrian@tetrate.io>
We originally had a `context.Context` for anything that might be
traced, but it turned out to be only useful for lifecycle and host functions.
For instruction-scoped aspects like memory updates, a context parameter is too
fine-grained and also invisible in practice. For example, most users will use
the compiler engine, and its memory, global or table access will never use go's
context.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This removes the ability to override the current file system with Go
context, allowing us to simplify common paths and improve performance.
The context override was only used once in GitHub, in Trivy, and we
found another way to do that without it.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This adds ResultNames to HostFunctionBuilder and FunctionDefinition
which helps for multi-results or special-cased ones.
End users can access result names in `FunctionDefinition.ResultNames` or
set for their own host functions via
`HostFunctionBuilder.WithResultNames`. This change adds them for all
built-in functions where result names help.
Most notably, GOOS=js uses `ProxyFunc` to allow logging when a function
returns multiple results. Before, the results were returned without
names: e.g. `11231,1` and now they are named like `n=11231,ok=1`.
We soon plan to allow more visibility in WASI, for example, logging
results that will write to memory offsets. This infrastructure makes it
possible to do that.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This adds host functions that work on dynamic function tables. These are
only used by emscripten, but require some infrastructure to support it.
I added the least possible to due the task. This also only handles i32
and void returns with up to four parameters as that covers the needs of
PDFium. Future integrations may need more parameters or a mix of floats.
Such use cases should be addressed as they come as otherwise it is a lot
of work for the cartesian product of all combinations.
See 1b0d724fd5/test/passes/post-emscripten.wast
See https://github.com/jerbob92/go-pdfium-wasm
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This switches to gofumpt and applies changes, as I've noticed working
in dapr (who uses this) that it finds some things that are annoying,
such as inconsistent block formatting in test tables.
Signed-off-by: Adrian Cole <adrian@tetrate.io>