While compilers should be conservative when targeting WebAssembly Core
features, runtimes should be lenient as otherwise people need to
constantly turn on all features. Currently, most examples have to turn
on 2.0 features because compilers such as AssemblyScript and TinyGo use
them by default. This matches the policy with the reality, and should
make first time use easier.
This top-levels an internal type as `api.CoreFeatures` and defaults to
2.0 as opposed to 1.0, our previous default. This is less cluttered than
the excess of `WithXXX` methods we had prior to implementing all
planned WebAssembly Core Specification 1.0 features.
Finally, this backfills rationale as flat config types were a distinct
decision even if feature set selection muddied the topic.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit implements the v128.const, i32x4.add and i64x2.add in
interpreter mode and this adds support for the vector value types in the
locals and globals.
Notably, the vector type values can be passed and returned by exported functions
as well as host functions via two-uint64 encodings as described in #484 (comment).
Note: implementation of these instructions on JIT will be done in subsequent PR.
part of #484
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit completes the reference-types proposal implementation.
Notably, this adds support for
* `ref.is_null`, `ref.func`, `ref.is_null` instructions
* `table.get`, `table.set`, `table.grow`, `table.size` and `table.fill` instructions
* `Externref` and `Funcref` types (including invocation via uint64 encoding).
part of #484
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This commit implements the rest of the unimplemented instructions in the
bulk-memory-operations proposal.
Notably, this adds support for table.init, table.copy and elem.drop
instructions toggled by FeatureBulkMemoryOperations.
Given that, now wazero has the complete support for the bulk-memory-operations
proposal as described in https://github.com/WebAssembly/spec/blob/main/proposals/bulk-memory-operations/Overview.mdfixes#321
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Global constants can be defined in wasm or in ModuleBuilder. In either
case, they end up being decoded and interpreted during instantiation.
This chooses signed encoding to avoid surprises. A more comprehensive
explanation was added to RATIONALE.md, but the motivation was a global
100 coming out negative.
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 adds `RuntimeConfig.WithFeatureMutableGlobal(enabled bool)`, which
allows disabling of mutable globals. When disabled, any attempt to add a
mutable global, either explicitly or implicitly via decoding wasm will
fail.
To support this, there's a new `Features` bitflag that can allow up to
63 feature toggles without passing structs.
While here, I fixed a significant performance problem in decoding
binary:
Before
```
BenchmarkCodecExample/binary.DecodeModule-16 184243 5623 ns/op 3848 B/op 184 allocs/op
```
Now
```
BenchmarkCodecExample/binary.DecodeModule-16 294084 3520 ns/op 2176 B/op 91 allocs/op
```
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This moves to a new end-user API under the root package `wazero`. This
simplifies call sites while hardening function calls to their known
return value. Most importantly, this moves most logic internal, as
noted in the RATIONALE.md.
Ex.
```go
// Read WebAssembly binary containing an exported "fac" function.
source, _ := os.ReadFile("./tests/engine/testdata/fac.wasm")
// Decode the binary as WebAssembly module.
mod, _ := wazero.DecodeModuleBinary(source)
// Initialize the execution environment called "store" with Interpreter-based engine.
store := wazero.NewStore()
// Instantiate the module, which returns its exported functions
functions, _ := store.Instantiate(mod)
// Get the factorial function
fac, _ := functions.GetFunctionI64Return("fac")
// Discover 7! is 5040
fmt.Println(fac(context.Background(), 7))
```
PS I changed the README to factorial because the wat version of
fibonacci is not consistent with the TinyGo one!
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Co-authored-by: Takaya Saeki <takaya@tetrate.io>
Co-authored-by: Takeshi Yoneda <takeshi@tetrate.io>