github.com/taubyte/vm-wasm-utils@v1.0.2/module.go (about)

     1  package wasm
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha256"
     6  	"errors"
     7  	"fmt"
     8  	"reflect"
     9  	"sort"
    10  	"strings"
    11  
    12  	"github.com/taubyte/vm-wasm-utils/ieee754"
    13  	"github.com/taubyte/vm-wasm-utils/leb128"
    14  	"github.com/tetratelabs/wazero/api"
    15  	experimental "github.com/tetratelabs/wazero/experimental"
    16  )
    17  
    18  // DecodeModule parses the WebAssembly Binary Format (%.wasm) into a Module. This function returns when the input is
    19  // exhausted or an error occurs. The result can be initialized for use via Store.Instantiate.
    20  //
    21  // Here's a description of the return values:
    22  // * result is the module parsed or nil on error
    23  // * err is a FormatError invoking the parser, dangling block comments or unexpected characters.
    24  // See binary.DecodeModule and text.DecodeModule
    25  type DecodeModule func(
    26  	wasm []byte,
    27  	enabledFeatures Features,
    28  	memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32),
    29  ) (result *Module, err error)
    30  
    31  // EncodeModule encodes the given module into a byte slice depending on the format of the implementation.
    32  // See binary.EncodeModule
    33  type EncodeModule func(m *Module) (bytes []byte)
    34  
    35  // Module is a WebAssembly binary representation.
    36  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#modules%E2%91%A8
    37  //
    38  // Differences from the specification:
    39  // * NameSection is the only key ("name") decoded from the SectionIDCustom.
    40  // * ExportSection is represented as a map for lookup convenience.
    41  // * Code.GoFunc is contains any go `func`. It may be present when Code.Body is not.
    42  type Module struct {
    43  	// TypeSection contains the unique FunctionType of functions imported or defined in this module.
    44  	//
    45  	// Note: Currently, there is no type ambiguity in the index as WebAssembly 1.0 only defines function type.
    46  	// In the future, other types may be introduced to support Features such as module linking.
    47  	//
    48  	// Note: In the Binary Format, this is SectionIDType.
    49  	//
    50  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#types%E2%91%A0%E2%91%A0
    51  	TypeSection []*FunctionType
    52  
    53  	// ImportSection contains imported functions, tables, memories or globals required for instantiation
    54  	// (Store.Instantiate).
    55  	//
    56  	// Note: there are no unique constraints relating to the two-level namespace of Import.Module and Import.Name.
    57  	//
    58  	// Note: In the Binary Format, this is SectionIDImport.
    59  	//
    60  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#import-section%E2%91%A0
    61  	ImportSection []*Import
    62  
    63  	// FunctionSection contains the index in TypeSection of each function defined in this module.
    64  	//
    65  	// Note: The function Index namespace begins with imported functions and ends with those defined in this module.
    66  	// For example, if there are two imported functions and one defined in this module, the function Index 3 is defined
    67  	// in this module at FunctionSection[0].
    68  	//
    69  	// Note: FunctionSection is index correlated with the CodeSection. If given the same position, ex. 2, a function
    70  	// type is at TypeSection[FunctionSection[2]], while its locals and body are at CodeSection[2].
    71  	//
    72  	// Note: In the Binary Format, this is SectionIDFunction.
    73  	//
    74  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-section%E2%91%A0
    75  	FunctionSection []Index
    76  
    77  	// TableSection contains each table defined in this module.
    78  	//
    79  	// Note: The table Index namespace begins with imported tables and ends with those defined in this module.
    80  	// For example, if there are two imported tables and one defined in this module, the table Index 3 is defined in
    81  	// this module at TableSection[0].
    82  	//
    83  	// Note: Version 1.0 (20191205) of the WebAssembly spec allows at most one table definition per module, so the
    84  	// length of the TableSection can be zero or one, and can only be one if there is no imported table.
    85  	//
    86  	// Note: In the Binary Format, this is SectionIDTable.
    87  	//
    88  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-section%E2%91%A0
    89  	TableSection []*Table
    90  
    91  	// MemorySection contains each memory defined in this module.
    92  	//
    93  	// Note: The memory Index namespace begins with imported memories and ends with those defined in this module.
    94  	// For example, if there are two imported memories and one defined in this module, the memory Index 3 is defined in
    95  	// this module at TableSection[0].
    96  	//
    97  	// Note: Version 1.0 (20191205) of the WebAssembly spec allows at most one memory definition per module, so the
    98  	// length of the MemorySection can be zero or one, and can only be one if there is no imported memory.
    99  	//
   100  	// Note: In the Binary Format, this is SectionIDMemory.
   101  	//
   102  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0
   103  	MemorySection *Memory
   104  
   105  	// GlobalSection contains each global defined in this module.
   106  	//
   107  	// Global indexes are offset by any imported globals because the global index space begins with imports, followed by
   108  	// ones defined in this module. For example, if there are two imported globals and three defined in this module, the
   109  	// global at index 3 is defined in this module at GlobalSection[0].
   110  	//
   111  	// Note: In the Binary Format, this is SectionIDGlobal.
   112  	//
   113  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-section%E2%91%A0
   114  	GlobalSection []*Global
   115  
   116  	// ExportSection contains each export defined in this module.
   117  	//
   118  	// Note: In the Binary Format, this is SectionIDExport.
   119  	//
   120  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A0
   121  	ExportSection []*Export
   122  
   123  	// StartSection is the index of a function to call before returning from Store.Instantiate.
   124  	//
   125  	// Note: The index here is not the position in the FunctionSection, rather in the function index namespace, which
   126  	// begins with imported functions.
   127  	//
   128  	// Note: In the Binary Format, this is SectionIDStart.
   129  	//
   130  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-section%E2%91%A0
   131  	StartSection *Index
   132  
   133  	// Note: In the Binary Format, this is SectionIDElement.
   134  	ElementSection []*ElementSegment
   135  
   136  	// CodeSection is index-correlated with FunctionSection and contains each
   137  	// function's locals and body.
   138  	//
   139  	// When present, the HostFunctionSection of the same index must be nil.
   140  	//
   141  	// Note: In the Binary Format, this is SectionIDCode.
   142  	//
   143  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0
   144  	CodeSection []*Code
   145  
   146  	// Note: In the Binary Format, this is SectionIDData.
   147  	DataSection []*DataSegment
   148  
   149  	// NameSection is set when the SectionIDCustom "name" was successfully decoded from the binary format.
   150  	//
   151  	// Note: This is the only SectionIDCustom defined in the WebAssembly 1.0 (20191205) Binary Format.
   152  	// Others are skipped as they are not used in wazero.
   153  	//
   154  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
   155  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0
   156  	NameSection *NameSection
   157  
   158  	// validatedActiveElementSegments are built on Validate when
   159  	// SectionIDElement is non-empty and all inputs are valid.
   160  	//
   161  	// Note: elementSegments retain Module.ElementSection order. Since an
   162  	// ElementSegment can overlap with another, order preservation ensures a
   163  	// consistent initialization result.
   164  	//
   165  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-instances%E2%91%A0
   166  	validatedActiveElementSegments []*validatedActiveElementSegment
   167  
   168  	// DataCountSection is the optional section and holds the number of data segments in the data section.
   169  	//
   170  	// Note: This may exist in WebAssembly 2.0 or WebAssembly 1.0 with FeatureBulkMemoryOperations.
   171  	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section
   172  	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
   173  	DataCountSection *uint32
   174  
   175  	// ID is the sha256 value of the source wasm and is used for caching.
   176  	ID ModuleID
   177  
   178  	// FunctionDefinitionSection is a wazero specific section built on Validate.
   179  	FunctionDefinitionSection []*FunctionDefinition
   180  }
   181  
   182  // ModuleID represents sha256 hash value uniquely assigned to Module.
   183  type ModuleID = [sha256.Size]byte
   184  
   185  // The wazero specific limitation described at RATIONALE.md.
   186  // TL;DR; We multiply by 8 (to get offsets in bytes) and the multiplication result must be less than 32bit max
   187  const (
   188  	MaximumGlobals       = uint32(1 << 27)
   189  	MaximumFunctionIndex = uint32(1 << 27)
   190  	MaximumTableIndex    = uint32(1 << 27)
   191  )
   192  
   193  // AssignModuleID calculates a sha256 checksum on `wasm` and set Module.ID to the result.
   194  func (m *Module) AssignModuleID(wasm []byte) {
   195  	m.ID = sha256.Sum256(wasm)
   196  }
   197  
   198  // TypeOfFunction returns the wasm.SectionIDType index for the given function namespace index or nil.
   199  // Note: The function index namespace is preceded by imported functions.
   200  // TODO: Returning nil should be impossible when decode results are validated. Validate decode before back-filling tests.
   201  func (m *Module) TypeOfFunction(funcIdx Index) *FunctionType {
   202  	typeSectionLength := uint32(len(m.TypeSection))
   203  	if typeSectionLength == 0 {
   204  		return nil
   205  	}
   206  	funcImportCount := Index(0)
   207  	for _, im := range m.ImportSection {
   208  		if im.Type == ExternTypeFunc {
   209  			if funcIdx == funcImportCount {
   210  				if im.DescFunc >= typeSectionLength {
   211  					return nil
   212  				}
   213  				return m.TypeSection[im.DescFunc]
   214  			}
   215  			funcImportCount++
   216  		}
   217  	}
   218  	funcSectionIdx := funcIdx - funcImportCount
   219  	if funcSectionIdx >= uint32(len(m.FunctionSection)) {
   220  		return nil
   221  	}
   222  	typeIdx := m.FunctionSection[funcSectionIdx]
   223  	if typeIdx >= typeSectionLength {
   224  		return nil
   225  	}
   226  	return m.TypeSection[typeIdx]
   227  }
   228  
   229  func (m *Module) Validate(enabledFeatures Features) error {
   230  	for _, tp := range m.TypeSection {
   231  		tp.CacheNumInUint64()
   232  	}
   233  
   234  	if err := m.validateStartSection(); err != nil {
   235  		return err
   236  	}
   237  
   238  	functions, globals, memory, tables, err := m.AllDeclarations()
   239  	if err != nil {
   240  		return err
   241  	}
   242  
   243  	if err = m.validateImports(enabledFeatures); err != nil {
   244  		return err
   245  	}
   246  
   247  	if err = m.validateGlobals(globals, uint32(len(functions)), MaximumGlobals); err != nil {
   248  		return err
   249  	}
   250  
   251  	if err = m.validateMemory(memory, globals, enabledFeatures); err != nil {
   252  		return err
   253  	}
   254  
   255  	if err = m.validateExports(enabledFeatures, functions, globals, memory, tables); err != nil {
   256  		return err
   257  	}
   258  
   259  	if m.CodeSection != nil {
   260  		if err = m.validateFunctions(enabledFeatures, functions, globals, memory, tables, MaximumFunctionIndex); err != nil {
   261  			return err
   262  		}
   263  	} // No need to validate host functions as NewHostModule validates
   264  
   265  	if _, err = m.validateTable(enabledFeatures, tables, MaximumTableIndex); err != nil {
   266  		return err
   267  	}
   268  
   269  	if err = m.validateDataCountSection(); err != nil {
   270  		return err
   271  	}
   272  	return nil
   273  }
   274  
   275  func (m *Module) validateStartSection() error {
   276  	// Check the start function is valid.
   277  	// TODO: this should be verified during decode so that errors have the correct source positions
   278  	if m.StartSection != nil {
   279  		startIndex := *m.StartSection
   280  		ft := m.TypeOfFunction(startIndex)
   281  		if ft == nil { // TODO: move this check to decoder so that a module can never be decoded invalidly
   282  			return fmt.Errorf("invalid start function: func[%d] has an invalid type", startIndex)
   283  		}
   284  		if len(ft.Params) > 0 || len(ft.Results) > 0 {
   285  			return fmt.Errorf("invalid start function: func[%d] must have an empty (nullary) signature: %s", startIndex, ft)
   286  		}
   287  	}
   288  	return nil
   289  }
   290  
   291  func (m *Module) validateGlobals(globals []*GlobalType, numFuncts, maxGlobals uint32) error {
   292  	if uint32(len(globals)) > maxGlobals {
   293  		return fmt.Errorf("too many globals in a module")
   294  	}
   295  
   296  	// Global initialization constant expression can only reference the imported globals.
   297  	// See the note on https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#constant-expressions%E2%91%A0
   298  	importedGlobals := globals[:m.ImportGlobalCount()]
   299  	for _, g := range m.GlobalSection {
   300  		if err := validateConstExpression(importedGlobals, numFuncts, g.Init, g.Type.ValType); err != nil {
   301  			return err
   302  		}
   303  	}
   304  	return nil
   305  }
   306  
   307  func (m *Module) validateFunctions(enabledFeatures Features, functions []Index, globals []*GlobalType, memory *Memory, tables []*Table, maximumFunctionIndex uint32) error {
   308  	if uint32(len(functions)) > maximumFunctionIndex {
   309  		return fmt.Errorf("too many functions in a store")
   310  	}
   311  
   312  	functionCount := m.SectionElementCount(SectionIDFunction)
   313  	codeCount := m.SectionElementCount(SectionIDCode)
   314  	if functionCount == 0 && codeCount == 0 {
   315  		return nil
   316  	}
   317  
   318  	typeCount := m.SectionElementCount(SectionIDType)
   319  	if codeCount != functionCount {
   320  		return fmt.Errorf("code count (%d) != function count (%d)", codeCount, functionCount)
   321  	}
   322  
   323  	declaredFuncIndexes, err := m.declaredFunctionIndexes()
   324  	if err != nil {
   325  		return err
   326  	}
   327  
   328  	for idx, typeIndex := range m.FunctionSection {
   329  		if typeIndex >= typeCount {
   330  			return fmt.Errorf("invalid %s: type section index %d out of range", m.funcDesc(SectionIDFunction, Index(idx)), typeIndex)
   331  		}
   332  		if m.CodeSection[idx].GoFunc != nil {
   333  			continue
   334  		}
   335  		if err = m.validateFunction(enabledFeatures, Index(idx), functions, globals, memory, tables, declaredFuncIndexes); err != nil {
   336  			return fmt.Errorf("invalid %s: %w", m.funcDesc(SectionIDFunction, Index(idx)), err)
   337  		}
   338  	}
   339  	return nil
   340  }
   341  
   342  // declaredFunctionIndexes returns a set of function indexes that can be used as an immediate for OpcodeRefFunc instruction.
   343  //
   344  // The criteria for which function indexes can be available for that instruction is vague in the spec:
   345  //
   346  //   - "References: the list of function indices that occur in the module outside functions and can hence be used to form references inside them."
   347  //   - https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/valid/conventions.html#contexts
   348  //   - "Ref is the set funcidx(module with functions=ε, start=ε) , i.e., the set of function indices occurring in the module, except in its functions or start function."
   349  //   - https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/valid/modules.html#valid-module
   350  //
   351  // To clarify, we reverse-engineer logic required to pass the WebAssembly Core specification 2.0 test suite:
   352  // https://github.com/WebAssembly/spec/blob/d39195773112a22b245ffbe864bab6d1182ccb06/test/core/ref_func.wast#L78-L115
   353  //
   354  // To summarize, the function indexes OpcodeRefFunc can refer include:
   355  //   - existing in an element section regardless of its mode (active, passive, declarative).
   356  //   - defined as globals whose value type is ValueRefFunc.
   357  //   - used as an exported function.
   358  //
   359  // See https://github.com/WebAssembly/reference-types/issues/31
   360  // See https://github.com/WebAssembly/reference-types/issues/76
   361  func (m *Module) declaredFunctionIndexes() (ret map[Index]struct{}, err error) {
   362  	ret = map[uint32]struct{}{}
   363  
   364  	for _, exp := range m.ExportSection {
   365  		if exp.Type == ExternTypeFunc {
   366  			ret[exp.Index] = struct{}{}
   367  		}
   368  	}
   369  
   370  	for i, g := range m.GlobalSection {
   371  		if g.Init.Opcode == OpcodeRefFunc {
   372  			var index uint32
   373  			index, _, err = leb128.DecodeUint32(bytes.NewReader(g.Init.Data))
   374  			if err != nil {
   375  				err = fmt.Errorf("%s[%d] failed to initialize: %w", SectionIDName(SectionIDGlobal), i, err)
   376  				return
   377  			}
   378  			ret[index] = struct{}{}
   379  		}
   380  	}
   381  
   382  	for _, elem := range m.ElementSection {
   383  		for _, index := range elem.Init {
   384  			if index != nil {
   385  				ret[*index] = struct{}{}
   386  			}
   387  		}
   388  	}
   389  	return
   390  }
   391  
   392  func (m *Module) funcDesc(sectionID SectionID, sectionIndex Index) string {
   393  	// Try to improve the error message by collecting any exports:
   394  	var exportNames []string
   395  	funcIdx := sectionIndex + m.importCount(ExternTypeFunc)
   396  	for _, e := range m.ExportSection {
   397  		if e.Index == funcIdx && e.Type == ExternTypeFunc {
   398  			exportNames = append(exportNames, fmt.Sprintf("%q", e.Name))
   399  		}
   400  	}
   401  	sectionIDName := SectionIDName(sectionID)
   402  	if exportNames == nil {
   403  		return fmt.Sprintf("%s[%d]", sectionIDName, sectionIndex)
   404  	}
   405  	sort.Strings(exportNames) // go map keys do not iterate consistently
   406  	return fmt.Sprintf("%s[%d] export[%s]", sectionIDName, sectionIndex, strings.Join(exportNames, ","))
   407  }
   408  
   409  func (m *Module) validateMemory(memory *Memory, globals []*GlobalType, enabledFeatures Features) error {
   410  	var activeElementCount int
   411  	for _, sec := range m.DataSection {
   412  		if !sec.IsPassive() {
   413  			activeElementCount++
   414  		}
   415  	}
   416  	if activeElementCount > 0 && memory == nil {
   417  		return fmt.Errorf("unknown memory")
   418  	}
   419  
   420  	for _, d := range m.DataSection {
   421  		if !d.IsPassive() {
   422  			if err := validateConstExpression(globals, 0, d.OffsetExpression, ValueTypeI32); err != nil {
   423  				return fmt.Errorf("calculate offset: %w", err)
   424  			}
   425  		}
   426  	}
   427  	return nil
   428  }
   429  
   430  func (m *Module) validateImports(enabledFeatures Features) error {
   431  	for _, i := range m.ImportSection {
   432  		switch i.Type {
   433  		case ExternTypeGlobal:
   434  			if !i.DescGlobal.Mutable {
   435  				continue
   436  			}
   437  			if err := enabledFeatures.Require(FeatureMutableGlobal); err != nil {
   438  				return fmt.Errorf("invalid import[%q.%q] global: %w", i.Module, i.Name, err)
   439  			}
   440  		}
   441  	}
   442  	return nil
   443  }
   444  
   445  func (m *Module) validateExports(enabledFeatures Features, functions []Index, globals []*GlobalType, memory *Memory, tables []*Table) error {
   446  	for _, exp := range m.ExportSection {
   447  		index := exp.Index
   448  		switch exp.Type {
   449  		case ExternTypeFunc:
   450  			if index >= uint32(len(functions)) {
   451  				return fmt.Errorf("unknown function for export[%q]", exp.Name)
   452  			}
   453  		case ExternTypeGlobal:
   454  			if index >= uint32(len(globals)) {
   455  				return fmt.Errorf("unknown global for export[%q]", exp.Name)
   456  			}
   457  			if !globals[index].Mutable {
   458  				continue
   459  			}
   460  			if err := enabledFeatures.Require(FeatureMutableGlobal); err != nil {
   461  				return fmt.Errorf("invalid export[%q] global[%d]: %w", exp.Name, index, err)
   462  			}
   463  		case ExternTypeMemory:
   464  			if index > 0 || memory == nil {
   465  				return fmt.Errorf("memory for export[%q] out of range", exp.Name)
   466  			}
   467  		case ExternTypeTable:
   468  			if index >= uint32(len(tables)) {
   469  				return fmt.Errorf("table for export[%q] out of range", exp.Name)
   470  			}
   471  		}
   472  	}
   473  	return nil
   474  }
   475  
   476  func validateConstExpression(globals []*GlobalType, numFuncs uint32, expr *ConstantExpression, expectedType ValueType) (err error) {
   477  	var actualType ValueType
   478  	r := bytes.NewReader(expr.Data)
   479  	switch expr.Opcode {
   480  	case OpcodeI32Const:
   481  		// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
   482  		_, _, err = leb128.DecodeInt32(r)
   483  		if err != nil {
   484  			return fmt.Errorf("read i32: %w", err)
   485  		}
   486  		actualType = ValueTypeI32
   487  	case OpcodeI64Const:
   488  		// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
   489  		_, _, err = leb128.DecodeInt64(r)
   490  		if err != nil {
   491  			return fmt.Errorf("read i64: %w", err)
   492  		}
   493  		actualType = ValueTypeI64
   494  	case OpcodeF32Const:
   495  		_, err = ieee754.DecodeFloat32(r)
   496  		if err != nil {
   497  			return fmt.Errorf("read f32: %w", err)
   498  		}
   499  		actualType = ValueTypeF32
   500  	case OpcodeF64Const:
   501  		_, err = ieee754.DecodeFloat64(r)
   502  		if err != nil {
   503  			return fmt.Errorf("read f64: %w", err)
   504  		}
   505  		actualType = ValueTypeF64
   506  	case OpcodeGlobalGet:
   507  		id, _, err := leb128.DecodeUint32(r)
   508  		if err != nil {
   509  			return fmt.Errorf("read index of global: %w", err)
   510  		}
   511  		if uint32(len(globals)) <= id {
   512  			return fmt.Errorf("global index out of range")
   513  		}
   514  		actualType = globals[id].ValType
   515  	case OpcodeRefNull:
   516  		reftype, err := r.ReadByte()
   517  		if err != nil {
   518  			return fmt.Errorf("read reference type for ref.null: %w", err)
   519  		} else if reftype != RefTypeFuncref && reftype != RefTypeExternref {
   520  			return fmt.Errorf("invalid type for ref.null: 0x%x", reftype)
   521  		}
   522  		actualType = reftype
   523  	case OpcodeRefFunc:
   524  		index, _, err := leb128.DecodeUint32(r)
   525  		if err != nil {
   526  			return fmt.Errorf("read i32: %w", err)
   527  		} else if index >= numFuncs {
   528  			return fmt.Errorf("ref.func index out of range [%d] with length %d", index, numFuncs-1)
   529  		}
   530  		actualType = ValueTypeFuncref
   531  	case OpcodeVecV128Const:
   532  		if len(expr.Data) != 16 {
   533  			return fmt.Errorf("%s needs 16 bytes but was %d bytes", OpcodeVecV128ConstName, len(expr.Data))
   534  		}
   535  		actualType = ValueTypeV128
   536  	default:
   537  		return fmt.Errorf("invalid opcode for const expression: 0x%x", expr.Opcode)
   538  	}
   539  
   540  	if actualType != expectedType {
   541  		return fmt.Errorf("const expression type mismatch expected %s but got %s",
   542  			ValueTypeName(expectedType), ValueTypeName(actualType))
   543  	}
   544  	return nil
   545  }
   546  
   547  func (m *Module) validateDataCountSection() (err error) {
   548  	if m.DataCountSection != nil && int(*m.DataCountSection) != len(m.DataSection) {
   549  		err = fmt.Errorf("data count section (%d) doesn't match the length of data section (%d)",
   550  			*m.DataCountSection, len(m.DataSection))
   551  	}
   552  	return
   553  }
   554  
   555  func (m *Module) buildGlobals(importedGlobals []*GlobalInstance) (globals []*GlobalInstance) {
   556  	for _, gs := range m.GlobalSection {
   557  		g := &GlobalInstance{Type: gs.Type}
   558  		switch v := executeConstExpression(importedGlobals, gs.Init).(type) {
   559  		case uint32:
   560  			g.Val = uint64(v)
   561  		case int32:
   562  			g.Val = uint64(uint32(v))
   563  		case int64:
   564  			g.Val = uint64(v)
   565  		case float32:
   566  			g.Val = api.EncodeF32(v)
   567  		case float64:
   568  			g.Val = api.EncodeF64(v)
   569  		case [2]uint64:
   570  			g.Val, g.ValHi = v[0], v[1]
   571  		default:
   572  			panic(fmt.Errorf("BUG: invalid conversion %d", v))
   573  		}
   574  		globals = append(globals, g)
   575  	}
   576  	return
   577  }
   578  
   579  // BuildFunctions generates function instances for all host or wasm-defined
   580  // functions in this module.
   581  //
   582  // # Notes
   583  //   - This relies on data generated by Module.BuildFunctionDefinitions.
   584  //   - This is exported for tests that don't call Instantiate, notably only
   585  //     enginetest.go.
   586  func (m *ModuleInstance) BuildFunctions(mod *Module, listeners []experimental.FunctionListener) (fns []*FunctionInstance) {
   587  	fns = make([]*FunctionInstance, 0, len(mod.FunctionDefinitionSection))
   588  	for i := range mod.FunctionSection {
   589  		code := mod.CodeSection[i]
   590  		fns = append(fns, &FunctionInstance{
   591  			IsHostFunction: code.IsHostFunction,
   592  			Kind:           code.Kind,
   593  			LocalTypes:     code.LocalTypes,
   594  			Body:           code.Body,
   595  			GoFunc:         code.GoFunc,
   596  			TypeID:         m.TypeIDs[mod.FunctionSection[i]],
   597  		})
   598  	}
   599  
   600  	importCount := mod.ImportFuncCount()
   601  	for i, f := range fns {
   602  		d := mod.FunctionDefinitionSection[uint32(i)+importCount]
   603  		f.Module = m
   604  		f.Idx = d.index
   605  		f.Type = d.funcType
   606  		f.definition = d
   607  		if listeners != nil {
   608  			f.FunctionListener = listeners[i]
   609  		}
   610  	}
   611  	return
   612  }
   613  
   614  func paramNames(localNames IndirectNameMap, funcIdx uint32, paramLen int) []string {
   615  	for _, nm := range localNames {
   616  		// Only build parameter names if we have one for each.
   617  		if nm.Index != funcIdx || len(nm.NameMap) < paramLen {
   618  			continue
   619  		}
   620  
   621  		ret := make([]string, paramLen)
   622  		for _, p := range nm.NameMap {
   623  			if int(p.Index) < paramLen {
   624  				ret[p.Index] = p.Name
   625  			}
   626  		}
   627  		return ret
   628  	}
   629  	return nil
   630  }
   631  
   632  func (m *Module) buildMemory() (mem *MemoryInstance) {
   633  	memSec := m.MemorySection
   634  	if memSec != nil {
   635  		mem = NewMemoryInstance(memSec)
   636  	}
   637  	return
   638  }
   639  
   640  // Index is the offset in an index namespace, not necessarily an absolute position in a Module section. This is because
   641  // index namespaces are often preceded by a corresponding type in the Module.ImportSection.
   642  //
   643  // For example, the function index namespace starts with any ExternTypeFunc in the Module.ImportSection followed by
   644  // the Module.FunctionSection
   645  //
   646  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-index
   647  type Index = uint32
   648  
   649  // FunctionType is a possibly empty function signature.
   650  //
   651  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-types%E2%91%A0
   652  type FunctionType struct {
   653  	// Params are the possibly empty sequence of value types accepted by a function with this signature.
   654  	Params []ValueType
   655  
   656  	// Results are the possibly empty sequence of value types returned by a function with this signature.
   657  	//
   658  	// Note: In WebAssembly 1.0 (20191205), there can be at most one result.
   659  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#result-types%E2%91%A0
   660  	Results []ValueType
   661  
   662  	// string is cached as it is used both for String and key
   663  	string string
   664  
   665  	// ParamNumInUint64 is the number of uint64 values requires to represent the Wasm param type.
   666  	ParamNumInUint64 int
   667  
   668  	// ResultsNumInUint64 is the number of uint64 values requires to represent the Wasm result type.
   669  	ResultNumInUint64 int
   670  }
   671  
   672  func (f *FunctionType) CacheNumInUint64() {
   673  	if f.ParamNumInUint64 == 0 {
   674  		for _, tp := range f.Params {
   675  			f.ParamNumInUint64++
   676  			if tp == ValueTypeV128 {
   677  				f.ParamNumInUint64++
   678  			}
   679  		}
   680  	}
   681  
   682  	if f.ResultNumInUint64 == 0 {
   683  		for _, tp := range f.Results {
   684  			f.ResultNumInUint64++
   685  			if tp == ValueTypeV128 {
   686  				f.ResultNumInUint64++
   687  			}
   688  		}
   689  	}
   690  }
   691  
   692  // EqualsSignature returns true if the function type has the same parameters and results.
   693  func (f *FunctionType) EqualsSignature(params []ValueType, results []ValueType) bool {
   694  	return bytes.Equal(f.Params, params) && bytes.Equal(f.Results, results)
   695  }
   696  
   697  // key gets or generates the key for Store.typeIDs. Ex. "i32_v" for one i32 parameter and no (void) result.
   698  func (f *FunctionType) key() string {
   699  	if f.string != "" {
   700  		return f.string
   701  	}
   702  	var ret string
   703  	for _, b := range f.Params {
   704  		ret += ValueTypeName(b)
   705  	}
   706  	if len(f.Params) == 0 {
   707  		ret += "v"
   708  	}
   709  	ret += "_"
   710  	for _, b := range f.Results {
   711  		ret += ValueTypeName(b)
   712  	}
   713  	if len(f.Results) == 0 {
   714  		ret += "v"
   715  	}
   716  	f.string = ret
   717  	return ret
   718  }
   719  
   720  // String implements fmt.Stringer.
   721  func (f *FunctionType) String() string {
   722  	return f.key()
   723  }
   724  
   725  // Import is the binary representation of an import indicated by Type
   726  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-import
   727  type Import struct {
   728  	Type ExternType
   729  	// Module is the possibly empty primary namespace of this import
   730  	Module string
   731  	// Module is the possibly empty secondary namespace of this import
   732  	Name string
   733  	// DescFunc is the index in Module.TypeSection when Type equals ExternTypeFunc
   734  	DescFunc Index
   735  	// DescTable is the inlined Table when Type equals ExternTypeTable
   736  	DescTable *Table
   737  	// DescMem is the inlined Memory when Type equals ExternTypeMemory
   738  	DescMem *Memory
   739  	// DescGlobal is the inlined GlobalType when Type equals ExternTypeGlobal
   740  	DescGlobal *GlobalType
   741  }
   742  
   743  // Memory describes the limits of pages (64KB) in a memory.
   744  type Memory struct {
   745  	Min, Cap, Max uint32
   746  	// IsMaxEncoded true if the Max is encoded in the original source (binary or text).
   747  	IsMaxEncoded bool
   748  }
   749  
   750  // Validate ensures values assigned to Min, Cap and Max are within valid thresholds.
   751  func (m *Memory) Validate() error {
   752  	min, capacity, max := m.Min, m.Cap, m.Max
   753  
   754  	if max > MemoryLimitPages {
   755  		return fmt.Errorf("max %d pages (%s) over limit of %d pages (%s)",
   756  			max, PagesToUnitOfBytes(max), MemoryLimitPages, PagesToUnitOfBytes(MemoryLimitPages))
   757  	} else if min > MemoryLimitPages {
   758  		return fmt.Errorf("min %d pages (%s) over limit of %d pages (%s)",
   759  			min, PagesToUnitOfBytes(min), MemoryLimitPages, PagesToUnitOfBytes(MemoryLimitPages))
   760  	} else if min > max {
   761  		return fmt.Errorf("min %d pages (%s) > max %d pages (%s)",
   762  			min, PagesToUnitOfBytes(min), max, PagesToUnitOfBytes(max))
   763  	} else if capacity < min {
   764  		return fmt.Errorf("capacity %d pages (%s) less than minimum %d pages (%s)",
   765  			capacity, PagesToUnitOfBytes(capacity), min, PagesToUnitOfBytes(min))
   766  	} else if capacity > MemoryLimitPages {
   767  		return fmt.Errorf("capacity %d pages (%s) over limit of %d pages (%s)",
   768  			capacity, PagesToUnitOfBytes(capacity), MemoryLimitPages, PagesToUnitOfBytes(MemoryLimitPages))
   769  	}
   770  	return nil
   771  }
   772  
   773  type GlobalType struct {
   774  	ValType ValueType
   775  	Mutable bool
   776  }
   777  
   778  type Global struct {
   779  	Type *GlobalType
   780  	Init *ConstantExpression
   781  }
   782  
   783  type ConstantExpression struct {
   784  	Opcode Opcode
   785  	Data   []byte
   786  }
   787  
   788  // Export is the binary representation of an export indicated by Type
   789  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-export
   790  type Export struct {
   791  	Type ExternType
   792  
   793  	// Name is what the host refers to this definition as.
   794  	Name string
   795  
   796  	// Index is the index of the definition to export, the index namespace is by Type
   797  	// Ex. If ExternTypeFunc, this is a position in the function index namespace.
   798  	Index Index
   799  }
   800  
   801  // Code is an entry in the Module.CodeSection containing the locals and body of the function.
   802  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-code
   803  type Code struct {
   804  	// IsHostFunction returns true if the function was implemented by the
   805  	// embedder (ex via wazero.ModuleBuilder) instead of a wasm binary.
   806  	//
   807  	// Notably, host functions can use the caller's memory, which might be
   808  	// different from its defining module.
   809  	//
   810  	// See https://www.w3.org/TR/wasm-core-1/#host-functions%E2%91%A0
   811  	IsHostFunction bool
   812  
   813  	// Kind describes how this function should be called.
   814  	Kind FunctionKind
   815  
   816  	// LocalTypes are any function-scoped variables in insertion order.
   817  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-local
   818  	LocalTypes []ValueType
   819  
   820  	// Body is a sequence of expressions ending in OpcodeEnd
   821  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-expr
   822  	Body []byte
   823  
   824  	// GoFunc is a host function defined in Go.
   825  	//
   826  	// When present, LocalTypes and Body must be nil.
   827  	//
   828  	// Note: This has no serialization format, so is not encodable.
   829  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#host-functions%E2%91%A2
   830  	GoFunc *reflect.Value
   831  }
   832  
   833  type DataSegment struct {
   834  	OffsetExpression *ConstantExpression
   835  	Init             []byte
   836  }
   837  
   838  // IsPassive returns true if this data segment is "passive" in the sense that memory offset and
   839  // index is determined at runtime and used by OpcodeMemoryInitName instruction in the bulk memory
   840  // operations proposal.
   841  //
   842  // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
   843  func (d *DataSegment) IsPassive() bool {
   844  	return d.OffsetExpression == nil
   845  }
   846  
   847  // NameSection represent the known custom name subsections defined in the WebAssembly Binary Format
   848  //
   849  // Note: This can be nil if no names were decoded for any reason including configuration.
   850  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
   851  type NameSection struct {
   852  	// ModuleName is the symbolic identifier for a module. Ex. math
   853  	//
   854  	// Note: This can be empty for any reason including configuration.
   855  	ModuleName string
   856  
   857  	// FunctionNames is an association of a function index to its symbolic identifier. Ex. add
   858  	//
   859  	// * the key (idx) is in the function namespace, where module defined functions are preceded by imported ones.
   860  	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#functions%E2%91%A7
   861  	//
   862  	// Ex. Assuming the below text format is the second import, you would expect FunctionNames[1] = "mul"
   863  	//	(import "Math" "Mul" (func $mul (param $x f32) (param $y f32) (result f32)))
   864  	//
   865  	// Note: FunctionNames are only used for debugging. At runtime, functions are called based on raw numeric index.
   866  	// Note: This can be nil for any reason including configuration.
   867  	FunctionNames NameMap
   868  
   869  	// LocalNames contains symbolic names for function parameters or locals that have one.
   870  	//
   871  	// Note: In the Text Format, function local names can inherit parameter names from their type. Ex.
   872  	//  * (module (import (func (param $x i32) (param i32))) (func (type 0))) = [{0, {x,0}}]
   873  	//  * (module (import (func (param i32) (param $y i32))) (func (type 0) (local $z i32))) = [0, [{y,1},{z,2}]]
   874  	//  * (module (func (param $x i32) (local $y i32) (local $z i32))) = [{x,0},{y,1},{z,2}]
   875  	//
   876  	// Note: LocalNames are only used for debugging. At runtime, locals are called based on raw numeric index.
   877  	// Note: This can be nil for any reason including configuration.
   878  	LocalNames IndirectNameMap
   879  }
   880  
   881  // NameMap associates an index with any associated names.
   882  //
   883  // Note: Often the index namespace bridges multiple sections. For example, the function index namespace starts with any
   884  // ExternTypeFunc in the Module.ImportSection followed by the Module.FunctionSection
   885  //
   886  // Note: NameMap is unique by NameAssoc.Index, but NameAssoc.Name needn't be unique.
   887  // Note: When encoding in the Binary format, this must be ordered by NameAssoc.Index
   888  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-namemap
   889  type NameMap []*NameAssoc
   890  
   891  type NameAssoc struct {
   892  	Index Index
   893  	Name  string
   894  }
   895  
   896  // IndirectNameMap associates an index with an association of names.
   897  //
   898  // Note: IndirectNameMap is unique by NameMapAssoc.Index, but NameMapAssoc.NameMap needn't be unique.
   899  // Note: When encoding in the Binary format, this must be ordered by NameMapAssoc.Index
   900  // https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-indirectnamemap
   901  type IndirectNameMap []*NameMapAssoc
   902  
   903  type NameMapAssoc struct {
   904  	Index   Index
   905  	NameMap NameMap
   906  }
   907  
   908  // AllDeclarations returns all declarations for functions, globals, memories and tables in a module including imported ones.
   909  func (m *Module) AllDeclarations() (functions []Index, globals []*GlobalType, memory *Memory, tables []*Table, err error) {
   910  	for _, imp := range m.ImportSection {
   911  		switch imp.Type {
   912  		case ExternTypeFunc:
   913  			functions = append(functions, imp.DescFunc)
   914  		case ExternTypeGlobal:
   915  			globals = append(globals, imp.DescGlobal)
   916  		case ExternTypeMemory:
   917  			memory = imp.DescMem
   918  		case ExternTypeTable:
   919  			tables = append(tables, imp.DescTable)
   920  		}
   921  	}
   922  
   923  	functions = append(functions, m.FunctionSection...)
   924  	for _, g := range m.GlobalSection {
   925  		globals = append(globals, g.Type)
   926  	}
   927  	if m.MemorySection != nil {
   928  		if memory != nil { // shouldn't be possible due to Validate
   929  			err = errors.New("at most one table allowed in module")
   930  			return
   931  		}
   932  		memory = m.MemorySection
   933  	}
   934  	if m.TableSection != nil {
   935  		tables = append(tables, m.TableSection...)
   936  	}
   937  	return
   938  }
   939  
   940  // SectionID identifies the sections of a Module in the WebAssembly 1.0 (20191205) Binary Format.
   941  //
   942  // Note: these are defined in the wasm package, instead of the binary package, as a key per section is needed regardless
   943  // of format, and deferring to the binary type avoids confusion.
   944  //
   945  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
   946  type SectionID = byte
   947  
   948  const (
   949  	// SectionIDCustom includes the standard defined NameSection and possibly others not defined in the standard.
   950  	SectionIDCustom SectionID = iota // don't add anything not in https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
   951  	SectionIDType
   952  	SectionIDImport
   953  	SectionIDFunction
   954  	SectionIDTable
   955  	SectionIDMemory
   956  	SectionIDGlobal
   957  	SectionIDExport
   958  	SectionIDStart
   959  	SectionIDElement
   960  	SectionIDCode
   961  	SectionIDData
   962  
   963  	// SectionIDDataCount may exist in WebAssembly 2.0 or WebAssembly 1.0 with FeatureBulkMemoryOperations enabled.
   964  	//
   965  	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section
   966  	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
   967  	SectionIDDataCount
   968  )
   969  
   970  // SectionIDName returns the canonical name of a module section.
   971  // https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
   972  func SectionIDName(sectionID SectionID) string {
   973  	switch sectionID {
   974  	case SectionIDCustom:
   975  		return "custom"
   976  	case SectionIDType:
   977  		return "type"
   978  	case SectionIDImport:
   979  		return "import"
   980  	case SectionIDFunction:
   981  		return "function"
   982  	case SectionIDTable:
   983  		return "table"
   984  	case SectionIDMemory:
   985  		return "memory"
   986  	case SectionIDGlobal:
   987  		return "global"
   988  	case SectionIDExport:
   989  		return "export"
   990  	case SectionIDStart:
   991  		return "start"
   992  	case SectionIDElement:
   993  		return "element"
   994  	case SectionIDCode:
   995  		return "code"
   996  	case SectionIDData:
   997  		return "data"
   998  	case SectionIDDataCount:
   999  		return "data_count"
  1000  	}
  1001  	return "unknown"
  1002  }
  1003  
  1004  // ValueType is an alias of api.ValueType defined to simplify imports.
  1005  type ValueType = api.ValueType
  1006  
  1007  const (
  1008  	ValueTypeI32 = api.ValueTypeI32
  1009  	ValueTypeI64 = api.ValueTypeI64
  1010  	ValueTypeF32 = api.ValueTypeF32
  1011  	ValueTypeF64 = api.ValueTypeF64
  1012  	// TODO: ValueTypeV128 is not exposed in the api pkg yet.
  1013  	ValueTypeV128 ValueType = 0x7b
  1014  	// TODO: ValueTypeFuncref is not exposed in the api pkg yet.
  1015  	ValueTypeFuncref   ValueType = 0x70
  1016  	ValueTypeExternref           = api.ValueTypeExternref
  1017  )
  1018  
  1019  // ValueTypeName is an alias of api.ValueTypeName defined to simplify imports.
  1020  func ValueTypeName(t ValueType) string {
  1021  	if t == ValueTypeFuncref {
  1022  		return "funcref"
  1023  	} else if t == ValueTypeV128 {
  1024  		return "v128"
  1025  	}
  1026  	return api.ValueTypeName(t)
  1027  }
  1028  
  1029  func isReferenceValueType(vt ValueType) bool {
  1030  	return vt == ValueTypeExternref || vt == ValueTypeFuncref
  1031  }
  1032  
  1033  // ExternType is an alias of api.ExternType defined to simplify imports.
  1034  type ExternType = api.ExternType
  1035  
  1036  const (
  1037  	ExternTypeFunc       = api.ExternTypeFunc
  1038  	ExternTypeFuncName   = api.ExternTypeFuncName
  1039  	ExternTypeTable      = api.ExternTypeTable
  1040  	ExternTypeTableName  = api.ExternTypeTableName
  1041  	ExternTypeMemory     = api.ExternTypeMemory
  1042  	ExternTypeMemoryName = api.ExternTypeMemoryName
  1043  	ExternTypeGlobal     = api.ExternTypeGlobal
  1044  	ExternTypeGlobalName = api.ExternTypeGlobalName
  1045  )
  1046  
  1047  // ExternTypeName is an alias of api.ExternTypeName defined to simplify imports.
  1048  func ExternTypeName(t ValueType) string {
  1049  	return api.ExternTypeName(t)
  1050  }