github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/wasm/function_definition.go (about)

     1  package wasm
     2  
     3  import (
     4  	"github.com/wasilibs/wazerox/api"
     5  	"github.com/wasilibs/wazerox/internal/internalapi"
     6  	"github.com/wasilibs/wazerox/internal/wasmdebug"
     7  )
     8  
     9  // ImportedFunctions returns the definitions of each imported function.
    10  //
    11  // Note: Unlike ExportedFunctions, there is no unique constraint on imports.
    12  func (m *Module) ImportedFunctions() (ret []api.FunctionDefinition) {
    13  	for i := uint32(0); i < m.ImportFunctionCount; i++ {
    14  		ret = append(ret, m.FunctionDefinition(i))
    15  	}
    16  	return
    17  }
    18  
    19  // ExportedFunctions returns the definitions of each exported function.
    20  func (m *Module) ExportedFunctions() map[string]api.FunctionDefinition {
    21  	ret := map[string]api.FunctionDefinition{}
    22  	for i := range m.ExportSection {
    23  		exp := &m.ExportSection[i]
    24  		if exp.Type == ExternTypeFunc {
    25  			d := m.FunctionDefinition(exp.Index)
    26  			ret[exp.Name] = d
    27  		}
    28  	}
    29  	return ret
    30  }
    31  
    32  // FunctionDefinition returns the FunctionDefinition for the given `index`.
    33  func (m *Module) FunctionDefinition(index Index) *FunctionDefinition {
    34  	// TODO: function initialization is lazy, but bulk. Make it per function.
    35  	m.buildFunctionDefinitions()
    36  	return &m.FunctionDefinitionSection[index]
    37  }
    38  
    39  // buildFunctionDefinitions generates function metadata that can be parsed from
    40  // the module. This must be called after all validation.
    41  func (m *Module) buildFunctionDefinitions() {
    42  	m.functionDefinitionSectionInitOnce.Do(m.buildFunctionDefinitionsOnce)
    43  }
    44  
    45  func (m *Module) buildFunctionDefinitionsOnce() {
    46  	var moduleName string
    47  	var functionNames NameMap
    48  	var localNames, resultNames IndirectNameMap
    49  	if m.NameSection != nil {
    50  		moduleName = m.NameSection.ModuleName
    51  		functionNames = m.NameSection.FunctionNames
    52  		localNames = m.NameSection.LocalNames
    53  		resultNames = m.NameSection.ResultNames
    54  	}
    55  
    56  	importCount := m.ImportFunctionCount
    57  	m.FunctionDefinitionSection = make([]FunctionDefinition, importCount+uint32(len(m.FunctionSection)))
    58  
    59  	importFuncIdx := Index(0)
    60  	for i := range m.ImportSection {
    61  		imp := &m.ImportSection[i]
    62  		if imp.Type != ExternTypeFunc {
    63  			continue
    64  		}
    65  
    66  		def := &m.FunctionDefinitionSection[importFuncIdx]
    67  		def.importDesc = imp
    68  		def.index = importFuncIdx
    69  		def.Functype = &m.TypeSection[imp.DescFunc]
    70  		importFuncIdx++
    71  	}
    72  
    73  	for codeIndex, typeIndex := range m.FunctionSection {
    74  		code := &m.CodeSection[codeIndex]
    75  		idx := importFuncIdx + Index(codeIndex)
    76  		def := &m.FunctionDefinitionSection[idx]
    77  		def.index = idx
    78  		def.Functype = &m.TypeSection[typeIndex]
    79  		def.goFunc = code.GoFunc
    80  	}
    81  
    82  	n, nLen := 0, len(functionNames)
    83  	for i := range m.FunctionDefinitionSection {
    84  		d := &m.FunctionDefinitionSection[i]
    85  		// The function name section begins with imports, but can be sparse.
    86  		// This keeps track of how far in the name section we've searched.
    87  		funcIdx := d.index
    88  		var funcName string
    89  		for ; n < nLen; n++ {
    90  			next := &functionNames[n]
    91  			if next.Index > funcIdx {
    92  				break // we have function names, but starting at a later index.
    93  			} else if next.Index == funcIdx {
    94  				funcName = next.Name
    95  				break
    96  			}
    97  		}
    98  
    99  		d.moduleName = moduleName
   100  		d.name = funcName
   101  		d.Debugname = wasmdebug.FuncName(moduleName, funcName, funcIdx)
   102  		d.paramNames = paramNames(localNames, funcIdx, len(d.Functype.Params))
   103  		d.resultNames = paramNames(resultNames, funcIdx, len(d.Functype.Results))
   104  
   105  		for i := range m.ExportSection {
   106  			e := &m.ExportSection[i]
   107  			if e.Type == ExternTypeFunc && e.Index == funcIdx {
   108  				d.exportNames = append(d.exportNames, e.Name)
   109  			}
   110  		}
   111  	}
   112  }
   113  
   114  // FunctionDefinition implements api.FunctionDefinition
   115  type FunctionDefinition struct {
   116  	internalapi.WazeroOnlyType
   117  	moduleName string
   118  	index      Index
   119  	name       string
   120  	// Debugname is exported for testing purpose.
   121  	Debugname string
   122  	goFunc    interface{}
   123  	// Functype is exported for testing purpose.
   124  	Functype    *FunctionType
   125  	importDesc  *Import
   126  	exportNames []string
   127  	paramNames  []string
   128  	resultNames []string
   129  }
   130  
   131  // ModuleName implements the same method as documented on api.FunctionDefinition.
   132  func (f *FunctionDefinition) ModuleName() string {
   133  	return f.moduleName
   134  }
   135  
   136  // Index implements the same method as documented on api.FunctionDefinition.
   137  func (f *FunctionDefinition) Index() uint32 {
   138  	return f.index
   139  }
   140  
   141  // Name implements the same method as documented on api.FunctionDefinition.
   142  func (f *FunctionDefinition) Name() string {
   143  	return f.name
   144  }
   145  
   146  // DebugName implements the same method as documented on api.FunctionDefinition.
   147  func (f *FunctionDefinition) DebugName() string {
   148  	return f.Debugname
   149  }
   150  
   151  // Import implements the same method as documented on api.FunctionDefinition.
   152  func (f *FunctionDefinition) Import() (moduleName, name string, isImport bool) {
   153  	if f.importDesc != nil {
   154  		importDesc := f.importDesc
   155  		moduleName, name, isImport = importDesc.Module, importDesc.Name, true
   156  	}
   157  	return
   158  }
   159  
   160  // ExportNames implements the same method as documented on api.FunctionDefinition.
   161  func (f *FunctionDefinition) ExportNames() []string {
   162  	return f.exportNames
   163  }
   164  
   165  // GoFunction implements the same method as documented on api.FunctionDefinition.
   166  func (f *FunctionDefinition) GoFunction() interface{} {
   167  	return f.goFunc
   168  }
   169  
   170  // ParamTypes implements api.FunctionDefinition ParamTypes.
   171  func (f *FunctionDefinition) ParamTypes() []ValueType {
   172  	return f.Functype.Params
   173  }
   174  
   175  // ParamNames implements the same method as documented on api.FunctionDefinition.
   176  func (f *FunctionDefinition) ParamNames() []string {
   177  	return f.paramNames
   178  }
   179  
   180  // ResultTypes implements api.FunctionDefinition ResultTypes.
   181  func (f *FunctionDefinition) ResultTypes() []ValueType {
   182  	return f.Functype.Results
   183  }
   184  
   185  // ResultNames implements the same method as documented on api.FunctionDefinition.
   186  func (f *FunctionDefinition) ResultNames() []string {
   187  	return f.resultNames
   188  }