wa-lang.org/wazero@v1.0.2/internal/wasm/module.go (about)

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