wa-lang.org/wazero@v1.0.2/namespace.go (about) 1 package wazero 2 3 import ( 4 "context" 5 "fmt" 6 7 "wa-lang.org/wazero/api" 8 internalsys "wa-lang.org/wazero/internal/sys" 9 "wa-lang.org/wazero/internal/wasm" 10 "wa-lang.org/wazero/sys" 11 ) 12 13 // Namespace contains instantiated modules, which cannot conflict until they are closed. 14 type Namespace interface { 15 // Module returns exports from an instantiated module in this namespace or nil if there aren't any. 16 Module(moduleName string) api.Module 17 18 // InstantiateModule instantiates the module namespace or errs if the configuration was invalid. 19 // 20 // Here's an example: 21 // module, _ := n.InstantiateModule(ctx, compiled, wazero.NewModuleConfig().WithName("prod")) 22 // 23 // While CompiledModule is pre-validated, there are a few situations which can cause an error: 24 // - The module name is already in use. 25 // - The module has a table element initializer that resolves to an index outside the Table minimum size. 26 // - The module has a start function, and it failed to execute. 27 InstantiateModule(ctx context.Context, compiled CompiledModule, config ModuleConfig) (api.Module, error) 28 29 // CloseWithExitCode closes all modules initialized in this Namespace with the provided exit code. 30 // An error is returned if any module returns an error when closed. 31 // 32 // Here's an example: 33 // n := r.NewNamespace(ctx) 34 // defer n.CloseWithExitCode(ctx, 2) // This closes all modules in this Namespace. 35 // 36 // Everything below here can be closed, but will anyway due to above. 37 // _, _ = wasi_snapshot_preview1.InstantiateSnapshotPreview1(ctx, n) 38 // mod, _ := n.InstantiateModuleFromBinary(ctx, wasm) 39 // 40 // See Closer 41 CloseWithExitCode(ctx context.Context, exitCode uint32) error 42 43 // Closer closes modules initialized in this Namespace by delegating to CloseWithExitCode with an exit code of zero. 44 // 45 // Here's an example: 46 // n := r.NewNamespace(ctx) 47 // defer n.Close(ctx) // This closes all modules in this Namespace. 48 api.Closer 49 } 50 51 // namespace allows decoupling of public interfaces from internal representation. 52 type namespace struct { 53 store *wasm.Store 54 ns *wasm.Namespace 55 } 56 57 // Module implements Namespace.Module. 58 func (ns *namespace) Module(moduleName string) api.Module { 59 return ns.ns.Module(moduleName) 60 } 61 62 // InstantiateModule implements Namespace.InstantiateModule 63 func (ns *namespace) InstantiateModule( 64 ctx context.Context, 65 compiled CompiledModule, 66 mConfig ModuleConfig, 67 ) (mod api.Module, err error) { 68 code := compiled.(*compiledModule) 69 config := mConfig.(*moduleConfig) 70 71 var sysCtx *internalsys.Context 72 if sysCtx, err = config.toSysContext(); err != nil { 73 return 74 } 75 76 name := config.name 77 if name == "" && code.module.NameSection != nil && code.module.NameSection.ModuleName != "" { 78 name = code.module.NameSection.ModuleName 79 } 80 81 // Instantiate the module in the appropriate namespace. 82 mod, err = ns.store.Instantiate(ctx, ns.ns, code.module, name, sysCtx) 83 if err != nil { 84 // If there was an error, don't leak the compiled module. 85 if code.closeWithModule { 86 _ = code.Close(ctx) // don't overwrite the error 87 } 88 return 89 } 90 91 // Attach the code closer so that anything afterwards closes the compiled code when closing the module. 92 if code.closeWithModule { 93 mod.(*wasm.CallContext).CodeCloser = code 94 } 95 96 // Now, invoke any start functions, failing at first error. 97 for _, fn := range config.startFunctions { 98 start := mod.ExportedFunction(fn) 99 if start == nil { 100 continue 101 } 102 if _, err = start.Call(ctx); err != nil { 103 _ = mod.Close(ctx) // Don't leak the module on error. 104 if _, ok := err.(*sys.ExitError); ok { 105 return // Don't wrap an exit error 106 } 107 err = fmt.Errorf("module[%s] function[%s] failed: %w", name, fn, err) 108 return 109 } 110 } 111 return 112 } 113 114 // Close implements api.Closer embedded in Namespace. 115 func (ns *namespace) Close(ctx context.Context) error { 116 return ns.CloseWithExitCode(ctx, 0) 117 } 118 119 // CloseWithExitCode implements Namespace.CloseWithExitCode 120 func (ns *namespace) CloseWithExitCode(ctx context.Context, exitCode uint32) error { 121 return ns.ns.CloseWithExitCode(ctx, exitCode) 122 }