Before, we allowed stubbed host functions to be defined in wasm instead
of Go. This improves performance and reduces a chance of side-effects vs
Go. In fact, any pure function was supported in wasm, provided it only
called pure functions.
This changes internals so that a wasm-defined host function can use
memory. Notably, host functions use the caller's memory, so this is
simpler to initially support in the interpreter.
This is needed to simplify and reduce performance hit of GOARCH=wasm,
GOOS=js code, which perform a lot of memory reads and do not have
idiomatic signatures.
Note: wasm-defined host functions remain internal until we gain
experience, at least conclusion of the wasm_exec host module.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This removes the constraint of a module being exclusively wasm or host
functions. Later pull requests can optimize special imports to be
implemented in wasm, particularly useful for disabled logging callbacks.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This top-levels `api.FunctionDefinition` which was formerly
experimental, and also adds import metadata to it. Now, it holds all
metadata known at compile time.
Here are the public API visible changes:
* api.ExportedFunction - replaced with api.FunctionDefinition as it is
usable for all types of functions.
* api.Function - `.ParamTypes/ResultTypes()` are replaced with
`.Definition().
* api.FunctionDefinition - extracted from experimental and adds
`.Import()` to get the any imported module and function name.
* experimental.FunctionDefinition - replaced with
api.FunctionDefinition.
* experimental.FunctionListenerFactory - adds first arg of the
instantiated module name, as it can be different than compiled.
* wazero.CompiledModule - Adds `.ImportedFunctions()` and changes result
type of `.ExportedFunctions()` to api.FunctionDefinition.
Internally, logic to create function definition are consolidated between
host and wasm-defined functions, notably wasm.Module now includes
`.BuildFunctionDefinitions()` which reduces duplication in
wasm.ModuleInstance `.BuildFunctions()`,
This obviates #681 by deleting the `ExportedFunction` type which
overlaps with this information.
This fixes#637 as it includes more metadata including imports.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
Co-authored-by: Takeshi Yoneda <takeshi@tetrate.io>
This completes the implementation of SIMD proposal for both
the interpreter and compiler(amd64).
This also fixes#210 by adding the complete documentation
over all the wazeroir operations.
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Co-authored-by: Crypt Keeper <64215+codefromthecrypt@users.noreply.github.com>
This implements various SIMD instructions related to
load, store, and lane manipulations for all engines.
Notablely, now our engines pass the following specification tests:
* simd_address.wast
* simd_const.wast
* simd_align.wast
* simd_laod16_lane.wast
* simd_laod32_lane.wast
* simd_laod64_lane.wast
* simd_laod8_lane.wast
* simd_lane.wast
* simd_load_extend.wast
* simd_load_splat.wast
* simd_load_zero.wast
* simd_store.wast
* simd_store16_lane.wast
* simd_store32_lane.wast
* simd_store64_lane.wast
* simd_store8_lane.wast
part of #484
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Co-authored-by: Adrian Cole <adrian@tetrate.io>
This notably changes NewRuntimeJIT to NewRuntimeCompiler as well renames
packages from jit to compiler.
This clarifies the implementation is AOT, not JIT, at least when
clarified to where it occurs (Runtime.CompileModule). In doing so, we
reduce any concern that compilation will happen during function
execution. We also free ourselves to create a JIT option without
confusion in the future via CompileConfig or otherwise.
Fixes#560
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 enables WebAssembly 2.0 Core Specification tests.
In order to pass the tests, this fixes several places mostly on the
validation logic.
Note that SIMD instructions are not implemented yet.
part of #484
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Co-authored-by: Crypt Keeper <64215+codefromthecrypt@users.noreply.github.com>
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 adds support for multiple tables per module.
Notably, if the WithFeatureReferenceTypes is enabled,
call_indirect, table.init and table.copy instructions
can reference non-zero indexed tables.
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>
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>
This is an API breaking change that does a few things:
* Stop encouraging practice that can break context propagation:
* Stops caching `context.Context` in `wazero.RuntimeConfig`
* Stops caching `context.Context` in `api.Module`
* Fixes context propagation in function calls:
* Changes `api.Function`'s arg0 from `api.Module` to `context.Context`
* Adds `context.Context` parameter in instantiation (propagates to
.start)
* Allows context propagation for heavy operations like compile:
* Adds `context.Context` as the initial parameter of `CompileModule`
The design we had earlier was a good start, but this is the only way to
ensure coherence when users start correlating or tracing. While adding a
`context.Context` parameter may seem difficult, wazero is a low-level
library and WebAssembly is notoriously difficult to troubleshoot. In
other words, it will be easier to explain to users to pass (even nil) as
the context parameter vs try to figure out things without coherent
context.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit makes it possible for functions to be compiled before instantiation.
Notably, this adds CompileModule method on Engine interface where we pass
wasm.Module (which is the decoded module) to engines, and engines compile
all the module functions and caches them keyed on *wasm.Module.
In order to achieve that, this stops the compiled native code from embedding typeID
which is assigned for all the function types in a store.
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
This adds tests that pass without changing deferred error handling.
There are some tests that don't pass even without deferred error
handling. I'll add those in a separate PR.
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 commit fixes a few bugs in engine.Release, and backfills
unittests. Notably, moduleEngines must not release the imported
functions.
Signed-off-by: Takeshi Yoneda takeshi@tetrate.io
Allows users to do the following to enable sign-extension-ops:
```
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfig().WithFeatureSignExtensionOps(true))
```
Resolves#66
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Co-authored-by: Adrian Cole <adrian@tetrate.io>
This flattens `FunctionInstance.FunctionType` into `Type` and `TypeID`
fields, where the former is known prior to instantiation. This helps
pave a way for integration between Wasm declared and host defined
modules.
This also clarifies that `FunctionInstance.String` was used as a lookup
key, by renaming and caching its impl. While at it, I renamed "null" to
"v" in its output as I had been using v for void noticing others were
doing that also. Moreover, null is easy to misunderstand as a bug.
Signed-off-by: Adrian Cole <adrian@tetrate.io>
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>