* experimental: give listener r/o view of globals
Signed-off-by: Thomas Pelletier <thomas@pelletier.codes>
* experimental: add global support to interpreter
Signed-off-by: Thomas Pelletier <thomas@pelletier.codes>
* exp: replace globals proxy with module interface
Signed-off-by: Thomas Pelletier <thomas@pelletier.codes>
* exp: trim down experimental.InternalModule
Signed-off-by: Thomas Pelletier <thomas@pelletier.codes>
* Replace globals view slice with constantGlobal
Signed-off-by: Thomas Pelletier <thomas@pelletier.codes>
* Fix tests after merge
Signed-off-by: Thomas Pelletier <thomas@pelletier.codes>
* Address PR feedback
Signed-off-by: Thomas Pelletier <thomas@pelletier.codes>
* Rename methods of experimental.Module
Signed-off-by: Thomas Pelletier <thomas@pelletier.codes>
* Run make check
Signed-off-by: Thomas Pelletier <thomas@pelletier.codes>
* Add WazeroOnlyType to constantGlobal
Signed-off-by: Thomas Pelletier <thomas@pelletier.codes>
---------
Signed-off-by: Thomas Pelletier <thomas@pelletier.codes>
This adds a new type `internalapi.WazeroOnly` which should be embedded on types users are likely to accidentally implement despite docs saying otherwise.
Signed-off-by: Nuno Cruces <ncruces@users.noreply.github.com>
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 restores the ability to leave out the initial context parameter
when defining functions with reflection. This is important because some
projects are porting from a different library to wazero, and all the
alternatives are not contextualized.
For example, this project is porting envoy host functions, and the
original definitions (in mosn) don't have a context parameter. By being
lenient, they can migrate easier.
See 6b813482b6/pkg/proxywasm/wazero/imports_v1.go
Signed-off-by: Adrian Cole <adrian@tetrate.io>
staticcheck linters broke until recent golangci-lint. Now, normal
behaviour of enforcing no nil context works again. Ex.
```
assemblyscript/assemblyscript_example_test.go:16:25: SA1012: do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use (staticcheck)
r := wazero.NewRuntime(nil)
```
Since default lint already checks for nil context, this removes our
permission of nil context args. The original reason we permitted nil is
no longer valid: we once allowed context to be stashed in config, and
removed that as it caused bugs. We forgot to undo allowing nil
explicitly.
Note: this doesn't particularly check in our code for nil context,
similar as we don't particularly check in our code for nil anything
else. End users should use linters as none of our parameters should be
nil anyway.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This prepares for exposing operations like Memory.Grow while keeping the
ability to trace what did that, by adding a `context.Context` initial
parameter. This adds this to all API methods that mutate or return
mutated data.
Before, we made a change to trace functions and general lifecycle
commands, but we missed this part. Ex. We track functions, but can't
track what closed the module, changed memory or a mutable constant.
Changing to do this now is not only more consistent, but helps us
optimize at least the interpreter to help users identify otherwise
opaque code that can cause harm. This is critical before we add more
functions that can cause harm, such as Memory.Grow.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
During #425, @neilalexander gave constructive feedback that the API is
both moving fast, and not good enough yet. This attempts to reduce the
incidental complexity at the cost of a little conflation.
### odd presence of `wasm` and `wasi` packages -> `api` package
We had public API packages in wasm and wasi, which helped us avoid
leaking too many internals as public. That these had names that look
like there should be implementations in them cause unnecessary
confusion. This squashes both into one package "api" which has no
package collission with anything.
We've long struggled with the poorly specified and non-uniformly
implemented WASI specification. Trying to bring visibility to its
constraints knowing they are routinely invalid taints our API for no
good reason. This removes all `WASI` commands for a default to invoke
the function `_start` if it exists. In doing so, there's only one path
to start a module.
Moreover, this puts all wasi code in a top-level package "wasi" as it
isn't re-imported by any internal types.
### Reuse of Module for pre and post instantiation to `Binary` -> `Module`
Module is defined by WebAssembly in many phases, from decoded to
instantiated. However, using the same noun in multiple packages is very
confusing. We at one point tried a name "DecodedModule" or
"InstantiatedModule", but this is a fools errand. By deviating slightly
from the spec we can make it unambiguous what a module is.
This make a result of compilation a `Binary`, retaining `Module` for an
instantiated one. In doing so, there's no longer any name conflicts
whatsoever.
### Confusion about config -> `ModuleConfig`
Also caused by splitting wasm into wasm+wasi is configuration. This
conflates both into the same type `ModuleConfig` as it is simpler than
trying to explain a "will never be finished" api of wasi snapshot-01 in
routine use of WebAssembly. In other words, this further moves WASI out
of the foreground as it has been nothing but burden.
```diff
--- a/README.md
+++ b/README.md
@@ -49,8 +49,8 @@ For example, here's how you can allow WebAssembly modules to read
-wm, err := r.InstantiateModule(wazero.WASISnapshotPreview1())
-defer wm.Close()
+wm, err := wasi.InstantiateSnapshotPreview1(r)
+defer wm.Close()
-sysConfig := wazero.NewSysConfig().WithFS(os.DirFS("/work/home"))
-module, err := wazero.StartWASICommandWithConfig(r, compiled, sysConfig)
+config := wazero.ModuleConfig().WithFS(os.DirFS("/work/home"))
+module, err := r.InstantiateModule(binary, config)
defer module.Close()
...
```
This converges host-defined modules with Wasm defined modules by
introducing a custom section for host-defined functions. The net result
are far less types and consistent initialization.
* HostModule is removed for Module
* HostFunction is removed for Function
* ModuleContext is removed for Module
Note: One impact of this is that the low-level API no longer accepts a
go context (context.Context), rather a `wasm.Module` which the function
is called in context of. This meant exposing `wasm.Module.WithContext`
to override the default.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This removes more exports and adds a toehold test for
`ReleaseModuleInstance` so that it can later be completed for both
wasm and host modules.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Global is a WebAssembly 1.0 (20191205) global exported from an
instantiated module (wazero.Runtime NewModule).
Ex. If the value is not mutable, you can read it once:
```go
offset := module.Global("memory.offset").Get()
```
Globals are allowed by specification to be mutable. However, this can
be disabled by configuration. When in doubt, safe cast to find out if
the value can change.
Ex.
```go
offset := module.Global("memory.offset")
if _, ok := offset.(wasm.MutableGlobal); ok {
value can change
} else {
value is constant
}
```
See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#globals%E2%91%A0
Signed-off-by: Adrian Cole <adrian@tetrate.io>