summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/runtime.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/runtime.go')
-rw-r--r--vendor/github.com/tetratelabs/wazero/runtime.go380
1 files changed, 0 insertions, 380 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/runtime.go b/vendor/github.com/tetratelabs/wazero/runtime.go
deleted file mode 100644
index 34742289e..000000000
--- a/vendor/github.com/tetratelabs/wazero/runtime.go
+++ /dev/null
@@ -1,380 +0,0 @@
-package wazero
-
-import (
- "context"
- "fmt"
- "sync/atomic"
-
- "github.com/tetratelabs/wazero/api"
- experimentalapi "github.com/tetratelabs/wazero/experimental"
- "github.com/tetratelabs/wazero/internal/expctxkeys"
- internalsock "github.com/tetratelabs/wazero/internal/sock"
- internalsys "github.com/tetratelabs/wazero/internal/sys"
- "github.com/tetratelabs/wazero/internal/wasm"
- binaryformat "github.com/tetratelabs/wazero/internal/wasm/binary"
- "github.com/tetratelabs/wazero/sys"
-)
-
-// Runtime allows embedding of WebAssembly modules.
-//
-// The below is an example of basic initialization:
-//
-// ctx := context.Background()
-// r := wazero.NewRuntime(ctx)
-// defer r.Close(ctx) // This closes everything this Runtime created.
-//
-// mod, _ := r.Instantiate(ctx, wasm)
-//
-// # Notes
-//
-// - This is an interface for decoupling, not third-party implementations.
-// All implementations are in wazero.
-// - Closing this closes any CompiledModule or Module it instantiated.
-type Runtime interface {
- // Instantiate instantiates a module from the WebAssembly binary (%.wasm)
- // with default configuration, which notably calls the "_start" function,
- // if it exists.
- //
- // Here's an example:
- // ctx := context.Background()
- // r := wazero.NewRuntime(ctx)
- // defer r.Close(ctx) // This closes everything this Runtime created.
- //
- // mod, _ := r.Instantiate(ctx, wasm)
- //
- // # Notes
- //
- // - See notes on InstantiateModule for error scenarios.
- // - See InstantiateWithConfig for configuration overrides.
- Instantiate(ctx context.Context, source []byte) (api.Module, error)
-
- // InstantiateWithConfig instantiates a module from the WebAssembly binary
- // (%.wasm) or errs for reasons including exit or validation.
- //
- // Here's an example:
- // ctx := context.Background()
- // r := wazero.NewRuntime(ctx)
- // defer r.Close(ctx) // This closes everything this Runtime created.
- //
- // mod, _ := r.InstantiateWithConfig(ctx, wasm,
- // wazero.NewModuleConfig().WithName("rotate"))
- //
- // # Notes
- //
- // - See notes on InstantiateModule for error scenarios.
- // - If you aren't overriding defaults, use Instantiate.
- // - This is a convenience utility that chains CompileModule with
- // InstantiateModule. To instantiate the same source multiple times,
- // use CompileModule as InstantiateModule avoids redundant decoding
- // and/or compilation.
- InstantiateWithConfig(ctx context.Context, source []byte, config ModuleConfig) (api.Module, error)
-
- // NewHostModuleBuilder lets you create modules out of functions defined in Go.
- //
- // Below defines and instantiates a module named "env" with one function:
- //
- // ctx := context.Background()
- // hello := func() {
- // fmt.Fprintln(stdout, "hello!")
- // }
- // _, err := r.NewHostModuleBuilder("env").
- // NewFunctionBuilder().WithFunc(hello).Export("hello").
- // Instantiate(ctx, r)
- //
- // Note: empty `moduleName` is not allowed.
- NewHostModuleBuilder(moduleName string) HostModuleBuilder
-
- // CompileModule decodes the WebAssembly binary (%.wasm) or errs if invalid.
- // Any pre-compilation done after decoding wasm is dependent on RuntimeConfig.
- //
- // There are two main reasons to use CompileModule instead of Instantiate:
- // - Improve performance when the same module is instantiated multiple times under different names
- // - Reduce the amount of errors that can occur during InstantiateModule.
- //
- // # Notes
- //
- // - The resulting module name defaults to what was binary from the custom name section.
- // - Any pre-compilation done after decoding the source is dependent on RuntimeConfig.
- //
- // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
- CompileModule(ctx context.Context, binary []byte) (CompiledModule, error)
-
- // InstantiateModule instantiates the module or errs for reasons including
- // exit or validation.
- //
- // Here's an example:
- // mod, _ := n.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().
- // WithName("prod"))
- //
- // # Errors
- //
- // While CompiledModule is pre-validated, there are a few situations which
- // can cause an error:
- // - The module name is already in use.
- // - The module has a table element initializer that resolves to an index
- // outside the Table minimum size.
- // - The module has a start function, and it failed to execute.
- // - The module was compiled to WASI and exited with a non-zero exit
- // code, you'll receive a sys.ExitError.
- // - RuntimeConfig.WithCloseOnContextDone was enabled and a context
- // cancellation or deadline triggered before a start function returned.
- InstantiateModule(ctx context.Context, compiled CompiledModule, config ModuleConfig) (api.Module, error)
-
- // CloseWithExitCode closes all the modules that have been initialized in this Runtime with the provided exit code.
- // An error is returned if any module returns an error when closed.
- //
- // Here's an example:
- // ctx := context.Background()
- // r := wazero.NewRuntime(ctx)
- // defer r.CloseWithExitCode(ctx, 2) // This closes everything this Runtime created.
- //
- // // Everything below here can be closed, but will anyway due to above.
- // _, _ = wasi_snapshot_preview1.InstantiateSnapshotPreview1(ctx, r)
- // mod, _ := r.Instantiate(ctx, wasm)
- CloseWithExitCode(ctx context.Context, exitCode uint32) error
-
- // Module returns an instantiated module in this runtime or nil if there aren't any.
- Module(moduleName string) api.Module
-
- // Closer closes all compiled code by delegating to CloseWithExitCode with an exit code of zero.
- api.Closer
-}
-
-// NewRuntime returns a runtime with a configuration assigned by NewRuntimeConfig.
-func NewRuntime(ctx context.Context) Runtime {
- return NewRuntimeWithConfig(ctx, NewRuntimeConfig())
-}
-
-// NewRuntimeWithConfig returns a runtime with the given configuration.
-func NewRuntimeWithConfig(ctx context.Context, rConfig RuntimeConfig) Runtime {
- config := rConfig.(*runtimeConfig)
- var engine wasm.Engine
- var cacheImpl *cache
- if c := config.cache; c != nil {
- // If the Cache is configured, we share the engine.
- cacheImpl = c.(*cache)
- engine = cacheImpl.initEngine(config.engineKind, config.newEngine, ctx, config.enabledFeatures)
- } else {
- // Otherwise, we create a new engine.
- engine = config.newEngine(ctx, config.enabledFeatures, nil)
- }
- store := wasm.NewStore(config.enabledFeatures, engine)
- return &runtime{
- cache: cacheImpl,
- store: store,
- enabledFeatures: config.enabledFeatures,
- memoryLimitPages: config.memoryLimitPages,
- memoryCapacityFromMax: config.memoryCapacityFromMax,
- dwarfDisabled: config.dwarfDisabled,
- storeCustomSections: config.storeCustomSections,
- ensureTermination: config.ensureTermination,
- }
-}
-
-// runtime allows decoupling of public interfaces from internal representation.
-type runtime struct {
- store *wasm.Store
- cache *cache
- enabledFeatures api.CoreFeatures
- memoryLimitPages uint32
- memoryCapacityFromMax bool
- dwarfDisabled bool
- storeCustomSections bool
-
- // closed is the pointer used both to guard moduleEngine.CloseWithExitCode and to store the exit code.
- //
- // The update value is 1 + exitCode << 32. This ensures an exit code of zero isn't mistaken for never closed.
- //
- // Note: Exclusively reading and updating this with atomics guarantees cross-goroutine observations.
- // See /RATIONALE.md
- closed atomic.Uint64
-
- ensureTermination bool
-}
-
-// Module implements Runtime.Module.
-func (r *runtime) Module(moduleName string) api.Module {
- if len(moduleName) == 0 {
- return nil
- }
- m := r.store.Module(moduleName)
- if m == nil {
- return nil
- } else if m.Source.IsHostModule {
- return hostModuleInstance{m}
- }
- return m
-}
-
-// CompileModule implements Runtime.CompileModule
-func (r *runtime) CompileModule(ctx context.Context, binary []byte) (CompiledModule, error) {
- if err := r.failIfClosed(); err != nil {
- return nil, err
- }
-
- internal, err := binaryformat.DecodeModule(binary, r.enabledFeatures,
- r.memoryLimitPages, r.memoryCapacityFromMax, !r.dwarfDisabled, r.storeCustomSections)
- if err != nil {
- return nil, err
- } else if err = internal.Validate(r.enabledFeatures); err != nil {
- // TODO: decoders should validate before returning, as that allows
- // them to err with the correct position in the wasm binary.
- return nil, err
- }
-
- // Now that the module is validated, cache the memory definitions.
- // TODO: lazy initialization of memory definition.
- internal.BuildMemoryDefinitions()
-
- c := &compiledModule{module: internal, compiledEngine: r.store.Engine}
-
- // typeIDs are static and compile-time known.
- typeIDs, err := r.store.GetFunctionTypeIDs(internal.TypeSection)
- if err != nil {
- return nil, err
- }
- c.typeIDs = typeIDs
-
- listeners, err := buildFunctionListeners(ctx, internal)
- if err != nil {
- return nil, err
- }
- internal.AssignModuleID(binary, listeners, r.ensureTermination)
- if err = r.store.Engine.CompileModule(ctx, internal, listeners, r.ensureTermination); err != nil {
- return nil, err
- }
- return c, nil
-}
-
-func buildFunctionListeners(ctx context.Context, internal *wasm.Module) ([]experimentalapi.FunctionListener, error) {
- // Test to see if internal code are using an experimental feature.
- fnlf := ctx.Value(expctxkeys.FunctionListenerFactoryKey{})
- if fnlf == nil {
- return nil, nil
- }
- factory := fnlf.(experimentalapi.FunctionListenerFactory)
- importCount := internal.ImportFunctionCount
- listeners := make([]experimentalapi.FunctionListener, len(internal.FunctionSection))
- for i := 0; i < len(listeners); i++ {
- listeners[i] = factory.NewFunctionListener(internal.FunctionDefinition(uint32(i) + importCount))
- }
- return listeners, nil
-}
-
-// failIfClosed returns an error if CloseWithExitCode was called implicitly (by Close) or explicitly.
-func (r *runtime) failIfClosed() error {
- if closed := r.closed.Load(); closed != 0 {
- return fmt.Errorf("runtime closed with exit_code(%d)", uint32(closed>>32))
- }
- return nil
-}
-
-// Instantiate implements Runtime.Instantiate
-func (r *runtime) Instantiate(ctx context.Context, binary []byte) (api.Module, error) {
- return r.InstantiateWithConfig(ctx, binary, NewModuleConfig())
-}
-
-// InstantiateWithConfig implements Runtime.InstantiateWithConfig
-func (r *runtime) InstantiateWithConfig(ctx context.Context, binary []byte, config ModuleConfig) (api.Module, error) {
- if compiled, err := r.CompileModule(ctx, binary); err != nil {
- return nil, err
- } else {
- compiled.(*compiledModule).closeWithModule = true
- return r.InstantiateModule(ctx, compiled, config)
- }
-}
-
-// InstantiateModule implements Runtime.InstantiateModule.
-func (r *runtime) InstantiateModule(
- ctx context.Context,
- compiled CompiledModule,
- mConfig ModuleConfig,
-) (mod api.Module, err error) {
- if err = r.failIfClosed(); err != nil {
- return nil, err
- }
-
- code := compiled.(*compiledModule)
- config := mConfig.(*moduleConfig)
-
- // Only add guest module configuration to guests.
- if !code.module.IsHostModule {
- if sockConfig, ok := ctx.Value(internalsock.ConfigKey{}).(*internalsock.Config); ok {
- config.sockConfig = sockConfig
- }
- }
-
- var sysCtx *internalsys.Context
- if sysCtx, err = config.toSysContext(); err != nil {
- return
- }
-
- name := config.name
- if !config.nameSet && code.module.NameSection != nil && code.module.NameSection.ModuleName != "" {
- name = code.module.NameSection.ModuleName
- }
-
- // Instantiate the module.
- mod, err = r.store.Instantiate(ctx, code.module, name, sysCtx, code.typeIDs)
- if err != nil {
- // If there was an error, don't leak the compiled module.
- if code.closeWithModule {
- _ = code.Close(ctx) // don't overwrite the error
- }
- return
- }
-
- if closeNotifier, ok := ctx.Value(expctxkeys.CloseNotifierKey{}).(experimentalapi.CloseNotifier); ok {
- mod.(*wasm.ModuleInstance).CloseNotifier = closeNotifier
- }
-
- // Attach the code closer so that anything afterward closes the compiled
- // code when closing the module.
- if code.closeWithModule {
- mod.(*wasm.ModuleInstance).CodeCloser = code
- }
-
- // Now, invoke any start functions, failing at first error.
- for _, fn := range config.startFunctions {
- start := mod.ExportedFunction(fn)
- if start == nil {
- continue
- }
- if _, err = start.Call(ctx); err != nil {
- _ = mod.Close(ctx) // Don't leak the module on error.
-
- if se, ok := err.(*sys.ExitError); ok {
- if se.ExitCode() == 0 { // Don't err on success.
- err = nil
- }
- return // Don't wrap an exit error
- }
- err = fmt.Errorf("module[%s] function[%s] failed: %w", name, fn, err)
- return
- }
- }
- return
-}
-
-// Close implements api.Closer embedded in Runtime.
-func (r *runtime) Close(ctx context.Context) error {
- return r.CloseWithExitCode(ctx, 0)
-}
-
-// CloseWithExitCode implements Runtime.CloseWithExitCode
-//
-// Note: it also marks the internal `closed` field
-func (r *runtime) CloseWithExitCode(ctx context.Context, exitCode uint32) error {
- closed := uint64(1) + uint64(exitCode)<<32 // Store exitCode as high-order bits.
- if !r.closed.CompareAndSwap(0, closed) {
- return nil
- }
- err := r.store.CloseWithExitCode(ctx, exitCode)
- if r.cache == nil {
- // Close the engine if the cache is not configured, which means that this engine is scoped in this runtime.
- if errCloseEngine := r.store.Engine.Close(); errCloseEngine != nil {
- return errCloseEngine
- }
- }
- return err
-}