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