Files
wazero/internal/wasm/store_module_list.go
Takeshi Yoneda a4226906cf Deletes wasm.CallCtx (#1280)
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
2023-03-24 17:00:43 -07:00

148 lines
3.4 KiB
Go

package wasm
import (
"fmt"
"github.com/tetratelabs/wazero/api"
)
// moduleListNode is a node in a doubly linked list of names.
type moduleListNode struct {
name string
module *ModuleInstance
next, prev *moduleListNode
}
// setModule makes the module visible for import.
func (s *Store) setModule(m *ModuleInstance) error {
s.mux.Lock()
defer s.mux.Unlock()
node, ok := s.nameToNode[m.ModuleName]
if !ok {
return fmt.Errorf("module[%s] name has not been required", m.ModuleName)
}
node.module = m
return nil
}
// deleteModule makes the moduleName available for instantiation again.
func (s *Store) deleteModule(node *moduleListNode) error {
if node == nil {
return nil
}
s.mux.Lock()
defer s.mux.Unlock()
// remove this module name
if node.prev != nil {
node.prev.next = node.next
}
if node.next != nil {
node.next.prev = node.prev
}
if s.moduleList == node {
s.moduleList = node.next
}
// clear the node state so it does not enter any other branch
// on subsequent calls to deleteModule
node.prev = nil
node.next = nil
if node.name != "" {
delete(s.nameToNode, node.name)
}
return nil
}
// module returns the module of the given name or error if not in this store
func (s *Store) module(moduleName string) (*ModuleInstance, error) {
s.mux.RLock()
defer s.mux.RUnlock()
node, ok := s.nameToNode[moduleName]
if !ok {
return nil, fmt.Errorf("module[%s] not in store", moduleName)
}
if node.module == nil {
return nil, fmt.Errorf("module[%s] not set in store", moduleName)
}
return node.module, nil
}
// requireModules returns all instantiated modules whose names equal the keys in the input, or errs if any are missing.
func (s *Store) requireModules(moduleNames map[string]struct{}) (map[string]*ModuleInstance, error) {
ret := make(map[string]*ModuleInstance, len(moduleNames))
s.mux.RLock()
defer s.mux.RUnlock()
for n := range moduleNames {
node, ok := s.nameToNode[n]
if !ok {
return nil, fmt.Errorf("module[%s] not instantiated", n)
}
ret[n] = node.module
}
return ret, nil
}
// requireModuleName is a pre-flight check to reserve a module.
// This must be reverted on error with deleteModule if initialization fails.
func (s *Store) requireModuleName(moduleName string) (*moduleListNode, error) {
node := &moduleListNode{name: moduleName}
s.mux.Lock()
defer s.mux.Unlock()
if _, ok := s.nameToNode[moduleName]; ok {
return nil, fmt.Errorf("module[%s] has already been instantiated", moduleName)
}
// add the newest node to the moduleNamesList as the head.
node.next = s.moduleList
if node.next != nil {
node.next.prev = node
}
s.moduleList = node
s.nameToNode[moduleName] = node
return node, nil
}
func (s *Store) registerAnonymous() *moduleListNode {
node := &moduleListNode{name: ""}
s.mux.Lock()
defer s.mux.Unlock()
// add the newest node to the moduleNamesList as the head.
node.next = s.moduleList
if node.next != nil {
node.next.prev = node
}
s.moduleList = node
return node
}
// AliasModule aliases the instantiated module named `src` as `dst`.
//
// Note: This is only used for spectests.
func (s *Store) AliasModule(src, dst string) error {
s.mux.Lock()
defer s.mux.Unlock()
s.nameToNode[dst] = s.nameToNode[src]
return nil
}
// Module implements wazero.Runtime Module
func (s *Store) Module(moduleName string) api.Module {
m, err := s.module(moduleName)
if err != nil {
return nil
}
return m
}