engine

package
v0.0.0-...-b118ce0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 6, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package engine provides the low-level WebAssembly Component Model runtime.

This package wraps wazero to provide Component Model semantics, including canonical ABI type lifting/lowering, asyncify support for async operations, and WASI preview1-to-preview2 adaptation.

Architecture

The engine package provides three main types:

WazeroEngine  - Creates and manages wazero runtime instances
WazeroModule  - Represents a compiled component, can create instances
WazeroInstance - A running component instance with exports

Component Instantiation Flow

  1. WazeroEngine.LoadModule() parses and validates the component binary
  2. WazeroModule holds the validated component and linker configuration
  3. WazeroModule.Instantiate() creates a WazeroInstance via the linker
  4. WazeroInstance provides Call methods for invoking exports

Canonical ABI

The canonical ABI defines how WIT types map to WASM core types:

WIT Type        Core Representation    Flat Count
─────────────────────────────────────────────────
bool, u8-u32    i32                    1
u64, s64        i64                    1
f32             f32                    1
f64             f64                    1
string          (ptr, len) as i32×2    2
list<T>         (ptr, len) as i32×2    2
record          flattened fields       sum of fields
variant         (disc, payload)        1 + max(cases)
option<T>       variant with none/some varies
result<T,E>     variant with ok/err    varies

When flat count exceeds MaxFlatParams (16) or MaxFlatResults (1), values are passed via linear memory using a return pointer (retptr).

Asyncify Support

Asyncify enables cooperative multitasking in WASM. Modules compiled with wasm-opt --asyncify can suspend execution (unwind) and resume later (rewind).

Usage:

if err := inst.EnableAsyncify(config); err != nil {
    log.Fatal(err)
}

// In host function that needs to block:
asyncify := inst.Asyncify()
if asyncify.State() == StateNormal {
    asyncify.StartUnwind(ctx) // Save stack, return to caller
    return                     // Guest sees function return
}
// On rewind, execution continues here
asyncify.StopRewind(ctx)
// Perform actual work, return result

WASI Adaptation

The engine provides automatic WASI preview1-to-preview2 adaptation for components that import preview1 interfaces. This allows legacy modules to run with modern WASI preview2 host implementations.

Resource Table

Resources (handles) are managed via ResourceTable, which maps integer handles to Go values. The table supports borrow semantics for the Component Model's resource lifecycle.

Thread Safety

WazeroEngine and WazeroModule are safe for concurrent use. WazeroInstance is NOT thread-safe and should be used by a single goroutine.

Experimental Features

Threads/Atomics: Enable via EngineConfig.EnableThreads. This enables the WebAssembly threads proposal (shared memory, atomic operations). Note that atomic operations are guest-only and not exposed to host functions.

Known Limitations

Memory64: The WebAssembly Memory64 proposal (64-bit memory addressing) is not supported. This limitation comes from the underlying wazero runtime (v1.10.1) which does not implement Memory64. Implementation would require:

  • wazero upstream Memory64 support
  • Updates to memory access code for uint64 addresses
  • Canonical ABI changes (pointer types become i64)

Most users should use the runtime package for a simpler API. This package is for advanced use cases requiring direct control.

Index

Constants

View Source
const (
	MaxFlatResults = transcoder.MaxFlatResults

	CabiRealloc = "cabi_realloc"
	CabiFree    = "cabi_free"
)
View Source
const AsyncifyDataAddr uint32 = 16
View Source
const AsyncifyDefaultStackSize uint32 = 1024

Variables

View Source
var IsAsyncified = asyncify.IsAsyncified

IsAsyncified checks if a WASM module has been asyncified.

Functions

func InstantiateWASIWithAdapter

func InstantiateWASIWithAdapter(ctx context.Context, r wazero.Runtime) (api.Module, error)

InstantiateWASIWithAdapter instantiates WASI preview1 with adapter functions required by componentize-py and similar tools that use the component model adapter.

func Logger

func Logger() *zap.Logger

Logger returns the engine's logger instance. It uses a no-op logger by default.

func MakeAsyncHandler

func MakeAsyncHandler(createOp func(ctx context.Context, mod api.Module, stack []uint64) PendingOp) api.GoModuleFunc

MakeAsyncHandler wraps an operation factory into a suspend/resume-aware handler.

func Resume

func Resume(ctx context.Context) (uint64, error)

Resume gets the operation result and stops rewinding. Called during rewind.

func Suspend

func Suspend(ctx context.Context, op PendingOp) error

Suspend registers op and starts unwinding. Called by host handlers.

func WithAsyncify

func WithAsyncify(ctx context.Context, a *Asyncify) context.Context

func WithScheduler

func WithScheduler(ctx context.Context, s *Scheduler) context.Context

Types

type Asyncify

type Asyncify struct {
	// contains filtered or unexported fields
}

Asyncify implements the Binaryen asyncify protocol (wasm-opt --asyncify).

States: 0=Normal, 1=Unwinding (saving stack), 2=Rewinding (restoring stack)

Memory layout at dataAddr:

  • [0:4] stack pointer (grows upward from dataAddr+8)
  • [4:8] stack end
  • [8:stackSize] stack data

func GetAsyncify

func GetAsyncify(ctx context.Context) *Asyncify

func NewAsyncify

func NewAsyncify() *Asyncify

func (*Asyncify) GetState

func (a *Asyncify) GetState(_ context.Context) int32

func (*Asyncify) Init

func (a *Asyncify) Init(mod api.Module) error

Init initializes asyncify. Call after module instantiation.

func (*Asyncify) IsNormal

func (a *Asyncify) IsNormal(_ context.Context) bool

func (*Asyncify) IsRewinding

func (a *Asyncify) IsRewinding(_ context.Context) bool

func (*Asyncify) IsUnwinding

func (a *Asyncify) IsUnwinding(_ context.Context) bool

func (*Asyncify) ResetStack

func (a *Asyncify) ResetStack()

ResetStack resets the stack pointer. Call before each new async operation.

func (*Asyncify) SetDataAddr

func (a *Asyncify) SetDataAddr(addr uint32)

func (*Asyncify) SetStackSize

func (a *Asyncify) SetStackSize(size uint32)

func (*Asyncify) StartRewind

func (a *Asyncify) StartRewind(ctx context.Context) error

func (*Asyncify) StartUnwind

func (a *Asyncify) StartUnwind(ctx context.Context) error

func (*Asyncify) StopRewind

func (a *Asyncify) StopRewind(ctx context.Context) error

func (*Asyncify) StopUnwind

func (a *Asyncify) StopUnwind(ctx context.Context) error

func (*Asyncify) SyncState

func (a *Asyncify) SyncState(ctx context.Context) int32

SyncState reads state from WASM module. Allocates; use only for debugging.

type AsyncifyConfig

type AsyncifyConfig struct {
	StackSize uint32
	DataAddr  uint32
}

type CallSession

type CallSession struct {
	// contains filtered or unexported fields
}

CallSession represents an in-progress async function call. Use StartCall to create, Step to advance, and LiftResult to extract results.

func (*CallSession) LiftResult

func (cs *CallSession) LiftResult(ctx context.Context, rawResults []uint64) (any, error)

LiftResult converts raw wasm results to typed Go values after StepDone.

func (*CallSession) Step

func (cs *CallSession) Step(ctx context.Context, yr *YieldResult) (StepResult, error)

Step advances execution. Pass nil for the first call, or a YieldResult to resume.

type CommandID

type CommandID = uint16

type CompileConfig

type CompileConfig struct {
	// EnableAsyncify enables automatic asyncify transformation for components.
	EnableAsyncify bool
}

CompileConfig holds configuration for pre-compilation

type Config

type Config struct {
	// MemoryLimitPages sets the maximum memory per instance in pages (64KB each).
	// 0 means default (65536 pages = 4GB).
	// 256 = 16MB, 1024 = 64MB, 4096 = 256MB
	MemoryLimitPages uint32

	// EnableThreads enables the WebAssembly threads proposal (experimental).
	// This allows atomic operations and shared memory within WASM modules.
	// Note: Thread operations are guest-only and not exposed to host functions.
	EnableThreads bool
}

Config holds configuration for engine creation

type ErrorKind

type ErrorKind string

ErrorKind categorizes errors for integration with external error handling.

const (
	KindUnknown           ErrorKind = "Unknown"
	KindCanceled          ErrorKind = "Canceled"
	KindTimeout           ErrorKind = "Timeout"
	KindInternal          ErrorKind = "Internal"
	KindInvalid           ErrorKind = "Invalid"
	KindResourceExhausted ErrorKind = "ResourceExhausted"
)

func ClassifyError

func ClassifyError(err error) ErrorKind

type HostFunc

type HostFunc struct {
	Handler   any
	Wrapper   *LowerWrapper
	Raw       api.GoModuleFunc
	Namespace string
	Name      string
	ParamVT   []api.ValueType
	ResultVT  []api.ValueType
	Typed     bool
	IsAsync   bool
}

type InstanceConfig

type InstanceConfig struct {
	Name            string
	AsyncifyImports []string
	EnableAsyncify  bool
}

InstanceConfig holds configuration for module instantiation

type LowerWrapper

type LowerWrapper struct {
	// contains filtered or unexported fields
}

LowerWrapper wraps a Go function for Canonical ABI lowering.

func NewLowerWrapper

func NewLowerWrapper(def *component.LowerDef, handler any) (*LowerWrapper, error)

func (*LowerWrapper) BuildRawFunc

func (w *LowerWrapper) BuildRawFunc() api.GoModuleFunc

func (*LowerWrapper) FlatParamTypes

func (w *LowerWrapper) FlatParamTypes() []api.ValueType

func (*LowerWrapper) FlatResultTypes

func (w *LowerWrapper) FlatResultTypes() []api.ValueType

func (*LowerWrapper) FlatSignature

func (w *LowerWrapper) FlatSignature() (paramCount, resultCount int)

func (*LowerWrapper) Name

func (w *LowerWrapper) Name() string

func (*LowerWrapper) ValidateHandler

func (w *LowerWrapper) ValidateHandler() error

ValidateHandler checks if the Go handler matches the WIT signature. Returns nil if Params is nil (unknown types from failed component parsing).

type PendingOp

type PendingOp interface {
	CmdID() CommandID
	Execute(ctx context.Context) (uint64, error)
}

PendingOp represents an async operation yielded during suspension.

type Scheduler

type Scheduler struct {
	// contains filtered or unexported fields
}

Scheduler manages async execution with step-based control for integration with external event loops.

func GetScheduler

func GetScheduler(ctx context.Context) *Scheduler

func NewScheduler

func NewScheduler(asyncify *Asyncify) *Scheduler

func (*Scheduler) ClearPending

func (s *Scheduler) ClearPending()

func (*Scheduler) Execute

func (s *Scheduler) Execute(ctx context.Context, fn api.Function, args ...uint64) error

Execute initializes execution. Call Step() to advance.

func (*Scheduler) GetResult

func (s *Scheduler) GetResult() (uint64, error)

func (*Scheduler) Reset

func (s *Scheduler) Reset()

func (*Scheduler) Run

func (s *Scheduler) Run(ctx context.Context, fn api.Function, args ...uint64) ([]uint64, error)

Run executes with internal event loop. Convenience wrapper over Execute/Step.

func (*Scheduler) SetPending

func (s *Scheduler) SetPending(op PendingOp)

func (*Scheduler) Step

func (s *Scheduler) Step(ctx context.Context, yr *YieldResult) (StepResult, error)

Step advances execution. Pass nil for first call, or YieldResult to resume.

type StepResult

type StepResult struct {
	PendingOp PendingOp
	Error     error
	ErrorKind ErrorKind
	Results   []uint64
	Status    StepStatus
}

type StepStatus

type StepStatus int
const (
	StepContinue StepStatus = iota // yielded an operation, expects resume
	StepIdle                       // waiting for external message
	StepDone                       // execution complete
)

type WazeroEngine

type WazeroEngine struct {
	// contains filtered or unexported fields
}

WazeroEngine implements Engine using wazero runtime

func NewWazeroEngine

func NewWazeroEngine(ctx context.Context) (*WazeroEngine, error)

NewWazeroEngine creates a new wazero-based engine

func NewWazeroEngineWithConfig

func NewWazeroEngineWithConfig(ctx context.Context, cfg *Config) (*WazeroEngine, error)

NewWazeroEngineWithConfig creates a new engine with custom configuration

func (*WazeroEngine) Close

func (e *WazeroEngine) Close(ctx context.Context) error

func (*WazeroEngine) InitWASI

func (e *WazeroEngine) InitWASI(ctx context.Context) error

InitWASI instantiates the WASI singleton for this engine's runtime. Safe for concurrent calls from multiple modules sharing the same engine.

func (*WazeroEngine) LoadModule

func (e *WazeroEngine) LoadModule(ctx context.Context, wasmBytes []byte) (*WazeroModule, error)

type WazeroInstance

type WazeroInstance struct {
	// contains filtered or unexported fields
}

WazeroInstance is a running WASM instance. It is NOT safe for concurrent use from multiple goroutines. Each goroutine should have its own Instance, or access must be synchronized externally.

func (*WazeroInstance) Asyncify

func (i *WazeroInstance) Asyncify() *Asyncify

Asyncify returns the asyncify runtime if enabled.

func (*WazeroInstance) CallInto

func (i *WazeroInstance) CallInto(ctx context.Context, funcName string, paramTypes []wit.Type, resultTypes []wit.Type, result any, params ...any) error

CallInto decodes results directly into caller's memory without intermediate allocation. result must be a pointer to the target type (e.g., *string, *uint32, *MyStruct). For void returns, pass nil. For strings, the result points directly into WASM memory and is only valid while the instance is alive.

func (*WazeroInstance) CallWithLift

func (i *WazeroInstance) CallWithLift(ctx context.Context, funcName string, params ...any) (any, error)

CallWithLift calls a function using cached lift information from canon registry. It is faster than Call for repeated invocations as it caches lookup results.

func (*WazeroInstance) CallWithTypes

func (i *WazeroInstance) CallWithTypes(ctx context.Context, funcName string, paramTypes []wit.Type, resultTypes []wit.Type, params ...any) (any, error)

CallWithTypes calls a WASM function with explicit WIT type information

func (*WazeroInstance) Close

func (i *WazeroInstance) Close(ctx context.Context) error

func (*WazeroInstance) EnableAsyncify

func (i *WazeroInstance) EnableAsyncify(config AsyncifyConfig) error

EnableAsyncify initializes asyncify support for this instance. Call EnableAsyncify after instantiation but before calling async functions. The module must have been compiled with asyncify (wasm-opt --asyncify).

func (*WazeroInstance) GetExportedFunction

func (i *WazeroInstance) GetExportedFunction(name string) api.Function

GetExportedFunction returns an exported function by name (public wrapper).

func (*WazeroInstance) MemorySize

func (i *WazeroInstance) MemorySize() uint32

MemorySize returns the current linear memory size in bytes, or 0 if no memory.

func (*WazeroInstance) RunAsync

func (i *WazeroInstance) RunAsync(ctx context.Context, name string, args ...uint64) ([]uint64, error)

RunAsync executes a function with asyncify event loop support. It returns after the function completes, processing any async operations.

func (*WazeroInstance) Scheduler

func (i *WazeroInstance) Scheduler() *Scheduler

Scheduler returns the async scheduler if enabled.

func (*WazeroInstance) StartCall

func (i *WazeroInstance) StartCall(ctx context.Context, funcName string, params ...any) (*CallSession, error)

StartCall prepares a call session by lowering params. Does not execute yet. Call Step to advance execution.

type WazeroMemory

type WazeroMemory struct {
	// contains filtered or unexported fields
}

WazeroMemory wraps wazero memory to implement wasmruntime.Memory

func (*WazeroMemory) Read

func (m *WazeroMemory) Read(offset uint32, length uint32) ([]byte, error)

func (*WazeroMemory) ReadU8

func (m *WazeroMemory) ReadU8(offset uint32) (uint8, error)

func (*WazeroMemory) ReadU16

func (m *WazeroMemory) ReadU16(offset uint32) (uint16, error)

func (*WazeroMemory) ReadU32

func (m *WazeroMemory) ReadU32(offset uint32) (uint32, error)

func (*WazeroMemory) ReadU64

func (m *WazeroMemory) ReadU64(offset uint32) (uint64, error)

func (*WazeroMemory) Size

func (m *WazeroMemory) Size() uint32

func (*WazeroMemory) Write

func (m *WazeroMemory) Write(offset uint32, data []byte) error

func (*WazeroMemory) WriteU8

func (m *WazeroMemory) WriteU8(offset uint32, value uint8) error

func (*WazeroMemory) WriteU16

func (m *WazeroMemory) WriteU16(offset uint32, value uint16) error

func (*WazeroMemory) WriteU32

func (m *WazeroMemory) WriteU32(offset uint32, value uint32) error

func (*WazeroMemory) WriteU64

func (m *WazeroMemory) WriteU64(offset uint32, value uint64) error

type WazeroModule

type WazeroModule struct {
	// contains filtered or unexported fields
}

WazeroModule is a compiled WASM module

func (*WazeroModule) AsyncifyImports

func (m *WazeroModule) AsyncifyImports() []string

AsyncifyImports returns the list of import names that require asyncify transformation. Uses intersection logic: a function is async only if both the host registration and the component canon lower agree. For core modules (no canon registry), trusts the host flag.

func (*WazeroModule) Compile

func (m *WazeroModule) Compile(ctx context.Context, cfg *CompileConfig) error

Compile pre-compiles the module and validates imports. Call Compile at registration time to fail fast on missing imports (strict mode). It returns error if compilation fails or imports cannot be satisfied. After Compile, Instantiate will reuse the cached InstancePre.

func (*WazeroModule) ExportNames

func (m *WazeroModule) ExportNames() []string

ExportNames returns the names of all exported functions

func (*WazeroModule) FindLift

func (m *WazeroModule) FindLift(name string) *component.LiftDef

FindLift returns the lift definition for an exported function

func (*WazeroModule) Instantiate

func (m *WazeroModule) Instantiate(ctx context.Context) (*WazeroInstance, error)

func (*WazeroModule) InstantiateWithConfig

func (m *WazeroModule) InstantiateWithConfig(ctx context.Context, cfg *InstanceConfig) (*WazeroInstance, error)

InstantiateWithConfig creates an instance with custom configuration

func (*WazeroModule) RegisterHostFuncTyped

func (m *WazeroModule) RegisterHostFuncTyped(namespace, name string, handler any) error

RegisterHostFuncTyped registers a typed Go function that will be auto-wrapped using the Canon ABI. The handler signature is validated against the WIT import. It uses semver matching: a host at version X.Y.Z can satisfy imports for X.Y.W where W <= Z.

func (*WazeroModule) RegisterHostFuncTypedAsync

func (m *WazeroModule) RegisterHostFuncTypedAsync(namespace, name string, handler any) error

RegisterHostFuncTypedAsync registers a typed Go function as an async host function. Same as RegisterHostFuncTyped but marks the function as async (yields during execution).

type YieldResult

type YieldResult struct {
	Error error
	Value uint64
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL