Files
wazero/wasm.go
Crypt Keeper aa61087016 Reduces exports and prepares ReleaseModuleInstance for testing (#327)
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>
2022-03-04 08:55:49 +08:00

146 lines
4.5 KiB
Go

package wazero
import (
"bytes"
"context"
"errors"
internalwasm "github.com/tetratelabs/wazero/internal/wasm"
"github.com/tetratelabs/wazero/internal/wasm/binary"
"github.com/tetratelabs/wazero/internal/wasm/text"
"github.com/tetratelabs/wazero/wasm"
)
// Runtime allows embedding of WebAssembly 1.0 (20191205) modules.
//
// Ex.
// r := wazero.NewRuntime()
// decoded, _ := r.DecodeModule(source)
// module, _ := r.NewModule(decoded)
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/
type Runtime interface {
wasm.Store
// DecodeModule decodes the WebAssembly 1.0 (20191205) text or binary source or errs if invalid.
//
// Note: the name defaults to what was decoded from the custom name section.
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
DecodeModule(source []byte) (*DecodedModule, error)
// NewModuleFromSource instantiates a module from the WebAssembly 1.0 (20191205) text or binary source or errs if
// invalid.
//
// Ex.
// module, _ := wazero.NewRuntime().NewModuleFromSource(source)
//
// Note: This is a convenience utility that chains DecodeModule with NewModule. To instantiate the same source
// multiple times, use DecodeModule as NewModule avoids redundant decoding and/or compilation.
NewModuleFromSource(source []byte) (wasm.Module, error)
// NewModule instantiates the module namespace or errs if the configuration was invalid.
//
// Ex.
// r := wazero.NewRuntime()
// decoded, _ := r.DecodeModule(source)
// module, _ := r.NewModule(decoded)
//
// Note: The last value of RuntimeConfig.WithContext is used for any WebAssembly 1.0 (20191205) Start Function.
NewModule(module *DecodedModule) (wasm.Module, error)
// TODO: RemoveModule
// NewHostModule instantiates the module namespace from the host or errs if the configuration was invalid.
//
// Ex.
// r := wazero.NewRuntime()
// wasiExports, _ := r.NewHostModule(wazero.WASISnapshotPreview1())
NewHostModule(hostModule *HostModuleConfig) (wasm.HostModule, error)
// TODO: RemoveHostModule
}
func NewRuntime() Runtime {
return NewRuntimeWithConfig(NewRuntimeConfig())
}
// NewRuntimeWithConfig returns a runtime with the given configuration.
func NewRuntimeWithConfig(config *RuntimeConfig) Runtime {
return &runtime{
ctx: config.ctx,
store: internalwasm.NewStore(config.ctx, config.engine, config.enabledFeatures),
enabledFeatures: config.enabledFeatures,
}
}
// runtime allows decoupling of public interfaces from internal representation.
type runtime struct {
ctx context.Context
store *internalwasm.Store
enabledFeatures internalwasm.Features
}
// Module implements wasm.Store Module
func (r *runtime) Module(moduleName string) wasm.Module {
return r.store.Module(moduleName)
}
// HostModule implements wasm.Store HostModule
func (r *runtime) HostModule(moduleName string) wasm.HostModule {
return r.store.HostModule(moduleName)
}
// DecodeModule implements Runtime.DecodeModule
func (r *runtime) DecodeModule(source []byte) (*DecodedModule, error) {
if source == nil {
return nil, errors.New("source == nil")
}
if len(source) < 8 { // Ex. less than magic+version in binary or '(module)' in text
return nil, errors.New("invalid source")
}
// Peek to see if this is a binary or text format
var decoder internalwasm.DecodeModule
if bytes.Equal(source[0:4], binary.Magic) {
decoder = binary.DecodeModule
} else {
decoder = text.DecodeModule
}
internal, err := decoder(source, r.enabledFeatures)
if err != nil {
return nil, err
} else if err = internal.Validate(); err != nil {
// TODO: decoders should validate before returning, as that allows
// them to err with the correct source position.
return nil, err
}
result := &DecodedModule{module: internal}
if internal.NameSection != nil {
result.name = internal.NameSection.ModuleName
}
return result, nil
}
// NewModuleFromSource implements Runtime.NewModuleFromSource
func (r *runtime) NewModuleFromSource(source []byte) (wasm.Module, error) {
if decoded, err := r.DecodeModule(source); err != nil {
return nil, err
} else {
return r.NewModule(decoded)
}
}
// NewModule implements Runtime.NewModule
func (r *runtime) NewModule(module *DecodedModule) (wasm.Module, error) {
return r.store.Instantiate(module.module, module.name)
}
// NewHostModule implements Runtime.NewHostModule
func (r *runtime) NewHostModule(hostModule *HostModuleConfig) (wasm.HostModule, error) {
return r.store.NewHostModule(hostModule.Name, hostModule.Functions)
}