Commit Graph

24 Commits

Author SHA1 Message Date
Crypt Keeper
429334cf98 Renames ModuleBuilder to HostModuleBuilder and drops memory and globals (#812)
We at one point considered making `ModuleBuilder` create complete
WebAssembly binaries. However, we recently spun out
[wabin](https://github.com/tetratelabs/wabin), which allows this.

Meanwhile, the features in `ModuleBuilder` were confusing and misused.
For example, the only two cases memory was exported on GitHub were done
by accident. This is because host functions act on the guest's memory,
not their own.

Hence, this removes memory and globals from host side definitions, and
renames the type to HostModuleBuilder to clarify this is not ever going
to be used to construct normal Wasm binaries.

Most importantly, this simplifies the API and reduces a lot of code. It
is important to make changes like this, particularly deleting any
experimental things that didn't end up useful.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
Co-authored-by: Anuraag Agrawal <anuraaga@gmail.com>
2022-09-28 14:42:14 +08:00
Takeshi Yoneda
076d3245e3 Pass context into NewRuntime (#748)
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
2022-08-18 14:47:49 +09:00
Crypt Keeper
1689fc1bbf Allows wasm-defined host functions to use memory in interpreter (#713)
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>
2022-07-25 09:12:44 +08:00
Crypt Keeper
866fac2e96 Makes CacheNumInUint64 lazy and stops crashing in assemblyscript (#712)
* Makes CacheNumInUint64 lazy and stops crashing in assemblyscript

This makes CacheNumInUint64 lazy so that all tests for function types
don't need to handle it. This also changes the assemblyscript special
functions so they don't crash when attempting to log. Finally, this
refactors `wasm.Func` so that it can enclose the parameter names as it
is more sensible than defining them elsewhere.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-07-22 16:01:20 +08:00
Crypt Keeper
0da1af2d51 Supports mix of wasm and go funcs in the same module (#707)
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>
2022-07-19 11:55:37 +08:00
Crypt Keeper
040736caac Adds function names to host functions and improves logging listener (#697)
This improves the experimental logging listener to show parameter name
and values like so:

```
--> ._start.command_export()
        	--> .__wasm_call_ctors()
        		--> .__wasilibc_initialize_environ()
        			==> wasi_snapshot_preview1.environ_sizes_get(result.environc=1048572,result.environBufSize=1048568)
        			<== ESUCCESS
        		<-- ()
        		==> wasi_snapshot_preview1.fd_prestat_get(fd=3,result.prestat=1048568)
        		<== ESUCCESS
        		--> .dlmalloc(2)
        			--> .sbrk(0)
        			<-- (1114112)
        		<-- (1060080)
--snip--
```

The convention `==>` implies it was a host function call
(def.IsHostFunction). This also improves the lifecycle by creating
listeners during compile. Finally, this backfills param names for
assemblyscript and wasi.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-07-14 16:43:25 +08:00
Crypt Keeper
adc7e5b170 Adds Runtime.NewNamespace to allow intentional name collisions (#604)
Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-06-01 10:03:19 +08:00
Takeshi Yoneda
064bcdddc6 Implements v128.const and adds support for vector value type. (#556)
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>
2022-05-16 13:17:26 +09:00
Crypt Keeper
8f8c9ee205 Extracts CompileConfig and consolidates code. (#533)
This performs several changes to allow compilation config to be
centralized and scoped properly. The immediate effects are that we can
now process external types during `Runtime.CompileModule` instead of
doing so later during `Runtime.InstantiateModule`. Another nice side
effect is memory size problems can err at a source line instead of
having to be handled in several places.

There are some API effects to this, and to pay for them, some less used
APIs were removed. The "easy APIs" are left alone. For example, the APIs
to compile and instantiate a module from Go or Wasm in one step are left
alone.

Here are the changes, some of which are only for consistency. Rationale
is summarized in each point.
* ModuleBuilder.Build -> ModuleBuilder.Compile
  * The result of this is similar to `CompileModule`, and pairs better
    with `ModuleBuilder.Instantiate` which is like `InstantiateModule`.
* CompiledCode -> CompiledModule
  * We punted on this name, the result is more than just code. This is
    better I think and more consistent as it introduces less terms.
* Adds CompileConfig param to Runtime.CompileModule.
  * This holds existing features and will have future ones, such as
    mapping externtypes to uint64 for wasm that doesn't yet support it.
* Merges Runtime.InstantiateModuleWithConfig with Runtime.InstantiateModule
  * This allows us to explain APIs in terms of implicit or explicit
    compilation and config, vs implicit, kindof implicit, and explicit.
* Removes Runtime.InstantiateModuleFromCodeWithConfig
  * Similar to above, this API only saves the compilation step and also
    difficult to reason with from a name POV.
* RuntimeConfig.WithMemory(CapacityPages|LimitPages) -> CompileConfig.WithMemorySizer
  * This allows all error handling to be attached to the source line
  * This also allows someone to reduce unbounded memory while knowing
    what its minimum is.
* ModuleConfig.With(Import|ImportModule) -> CompileConfig.WithImportRenamer
  * This allows more types of import manipulation, also without
    conflating functions with globals.
* Adds api.ExternType
  * Needed for ImportRenamer and will be needed later for ExportRenamer.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-05-09 11:02:32 +08:00
Crypt Keeper
fbea2de984 Makes wazero.CompiledCode an interface instead of a struct (#519)
This makes wazero.CompiledCode an interface instead of a struct to
prevent it from being used incorrectly. For example, even though the
fields are not exported, someone can mistakenly instantiate this
when it is a struct, and in doing so violate internal assumptions.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-05-02 11:44:01 +08:00
Crypt Keeper
a91140f7f7 Changes RuntimeConfig to an interface and exposes WithWasmCore2 (#518)
WebAssembly Core Working Draft 1 recently came out. Before that, we had
a toe-hold feature bucked called FinishedFeatures. This replaces
`RuntimeConfig.WithFinishedFeatures` with `RuntimeConfig.WithWasmCore2`.
This also adds `WithWasmCore1` for those who want to lock into 1.0
features as opposed to relying on defaults.

This also fixes some design debt where we hadn't finished migrating
public types that require constructor functions (NewXxx) to interfaces.
By using interfaces, we prevent people from accidentally initializing
key configuration directly (via &Xxx), causing nil field refs. This also
helps prevent confusion about how to use the type (ex pointer or not) as
there's only one way (as an interface).

See https://github.com/tetratelabs/wazero/issues/516

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-05-02 10:29:38 +08:00
Crypt Keeper
2c03098dba Adds Runtime.WithCapacityPages to avoid allocations during runtime. (#514)
`Runtime.WithMemoryCapacityPages` is a function that determines memory
capacity in pages (65536 bytes per page). The inputs are the min and
possibly nil max defined by the module, and the default is to return
the min.

Ex. To set capacity to max when exists:
```golang
c.WithMemoryCapacityPages(func(minPages uint32, maxPages *uint32) uint32 {
	if maxPages != nil {
		return *maxPages
	}
	return minPages
})
```

Note: This applies at compile time, ModuleBuilder.Build or Runtime.CompileModule.

Fixes #500

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-04-29 17:54:48 +08:00
Crypt Keeper
45ccab589b Refactors API to ensure context propagation (#482)
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>
2022-04-19 16:52:57 +08:00
Takeshi Yoneda
0ca7ee1340 Use same CompiledCode for import replacement (#478)
This commit allows CompiledCode to be re-used regardless of
the existence of import replacement configs for instantiation.

In order to achieve this, we introduce ModuleID, which is sha256
checksum calculated on source bytes, as a key for module compilation
cache. Previously, we used*wasm.Module as keys for caches which
differ before/after import replacement.

Signed-off-by: Takeshi Yoneda takeshi@tetrate.io
2022-04-18 20:07:28 +09:00
Takeshi Yoneda
d2905d480c Make CompileModule actually compile (#469)
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>
2022-04-18 18:14:58 +09:00
Crypt Keeper
1e383881ed Removes testify dependency (#462)
This implements our own assertion library so that we can remove the
testify dependency. I've changed a lot of call sites so that we only
have to maintain a minimal amount of assertions.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-04-14 16:37:43 +08:00
Takeshi Yoneda
e3035b5a76 binary: complete encoder (#463)
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
2022-04-14 16:55:53 +09:00
Crypt Keeper
ce1052a097 Isolates testify to one file, so that it is easier to remove (#460)
This starts the process of removing all dependencies from wazero, by
isolating all assertions we use into a single file. This allows us to
port those assertions as we have time, and when twitchy is gone, the
project literally has no dependencies except go!

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-04-14 10:05:38 +08:00
Crypt Keeper
fb0b311844 Consistently uses LEB128 signed encoding for global constants (#443)
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>
2022-04-06 09:50:47 +08:00
Crypt Keeper
f5598c9a8e Fixes global numeric types to have max of signed encoding (#442)
This adjusts towards the exiting code which used int32/64 instead of
uint32/64. The reason is that the spec indicates intepretation as signed
numbers, which affects the maximum value.

See https://www.w3.org/TR/wasm-core-1/#value-types%E2%91%A2

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-04-06 06:35:31 +08:00
Crypt Keeper
b1cffcc58e Adds ModuleBuilder.ExportGlobalXXX to configure constants (#441)
See https://github.com/summerwind/the-art-of-webassembly-go/issues/1

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-04-05 15:41:19 +08:00
Crypt Keeper
9345a89bea Adds ModuleBuilder.ExportMemory and ExportMemoryWithMax (#440)
This adds functions to configure memory with ModuleBuilder. This uses
two functions, ExportMemory and ExportMemoryWithMax, as working with
uint32 pointers is awkward.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-04-05 13:12:43 +08:00
Crypt Keeper
2664b1eb62 Simplifies API per feedback (#427)
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()
 ...
```
2022-04-02 06:42:36 +08:00
Crypt Keeper
50d9fa58a1 Runtime.NewModule -> InstantiateModule and adds ModuleBuilder (#349)
This reverts `Runtime.NewModule` back to `InstantiateModule` as it calls
more attention to the registration aspect of it, and also makes a chain
of `NewXX` more clear. This is particularly helpful as this change
introduces `ModuleBuilder` which is created by `NewModuleBuilder`.

`ModuleBuilder` is a way to define a WebAssembly 1.0 (20191205) in Go.
The first iteration allows setting the module name and exported
functions. The next PR will add globals.

Ex. Below defines and instantiates a module named "env" with one function:

```go
hello := func() {
	fmt.Fprintln(stdout, "hello!")
}
_, err := r.NewModuleBuilder("env").ExportFunction("hello", hello).InstantiateModule()
```

If the same module may be instantiated multiple times, it is more efficient to separate steps. Ex.

```go
env, err := r.NewModuleBuilder("env").ExportFunction("get_random_string", getRandomString).Build()

_, err := r.InstantiateModule(env.WithName("env.1"))
_, err := r.InstantiateModule(env.WithName("env.2"))
```

Note: Builder methods do not return errors, to allow chaining. Any validation errors are deferred until Build.
Note: Insertion order is not retained. Anything defined by this builder is sorted lexicographically on Build.

Signed-off-by: Adrian Cole <adrian@tetrate.io>
2022-03-09 10:39:13 +08:00