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

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