module.go

   1package wasm
   2
   3import (
   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.
  28type 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.
 191type 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
 195const (
 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.
 203func (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
 221func 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.
 229func (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
 260func (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
 307func (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
 323func (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
 340func (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
 400func (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
 434func (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
 452func (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
 478func (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
 501func (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
 533func 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
 604func (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
 612func (m *ModuleInstance) buildGlobals(module *Module, funcRefResolver func(funcIndex Index) Reference) {
 613	importedGlobals := m.Globals[:module.ImportGlobalCount]
 614
 615	me := m.Engine
 616	engineOwnGlobal := me.OwnsGlobals()
 617	for i := Index(0); i < Index(len(module.GlobalSection)); i++ {
 618		gs := &module.GlobalSection[i]
 619		g := &GlobalInstance{}
 620		if engineOwnGlobal {
 621			g.Me = me
 622			g.Index = i + module.ImportGlobalCount
 623		}
 624		m.Globals[i+module.ImportGlobalCount] = g
 625		g.Type = gs.Type
 626		g.initialize(importedGlobals, &gs.Init, funcRefResolver)
 627	}
 628}
 629
 630func paramNames(localNames IndirectNameMap, funcIdx uint32, paramLen int) []string {
 631	for i := range localNames {
 632		nm := &localNames[i]
 633		// Only build parameter names if we have one for each.
 634		if nm.Index != funcIdx || len(nm.NameMap) < paramLen {
 635			continue
 636		}
 637
 638		ret := make([]string, paramLen)
 639		for j := range nm.NameMap {
 640			p := &nm.NameMap[j]
 641			if int(p.Index) < paramLen {
 642				ret[p.Index] = p.Name
 643			}
 644		}
 645		return ret
 646	}
 647	return nil
 648}
 649
 650func (m *ModuleInstance) buildMemory(module *Module, allocator experimental.MemoryAllocator) {
 651	memSec := module.MemorySection
 652	if memSec != nil {
 653		m.MemoryInstance = NewMemoryInstance(memSec, allocator, m.Engine)
 654		m.MemoryInstance.definition = &module.MemoryDefinitionSection[0]
 655	}
 656}
 657
 658// Index is the offset in an index, not necessarily an absolute position in a Module section. This is because
 659// indexs are often preceded by a corresponding type in the Module.ImportSection.
 660//
 661// For example, the function index starts with any ExternTypeFunc in the Module.ImportSection followed by
 662// the Module.FunctionSection
 663//
 664// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-index
 665type Index = uint32
 666
 667// FunctionType is a possibly empty function signature.
 668//
 669// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-types%E2%91%A0
 670type FunctionType struct {
 671	// Params are the possibly empty sequence of value types accepted by a function with this signature.
 672	Params []ValueType
 673
 674	// Results are the possibly empty sequence of value types returned by a function with this signature.
 675	//
 676	// Note: In WebAssembly 1.0 (20191205), there can be at most one result.
 677	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#result-types%E2%91%A0
 678	Results []ValueType
 679
 680	// string is cached as it is used both for String and key
 681	string string
 682
 683	// ParamNumInUint64 is the number of uint64 values requires to represent the Wasm param type.
 684	ParamNumInUint64 int
 685
 686	// ResultsNumInUint64 is the number of uint64 values requires to represent the Wasm result type.
 687	ResultNumInUint64 int
 688}
 689
 690func (f *FunctionType) CacheNumInUint64() {
 691	if f.ParamNumInUint64 == 0 {
 692		for _, tp := range f.Params {
 693			f.ParamNumInUint64++
 694			if tp == ValueTypeV128 {
 695				f.ParamNumInUint64++
 696			}
 697		}
 698	}
 699
 700	if f.ResultNumInUint64 == 0 {
 701		for _, tp := range f.Results {
 702			f.ResultNumInUint64++
 703			if tp == ValueTypeV128 {
 704				f.ResultNumInUint64++
 705			}
 706		}
 707	}
 708}
 709
 710// EqualsSignature returns true if the function type has the same parameters and results.
 711func (f *FunctionType) EqualsSignature(params []ValueType, results []ValueType) bool {
 712	return bytes.Equal(f.Params, params) && bytes.Equal(f.Results, results)
 713}
 714
 715// key gets or generates the key for Store.typeIDs. e.g. "i32_v" for one i32 parameter and no (void) result.
 716func (f *FunctionType) key() string {
 717	if f.string != "" {
 718		return f.string
 719	}
 720	var ret string
 721	for _, b := range f.Params {
 722		ret += ValueTypeName(b)
 723	}
 724	if len(f.Params) == 0 {
 725		ret += "v_"
 726	} else {
 727		ret += "_"
 728	}
 729	for _, b := range f.Results {
 730		ret += ValueTypeName(b)
 731	}
 732	if len(f.Results) == 0 {
 733		ret += "v"
 734	}
 735	f.string = ret
 736	return ret
 737}
 738
 739// String implements fmt.Stringer.
 740func (f *FunctionType) String() string {
 741	return f.key()
 742}
 743
 744// Import is the binary representation of an import indicated by Type
 745// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-import
 746type Import struct {
 747	Type ExternType
 748	// Module is the possibly empty primary namespace of this import
 749	Module string
 750	// Module is the possibly empty secondary namespace of this import
 751	Name string
 752	// DescFunc is the index in Module.TypeSection when Type equals ExternTypeFunc
 753	DescFunc Index
 754	// DescTable is the inlined Table when Type equals ExternTypeTable
 755	DescTable Table
 756	// DescMem is the inlined Memory when Type equals ExternTypeMemory
 757	DescMem *Memory
 758	// DescGlobal is the inlined GlobalType when Type equals ExternTypeGlobal
 759	DescGlobal GlobalType
 760	// IndexPerType has the index of this import per ExternType.
 761	IndexPerType Index
 762}
 763
 764// Memory describes the limits of pages (64KB) in a memory.
 765type Memory struct {
 766	Min, Cap, Max uint32
 767	// IsMaxEncoded true if the Max is encoded in the original binary.
 768	IsMaxEncoded bool
 769	// IsShared true if the memory is shared for access from multiple agents.
 770	IsShared bool
 771}
 772
 773// Validate ensures values assigned to Min, Cap and Max are within valid thresholds.
 774func (m *Memory) Validate(memoryLimitPages uint32) error {
 775	min, capacity, max := m.Min, m.Cap, m.Max
 776
 777	if max > memoryLimitPages {
 778		return fmt.Errorf("max %d pages (%s) over limit of %d pages (%s)",
 779			max, PagesToUnitOfBytes(max), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages))
 780	} else if min > memoryLimitPages {
 781		return fmt.Errorf("min %d pages (%s) over limit of %d pages (%s)",
 782			min, PagesToUnitOfBytes(min), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages))
 783	} else if min > max {
 784		return fmt.Errorf("min %d pages (%s) > max %d pages (%s)",
 785			min, PagesToUnitOfBytes(min), max, PagesToUnitOfBytes(max))
 786	} else if capacity < min {
 787		return fmt.Errorf("capacity %d pages (%s) less than minimum %d pages (%s)",
 788			capacity, PagesToUnitOfBytes(capacity), min, PagesToUnitOfBytes(min))
 789	} else if capacity > memoryLimitPages {
 790		return fmt.Errorf("capacity %d pages (%s) over limit of %d pages (%s)",
 791			capacity, PagesToUnitOfBytes(capacity), memoryLimitPages, PagesToUnitOfBytes(memoryLimitPages))
 792	}
 793	return nil
 794}
 795
 796type GlobalType struct {
 797	ValType ValueType
 798	Mutable bool
 799}
 800
 801type Global struct {
 802	Type GlobalType
 803	Init ConstantExpression
 804}
 805
 806type ConstantExpression struct {
 807	Opcode Opcode
 808	Data   []byte
 809}
 810
 811// Export is the binary representation of an export indicated by Type
 812// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-export
 813type Export struct {
 814	Type ExternType
 815
 816	// Name is what the host refers to this definition as.
 817	Name string
 818
 819	// Index is the index of the definition to export, the index is by Type
 820	// e.g. If ExternTypeFunc, this is a position in the function index.
 821	Index Index
 822}
 823
 824// Code is an entry in the Module.CodeSection containing the locals and body of the function.
 825// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-code
 826type Code struct {
 827	// LocalTypes are any function-scoped variables in insertion order.
 828	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-local
 829	LocalTypes []ValueType
 830
 831	// Body is a sequence of expressions ending in OpcodeEnd
 832	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-expr
 833	Body []byte
 834
 835	// GoFunc is non-nil when IsHostFunction and defined in go, either
 836	// api.GoFunction or api.GoModuleFunction. When present, LocalTypes and Body must
 837	// be nil.
 838	//
 839	// Note: This has no serialization format, so is not encodable.
 840	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#host-functions%E2%91%A2
 841	GoFunc interface{}
 842
 843	// BodyOffsetInCodeSection is the offset of the beginning of the body in the code section.
 844	// This is used for DWARF based stack trace where a program counter represents an offset in code section.
 845	BodyOffsetInCodeSection uint64
 846}
 847
 848type DataSegment struct {
 849	OffsetExpression ConstantExpression
 850	Init             []byte
 851	Passive          bool
 852}
 853
 854// IsPassive returns true if this data segment is "passive" in the sense that memory offset and
 855// index is determined at runtime and used by OpcodeMemoryInitName instruction in the bulk memory
 856// operations proposal.
 857//
 858// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
 859func (d *DataSegment) IsPassive() bool {
 860	return d.Passive
 861}
 862
 863// NameSection represent the known custom name subsections defined in the WebAssembly Binary Format
 864//
 865// Note: This can be nil if no names were decoded for any reason including configuration.
 866// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
 867type NameSection struct {
 868	// ModuleName is the symbolic identifier for a module. e.g. math
 869	//
 870	// Note: This can be empty for any reason including configuration.
 871	ModuleName string
 872
 873	// FunctionNames is an association of a function index to its symbolic identifier. e.g. add
 874	//
 875	// * the key (idx) is in the function index, where module defined functions are preceded by imported ones.
 876	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#functions%E2%91%A7
 877	//
 878	// For example, assuming the below text format is the second import, you would expect FunctionNames[1] = "mul"
 879	//	(import "Math" "Mul" (func $mul (param $x f32) (param $y f32) (result f32)))
 880	//
 881	// Note: FunctionNames are only used for debugging. At runtime, functions are called based on raw numeric index.
 882	// Note: This can be nil for any reason including configuration.
 883	FunctionNames NameMap
 884
 885	// LocalNames contains symbolic names for function parameters or locals that have one.
 886	//
 887	// Note: In the Text Format, function local names can inherit parameter
 888	// names from their type. Here are some examples:
 889	//  * (module (import (func (param $x i32) (param i32))) (func (type 0))) = [{0, {x,0}}]
 890	//  * (module (import (func (param i32) (param $y i32))) (func (type 0) (local $z i32))) = [0, [{y,1},{z,2}]]
 891	//  * (module (func (param $x i32) (local $y i32) (local $z i32))) = [{x,0},{y,1},{z,2}]
 892	//
 893	// Note: LocalNames are only used for debugging. At runtime, locals are called based on raw numeric index.
 894	// Note: This can be nil for any reason including configuration.
 895	LocalNames IndirectNameMap
 896
 897	// ResultNames is a wazero-specific mechanism to store result names.
 898	ResultNames IndirectNameMap
 899}
 900
 901// CustomSection contains the name and raw data of a custom section.
 902type CustomSection struct {
 903	Name string
 904	Data []byte
 905}
 906
 907// NameMap associates an index with any associated names.
 908//
 909// Note: Often the index bridges multiple sections. For example, the function index starts with any
 910// ExternTypeFunc in the Module.ImportSection followed by the Module.FunctionSection
 911//
 912// Note: NameMap is unique by NameAssoc.Index, but NameAssoc.Name needn't be unique.
 913// Note: When encoding in the Binary format, this must be ordered by NameAssoc.Index
 914// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-namemap
 915type NameMap []NameAssoc
 916
 917type NameAssoc struct {
 918	Index Index
 919	Name  string
 920}
 921
 922// IndirectNameMap associates an index with an association of names.
 923//
 924// Note: IndirectNameMap is unique by NameMapAssoc.Index, but NameMapAssoc.NameMap needn't be unique.
 925// Note: When encoding in the Binary format, this must be ordered by NameMapAssoc.Index
 926// https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-indirectnamemap
 927type IndirectNameMap []NameMapAssoc
 928
 929type NameMapAssoc struct {
 930	Index   Index
 931	NameMap NameMap
 932}
 933
 934// AllDeclarations returns all declarations for functions, globals, memories and tables in a module including imported ones.
 935func (m *Module) AllDeclarations() (functions []Index, globals []GlobalType, memory *Memory, tables []Table, err error) {
 936	for i := range m.ImportSection {
 937		imp := &m.ImportSection[i]
 938		switch imp.Type {
 939		case ExternTypeFunc:
 940			functions = append(functions, imp.DescFunc)
 941		case ExternTypeGlobal:
 942			globals = append(globals, imp.DescGlobal)
 943		case ExternTypeMemory:
 944			memory = imp.DescMem
 945		case ExternTypeTable:
 946			tables = append(tables, imp.DescTable)
 947		}
 948	}
 949
 950	functions = append(functions, m.FunctionSection...)
 951	for i := range m.GlobalSection {
 952		g := &m.GlobalSection[i]
 953		globals = append(globals, g.Type)
 954	}
 955	if m.MemorySection != nil {
 956		if memory != nil { // shouldn't be possible due to Validate
 957			err = errors.New("at most one table allowed in module")
 958			return
 959		}
 960		memory = m.MemorySection
 961	}
 962	if m.TableSection != nil {
 963		tables = append(tables, m.TableSection...)
 964	}
 965	return
 966}
 967
 968// SectionID identifies the sections of a Module in the WebAssembly 1.0 (20191205) Binary Format.
 969//
 970// Note: these are defined in the wasm package, instead of the binary package, as a key per section is needed regardless
 971// of format, and deferring to the binary type avoids confusion.
 972//
 973// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
 974type SectionID = byte
 975
 976const (
 977	// SectionIDCustom includes the standard defined NameSection and possibly others not defined in the standard.
 978	SectionIDCustom SectionID = iota // don't add anything not in https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
 979	SectionIDType
 980	SectionIDImport
 981	SectionIDFunction
 982	SectionIDTable
 983	SectionIDMemory
 984	SectionIDGlobal
 985	SectionIDExport
 986	SectionIDStart
 987	SectionIDElement
 988	SectionIDCode
 989	SectionIDData
 990
 991	// SectionIDDataCount may exist in WebAssembly 2.0 or WebAssembly 1.0 with CoreFeatureBulkMemoryOperations enabled.
 992	//
 993	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section
 994	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
 995	SectionIDDataCount
 996)
 997
 998// SectionIDName returns the canonical name of a module section.
 999// https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
1000func SectionIDName(sectionID SectionID) string {
1001	switch sectionID {
1002	case SectionIDCustom:
1003		return "custom"
1004	case SectionIDType:
1005		return "type"
1006	case SectionIDImport:
1007		return "import"
1008	case SectionIDFunction:
1009		return "function"
1010	case SectionIDTable:
1011		return "table"
1012	case SectionIDMemory:
1013		return "memory"
1014	case SectionIDGlobal:
1015		return "global"
1016	case SectionIDExport:
1017		return "export"
1018	case SectionIDStart:
1019		return "start"
1020	case SectionIDElement:
1021		return "element"
1022	case SectionIDCode:
1023		return "code"
1024	case SectionIDData:
1025		return "data"
1026	case SectionIDDataCount:
1027		return "data_count"
1028	}
1029	return "unknown"
1030}
1031
1032// ValueType is an alias of api.ValueType defined to simplify imports.
1033type ValueType = api.ValueType
1034
1035const (
1036	ValueTypeI32 = api.ValueTypeI32
1037	ValueTypeI64 = api.ValueTypeI64
1038	ValueTypeF32 = api.ValueTypeF32
1039	ValueTypeF64 = api.ValueTypeF64
1040	// TODO: ValueTypeV128 is not exposed in the api pkg yet.
1041	ValueTypeV128 ValueType = 0x7b
1042	// TODO: ValueTypeFuncref is not exposed in the api pkg yet.
1043	ValueTypeFuncref   ValueType = 0x70
1044	ValueTypeExternref           = api.ValueTypeExternref
1045)
1046
1047// ValueTypeName is an alias of api.ValueTypeName defined to simplify imports.
1048func ValueTypeName(t ValueType) string {
1049	if t == ValueTypeFuncref {
1050		return "funcref"
1051	} else if t == ValueTypeV128 {
1052		return "v128"
1053	}
1054	return api.ValueTypeName(t)
1055}
1056
1057func isReferenceValueType(vt ValueType) bool {
1058	return vt == ValueTypeExternref || vt == ValueTypeFuncref
1059}
1060
1061// ExternType is an alias of api.ExternType defined to simplify imports.
1062type ExternType = api.ExternType
1063
1064const (
1065	ExternTypeFunc       = api.ExternTypeFunc
1066	ExternTypeFuncName   = api.ExternTypeFuncName
1067	ExternTypeTable      = api.ExternTypeTable
1068	ExternTypeTableName  = api.ExternTypeTableName
1069	ExternTypeMemory     = api.ExternTypeMemory
1070	ExternTypeMemoryName = api.ExternTypeMemoryName
1071	ExternTypeGlobal     = api.ExternTypeGlobal
1072	ExternTypeGlobalName = api.ExternTypeGlobalName
1073)
1074
1075// ExternTypeName is an alias of api.ExternTypeName defined to simplify imports.
1076func ExternTypeName(t ValueType) string {
1077	return api.ExternTypeName(t)
1078}