package wasm

import (
	
	
	
	
	
	
	
	
	

	
	
	
	
	
)

// Module is a WebAssembly binary representation.
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#modules%E2%91%A8
//
// Differences from the specification:
// * NameSection is the only key ("name") decoded from the SectionIDCustom.
// * ExportSection is represented as a map for lookup convenience.
// * Code.GoFunc is contains any go `func`. It may be present when Code.Body is not.
type Module struct {
	// TypeSection contains the unique FunctionType of functions imported or defined in this module.
	//
	// Note: Currently, there is no type ambiguity in the index as WebAssembly 1.0 only defines function type.
	// In the future, other types may be introduced to support CoreFeatures such as module linking.
	//
	// Note: In the Binary Format, this is SectionIDType.
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#types%E2%91%A0%E2%91%A0
	TypeSection []FunctionType

	// ImportSection contains imported functions, tables, memories or globals required for instantiation
	// (Store.Instantiate).
	//
	// Note: there are no unique constraints relating to the two-level namespace of Import.Module and Import.Name.
	//
	// Note: In the Binary Format, this is SectionIDImport.
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#import-section%E2%91%A0
	ImportSection []Import
	// ImportFunctionCount ImportGlobalCount ImportMemoryCount, and ImportTableCount are
	// the cached import count per ExternType set during decoding.
	ImportFunctionCount,
	ImportGlobalCount,
	ImportMemoryCount,
	ImportTableCount Index
	// ImportPerModule maps a module name to the list of Import to be imported from the module.
	// This is used to do fast import resolution during instantiation.
	ImportPerModule map[string][]*Import

	// FunctionSection contains the index in TypeSection of each function defined in this module.
	//
	// Note: The function Index space begins with imported functions and ends with those defined in this module.
	// For example, if there are two imported functions and one defined in this module, the function Index 3 is defined
	// in this module at FunctionSection[0].
	//
	// Note: FunctionSection is index correlated with the CodeSection. If given the same position, e.g. 2, a function
	// type is at TypeSection[FunctionSection[2]], while its locals and body are at CodeSection[2].
	//
	// Note: In the Binary Format, this is SectionIDFunction.
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-section%E2%91%A0
	FunctionSection []Index

	// TableSection contains each table defined in this module.
	//
	// Note: The table Index space begins with imported tables and ends with those defined in this module.
	// For example, if there are two imported tables and one defined in this module, the table Index 3 is defined in
	// this module at TableSection[0].
	//
	// Note: Version 1.0 (20191205) of the WebAssembly spec allows at most one table definition per module, so the
	// length of the TableSection can be zero or one, and can only be one if there is no imported table.
	//
	// Note: In the Binary Format, this is SectionIDTable.
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-section%E2%91%A0
	TableSection []Table

	// MemorySection contains each memory defined in this module.
	//
	// Note: The memory Index space begins with imported memories and ends with those defined in this module.
	// For example, if there are two imported memories and one defined in this module, the memory Index 3 is defined in
	// this module at TableSection[0].
	//
	// Note: Version 1.0 (20191205) of the WebAssembly spec allows at most one memory definition per module, so the
	// length of the MemorySection can be zero or one, and can only be one if there is no imported memory.
	//
	// Note: In the Binary Format, this is SectionIDMemory.
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0
	MemorySection *Memory

	// GlobalSection contains each global defined in this module.
	//
	// Global indexes are offset by any imported globals because the global index begins with imports, followed by
	// ones defined in this module. For example, if there are two imported globals and three defined in this module, the
	// global at index 3 is defined in this module at GlobalSection[0].
	//
	// Note: In the Binary Format, this is SectionIDGlobal.
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-section%E2%91%A0
	GlobalSection []Global

	// ExportSection contains each export defined in this module.
	//
	// Note: In the Binary Format, this is SectionIDExport.
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A0
	ExportSection []Export
	// Exports maps a name to Export, and is convenient for fast look up of exported instances at runtime.
	// Each item of this map points to an element of ExportSection.
	Exports map[string]*Export

	// StartSection is the index of a function to call before returning from Store.Instantiate.
	//
	// Note: The index here is not the position in the FunctionSection, rather in the function index, which
	// begins with imported functions.
	//
	// Note: In the Binary Format, this is SectionIDStart.
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-section%E2%91%A0
	StartSection *Index

	// Note: In the Binary Format, this is SectionIDElement.
	ElementSection []ElementSegment

	// CodeSection is index-correlated with FunctionSection and contains each
	// function's locals and body.
	//
	// When present, the HostFunctionSection of the same index must be nil.
	//
	// Note: In the Binary Format, this is SectionIDCode.
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0
	CodeSection []Code

	// Note: In the Binary Format, this is SectionIDData.
	DataSection []DataSegment

	// NameSection is set when the SectionIDCustom "name" was successfully decoded from the binary format.
	//
	// Note: This is the only SectionIDCustom defined in the WebAssembly 1.0 (20191205) Binary Format.
	// Others are skipped as they are not used in wazero.
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0
	NameSection *NameSection

	// CustomSections are set when the SectionIDCustom other than "name" were successfully decoded from the binary format.
	//
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0
	CustomSections []*CustomSection

	// DataCountSection is the optional section and holds the number of data segments in the data section.
	//
	// Note: This may exist in WebAssembly 2.0 or WebAssembly 1.0 with CoreFeatureBulkMemoryOperations.
	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section
	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
	DataCountSection *uint32

	// ID is the sha256 value of the source wasm plus the configurations which affect the runtime representation of
	// Wasm binary. This is only used for caching.
	ID ModuleID

	// IsHostModule true if this is the host module, false otherwise.
	IsHostModule bool

	// functionDefinitionSectionInitOnce guards FunctionDefinitionSection so that it is initialized exactly once.
	functionDefinitionSectionInitOnce sync.Once

	// FunctionDefinitionSection is a wazero-specific section.
	FunctionDefinitionSection []FunctionDefinition

	// MemoryDefinitionSection is a wazero-specific section.
	MemoryDefinitionSection []MemoryDefinition

	// DWARFLines is used to emit DWARF based stack trace. This is created from the multiple custom sections
	// as described in https://yurydelendik.github.io/webassembly-dwarf/, though it is not specified in the Wasm
	// specification: https://github.com/WebAssembly/debugging/issues/1
	DWARFLines *wasmdebug.DWARFLines
}

// ModuleID represents sha256 hash value uniquely assigned to Module.
type ModuleID = [sha256.Size]byte

// The wazero specific limitation described at RATIONALE.md.
// TL;DR; We multiply by 8 (to get offsets in bytes) and the multiplication result must be less than 32bit max
const (
	MaximumGlobals       = uint32(1 << 27)
	MaximumFunctionIndex = uint32(1 << 27)
	MaximumTableIndex    = uint32(1 << 27)
)

// AssignModuleID calculates a sha256 checksum on `wasm` and other args, and set Module.ID to the result.
// See the doc on Module.ID on what it's used for.
func ( *Module) ( []byte,  []experimental.FunctionListener,  bool) {
	 := sha256.New()
	.Write()
	// Use the pre-allocated space backed by m.ID below.

	// Write the existence of listeners to the checksum per function.
	for ,  := range  {
		binary.LittleEndian.PutUint32(.ID[:], uint32())
		.ID[4] = boolToByte( != nil)
		.Write(.ID[:5])
	}
	// Write the flag of ensureTermination to the checksum.
	.ID[0] = boolToByte()
	.Write(.ID[:1])
	// Get checksum by passing the slice underlying m.ID.
	.Sum(.ID[:0])
}

func boolToByte( bool) ( byte) {
	if  {
		 = 1
	}
	return
}

// typeOfFunction returns the wasm.FunctionType for the given function space index or nil.
func ( *Module) ( Index) *FunctionType {
	,  := uint32(len(.TypeSection)), .ImportFunctionCount
	if  <  {
		// Imports are not exclusively functions. This is the current function index in the loop.
		 := Index(0)
		for  := range .ImportSection {
			 := &.ImportSection[]
			if .Type != ExternTypeFunc {
				continue
			}
			if  ==  {
				if .DescFunc >=  {
					return nil
				}
				return &.TypeSection[.DescFunc]
			}
			++
		}
	}

	 :=  - .ImportFunctionCount
	if  >= uint32(len(.FunctionSection)) {
		return nil
	}
	 := .FunctionSection[]
	if  >=  {
		return nil
	}
	return &.TypeSection[]
}

func ( *Module) ( api.CoreFeatures) error {
	for  := range .TypeSection {
		 := &.TypeSection[]
		.CacheNumInUint64()
	}

	if  := .validateStartSection();  != nil {
		return 
	}

	, , , ,  := .AllDeclarations()
	if  != nil {
		return 
	}

	if  = .validateImports();  != nil {
		return 
	}

	if  = .validateGlobals(, uint32(len()), MaximumGlobals);  != nil {
		return 
	}

	if  = .validateMemory(, , );  != nil {
		return 
	}

	if  = .validateExports(, , , , );  != nil {
		return 
	}

	if .CodeSection != nil {
		if  = .validateFunctions(, , , , , MaximumFunctionIndex);  != nil {
			return 
		}
	} // No need to validate host functions as NewHostModule validates

	if  = .validateTable(, , MaximumTableIndex);  != nil {
		return 
	}

	if  = .validateDataCountSection();  != nil {
		return 
	}
	return nil
}

func ( *Module) () error {
	// Check the start function is valid.
	// TODO: this should be verified during decode so that errors have the correct source positions
	if .StartSection != nil {
		 := *.StartSection
		 := .typeOfFunction()
		if  == nil { // TODO: move this check to decoder so that a module can never be decoded invalidly
			return fmt.Errorf("invalid start function: func[%d] has an invalid type", )
		}
		if len(.Params) > 0 || len(.Results) > 0 {
			return fmt.Errorf("invalid start function: func[%d] must have an empty (nullary) signature: %s", , )
		}
	}
	return nil
}

func ( *Module) ( []GlobalType, ,  uint32) error {
	if uint32(len()) >  {
		return fmt.Errorf("too many globals in a module")
	}

	// Global initialization constant expression can only reference the imported globals.
	// See the note on https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#constant-expressions%E2%91%A0
	 := [:.ImportGlobalCount]
	for  := range .GlobalSection {
		 := &.GlobalSection[]
		if  := validateConstExpression(, , &.Init, .Type.ValType);  != nil {
			return 
		}
	}
	return nil
}

func ( *Module) ( api.CoreFeatures,  []Index,  []GlobalType,  *Memory,  []Table,  uint32) error {
	if uint32(len()) >  {
		return fmt.Errorf("too many functions (%d) in a module", len())
	}

	 := .SectionElementCount(SectionIDFunction)
	 := .SectionElementCount(SectionIDCode)
	if  == 0 &&  == 0 {
		return nil
	}

	 := .SectionElementCount(SectionIDType)
	if  !=  {
		return fmt.Errorf("code count (%d) != function count (%d)", , )
	}

	,  := .declaredFunctionIndexes()
	if  != nil {
		return 
	}

	// Create bytes.Reader once as it causes allocation, and
	// we frequently need it (e.g. on every If instruction).
	 := bytes.NewReader(nil)
	// Also, we reuse the stacks across multiple function validations to reduce allocations.
	 := &stacks{}
	for ,  := range .FunctionSection {
		if  >=  {
			return fmt.Errorf("invalid %s: type section index %d out of range", .funcDesc(SectionIDFunction, Index()), )
		}
		 := &.CodeSection[]
		if .GoFunc != nil {
			continue
		}
		if  = .validateFunction(, , Index(), , , , , , );  != nil {
			return fmt.Errorf("invalid %s: %w", .funcDesc(SectionIDFunction, Index()), )
		}
	}
	return nil
}

// declaredFunctionIndexes returns a set of function indexes that can be used as an immediate for OpcodeRefFunc instruction.
//
// The criteria for which function indexes can be available for that instruction is vague in the spec:
//
//   - "References: the list of function indices that occur in the module outside functions and can hence be used to form references inside them."
//   - https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/valid/conventions.html#contexts
//   - "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."
//   - https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/valid/modules.html#valid-module
//
// To clarify, we reverse-engineer logic required to pass the WebAssembly Core specification 2.0 test suite:
// https://github.com/WebAssembly/spec/blob/d39195773112a22b245ffbe864bab6d1182ccb06/test/core/ref_func.wast#L78-L115
//
// To summarize, the function indexes OpcodeRefFunc can refer include:
//   - existing in an element section regardless of its mode (active, passive, declarative).
//   - defined as globals whose value type is ValueRefFunc.
//   - used as an exported function.
//
// See https://github.com/WebAssembly/reference-types/issues/31
// See https://github.com/WebAssembly/reference-types/issues/76
func ( *Module) () ( map[Index]struct{},  error) {
	 = map[uint32]struct{}{}

	for  := range .ExportSection {
		 := &.ExportSection[]
		if .Type == ExternTypeFunc {
			[.Index] = struct{}{}
		}
	}

	for  := range .GlobalSection {
		 := &.GlobalSection[]
		if .Init.Opcode == OpcodeRefFunc {
			var  uint32
			, _,  = leb128.LoadUint32(.Init.Data)
			if  != nil {
				 = fmt.Errorf("%s[%d] failed to initialize: %w", SectionIDName(SectionIDGlobal), , )
				return
			}
			[] = struct{}{}
		}
	}

	for  := range .ElementSection {
		 := &.ElementSection[]
		for ,  := range .Init {
			if  != ElementInitNullReference {
				[] = struct{}{}
			}
		}
	}
	return
}

func ( *Module) ( SectionID,  Index) string {
	// Try to improve the error message by collecting any exports:
	var  []string
	 :=  + .ImportFunctionCount
	for  := range .ExportSection {
		 := &.ExportSection[]
		if .Index ==  && .Type == ExternTypeFunc {
			 = append(, fmt.Sprintf("%q", .Name))
		}
	}
	 := SectionIDName()
	if  == nil {
		return fmt.Sprintf("%s[%d]", , )
	}
	sort.Strings() // go map keys do not iterate consistently
	return fmt.Sprintf("%s[%d] export[%s]", , , strings.Join(, ","))
}

func ( *Module) ( *Memory,  []GlobalType,  api.CoreFeatures) error {
	var  int
	for  := range .DataSection {
		 := &.DataSection[]
		if !.IsPassive() {
			++
		}
	}
	if  > 0 &&  == nil {
		return fmt.Errorf("unknown memory")
	}

	// Constant expression can only reference imported globals.
	// https://github.com/WebAssembly/spec/blob/5900d839f38641989a9d8df2df4aee0513365d39/test/core/data.wast#L84-L91
	 := [:.ImportGlobalCount]
	for  := range .DataSection {
		 := &.DataSection[]
		if !.IsPassive() {
			if  := validateConstExpression(, 0, &.OffsetExpression, ValueTypeI32);  != nil {
				return fmt.Errorf("calculate offset: %w", )
			}
		}
	}
	return nil
}

func ( *Module) ( api.CoreFeatures) error {
	for  := range .ImportSection {
		 := &.ImportSection[]
		if .Module == "" {
			return fmt.Errorf("import[%d] has an empty module name", )
		}
		switch .Type {
		case ExternTypeFunc:
			if int(.DescFunc) >= len(.TypeSection) {
				return fmt.Errorf("invalid import[%q.%q] function: type index out of range", .Module, .Name)
			}
		case ExternTypeGlobal:
			if !.DescGlobal.Mutable {
				continue
			}
			if  := .RequireEnabled(api.CoreFeatureMutableGlobal);  != nil {
				return fmt.Errorf("invalid import[%q.%q] global: %w", .Module, .Name, )
			}
		}
	}
	return nil
}

func ( *Module) ( api.CoreFeatures,  []Index,  []GlobalType,  *Memory,  []Table) error {
	for  := range .ExportSection {
		 := &.ExportSection[]
		 := .Index
		switch .Type {
		case ExternTypeFunc:
			if  >= uint32(len()) {
				return fmt.Errorf("unknown function for export[%q]", .Name)
			}
		case ExternTypeGlobal:
			if  >= uint32(len()) {
				return fmt.Errorf("unknown global for export[%q]", .Name)
			}
			if ![].Mutable {
				continue
			}
			if  := .RequireEnabled(api.CoreFeatureMutableGlobal);  != nil {
				return fmt.Errorf("invalid export[%q] global[%d]: %w", .Name, , )
			}
		case ExternTypeMemory:
			if  > 0 ||  == nil {
				return fmt.Errorf("memory for export[%q] out of range", .Name)
			}
		case ExternTypeTable:
			if  >= uint32(len()) {
				return fmt.Errorf("table for export[%q] out of range", .Name)
			}
		}
	}
	return nil
}

func validateConstExpression( []GlobalType,  uint32,  *ConstantExpression,  ValueType) ( error) {
	var  ValueType
	switch .Opcode {
	case OpcodeI32Const:
		// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
		_, _,  = leb128.LoadInt32(.Data)
		if  != nil {
			return fmt.Errorf("read i32: %w", )
		}
		 = ValueTypeI32
	case OpcodeI64Const:
		// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
		_, _,  = leb128.LoadInt64(.Data)
		if  != nil {
			return fmt.Errorf("read i64: %w", )
		}
		 = ValueTypeI64
	case OpcodeF32Const:
		_,  = ieee754.DecodeFloat32(.Data)
		if  != nil {
			return fmt.Errorf("read f32: %w", )
		}
		 = ValueTypeF32
	case OpcodeF64Const:
		_,  = ieee754.DecodeFloat64(.Data)
		if  != nil {
			return fmt.Errorf("read f64: %w", )
		}
		 = ValueTypeF64
	case OpcodeGlobalGet:
		, ,  := leb128.LoadUint32(.Data)
		if  != nil {
			return fmt.Errorf("read index of global: %w", )
		}
		if uint32(len()) <=  {
			return fmt.Errorf("global index out of range")
		}
		 = [].ValType
	case OpcodeRefNull:
		if len(.Data) == 0 {
			return fmt.Errorf("read reference type for ref.null: %w", io.ErrShortBuffer)
		}
		 := .Data[0]
		if  != RefTypeFuncref &&  != RefTypeExternref {
			return fmt.Errorf("invalid type for ref.null: 0x%x", )
		}
		 = 
	case OpcodeRefFunc:
		, ,  := leb128.LoadUint32(.Data)
		if  != nil {
			return fmt.Errorf("read i32: %w", )
		} else if  >=  {
			return fmt.Errorf("ref.func index out of range [%d] with length %d", , -1)
		}
		 = ValueTypeFuncref
	case OpcodeVecV128Const:
		if len(.Data) != 16 {
			return fmt.Errorf("%s needs 16 bytes but was %d bytes", OpcodeVecV128ConstName, len(.Data))
		}
		 = ValueTypeV128
	default:
		return fmt.Errorf("invalid opcode for const expression: 0x%x", .Opcode)
	}

	if  !=  {
		return fmt.Errorf("const expression type mismatch expected %s but got %s",
			ValueTypeName(), ValueTypeName())
	}
	return nil
}

func ( *Module) () ( error) {
	if .DataCountSection != nil && int(*.DataCountSection) != len(.DataSection) {
		 = fmt.Errorf("data count section (%d) doesn't match the length of data section (%d)",
			*.DataCountSection, len(.DataSection))
	}
	return
}

func ( *ModuleInstance) ( *Module,  func( Index) Reference) {
	 := .Globals[:.ImportGlobalCount]

	 := .Engine
	 := .OwnsGlobals()
	for  := Index(0);  < Index(len(.GlobalSection)); ++ {
		 := &.GlobalSection[]
		 := &GlobalInstance{}
		if  {
			.Me = 
			.Index =  + .ImportGlobalCount
		}
		.Globals[+.ImportGlobalCount] = 
		.Type = .Type
		.initialize(, &.Init, )
	}
}

func paramNames( IndirectNameMap,  uint32,  int) []string {
	for  := range  {
		 := &[]
		// Only build parameter names if we have one for each.
		if .Index !=  || len(.NameMap) <  {
			continue
		}

		 := make([]string, )
		for  := range .NameMap {
			 := &.NameMap[]
			if int(.Index) <  {
				[.Index] = .Name
			}
		}
		return 
	}
	return nil
}

func ( *ModuleInstance) ( *Module,  experimental.MemoryAllocator) {
	 := .MemorySection
	if  != nil {
		.MemoryInstance = NewMemoryInstance(, , .Engine)
		.MemoryInstance.definition = &.MemoryDefinitionSection[0]
	}
}

// Index is the offset in an index, not necessarily an absolute position in a Module section. This is because
// indexs are often preceded by a corresponding type in the Module.ImportSection.
//
// For example, the function index starts with any ExternTypeFunc in the Module.ImportSection followed by
// the Module.FunctionSection
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-index
type Index = uint32

// FunctionType is a possibly empty function signature.
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-types%E2%91%A0
type FunctionType struct {
	// Params are the possibly empty sequence of value types accepted by a function with this signature.
	Params []ValueType

	// Results are the possibly empty sequence of value types returned by a function with this signature.
	//
	// Note: In WebAssembly 1.0 (20191205), there can be at most one result.
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#result-types%E2%91%A0
	Results []ValueType

	// string is cached as it is used both for String and key
	string string

	// ParamNumInUint64 is the number of uint64 values requires to represent the Wasm param type.
	ParamNumInUint64 int

	// ResultsNumInUint64 is the number of uint64 values requires to represent the Wasm result type.
	ResultNumInUint64 int
}

func ( *FunctionType) () {
	if .ParamNumInUint64 == 0 {
		for ,  := range .Params {
			.ParamNumInUint64++
			if  == ValueTypeV128 {
				.ParamNumInUint64++
			}
		}
	}

	if .ResultNumInUint64 == 0 {
		for ,  := range .Results {
			.ResultNumInUint64++
			if  == ValueTypeV128 {
				.ResultNumInUint64++
			}
		}
	}
}

// EqualsSignature returns true if the function type has the same parameters and results.
func ( *FunctionType) ( []ValueType,  []ValueType) bool {
	return bytes.Equal(.Params, ) && bytes.Equal(.Results, )
}

// key gets or generates the key for Store.typeIDs. e.g. "i32_v" for one i32 parameter and no (void) result.
func ( *FunctionType) () string {
	if .string != "" {
		return .string
	}
	var  string
	for ,  := range .Params {
		 += ValueTypeName()
	}
	if len(.Params) == 0 {
		 += "v_"
	} else {
		 += "_"
	}
	for ,  := range .Results {
		 += ValueTypeName()
	}
	if len(.Results) == 0 {
		 += "v"
	}
	.string = 
	return 
}

// String implements fmt.Stringer.
func ( *FunctionType) () string {
	return .key()
}

// Import is the binary representation of an import indicated by Type
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-import
type Import struct {
	Type ExternType
	// Module is the possibly empty primary namespace of this import
	Module string
	// Module is the possibly empty secondary namespace of this import
	Name string
	// DescFunc is the index in Module.TypeSection when Type equals ExternTypeFunc
	DescFunc Index
	// DescTable is the inlined Table when Type equals ExternTypeTable
	DescTable Table
	// DescMem is the inlined Memory when Type equals ExternTypeMemory
	DescMem *Memory
	// DescGlobal is the inlined GlobalType when Type equals ExternTypeGlobal
	DescGlobal GlobalType
	// IndexPerType has the index of this import per ExternType.
	IndexPerType Index
}

// Memory describes the limits of pages (64KB) in a memory.
type Memory struct {
	Min, Cap, Max uint32
	// IsMaxEncoded true if the Max is encoded in the original binary.
	IsMaxEncoded bool
	// IsShared true if the memory is shared for access from multiple agents.
	IsShared bool
}

// Validate ensures values assigned to Min, Cap and Max are within valid thresholds.
func ( *Memory) ( uint32) error {
	, ,  := .Min, .Cap, .Max

	if  >  {
		return fmt.Errorf("max %d pages (%s) over limit of %d pages (%s)",
			, PagesToUnitOfBytes(), , PagesToUnitOfBytes())
	} else if  >  {
		return fmt.Errorf("min %d pages (%s) over limit of %d pages (%s)",
			, PagesToUnitOfBytes(), , PagesToUnitOfBytes())
	} else if  >  {
		return fmt.Errorf("min %d pages (%s) > max %d pages (%s)",
			, PagesToUnitOfBytes(), , PagesToUnitOfBytes())
	} else if  <  {
		return fmt.Errorf("capacity %d pages (%s) less than minimum %d pages (%s)",
			, PagesToUnitOfBytes(), , PagesToUnitOfBytes())
	} else if  >  {
		return fmt.Errorf("capacity %d pages (%s) over limit of %d pages (%s)",
			, PagesToUnitOfBytes(), , PagesToUnitOfBytes())
	}
	return nil
}

type GlobalType struct {
	ValType ValueType
	Mutable bool
}

type Global struct {
	Type GlobalType
	Init ConstantExpression
}

type ConstantExpression struct {
	Opcode Opcode
	Data   []byte
}

// Export is the binary representation of an export indicated by Type
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-export
type Export struct {
	Type ExternType

	// Name is what the host refers to this definition as.
	Name string

	// Index is the index of the definition to export, the index is by Type
	// e.g. If ExternTypeFunc, this is a position in the function index.
	Index Index
}

// Code is an entry in the Module.CodeSection containing the locals and body of the function.
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-code
type Code struct {
	// LocalTypes are any function-scoped variables in insertion order.
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-local
	LocalTypes []ValueType

	// Body is a sequence of expressions ending in OpcodeEnd
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-expr
	Body []byte

	// GoFunc is non-nil when IsHostFunction and defined in go, either
	// api.GoFunction or api.GoModuleFunction. When present, LocalTypes and Body must
	// be nil.
	//
	// Note: This has no serialization format, so is not encodable.
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#host-functions%E2%91%A2
	GoFunc interface{}

	// BodyOffsetInCodeSection is the offset of the beginning of the body in the code section.
	// This is used for DWARF based stack trace where a program counter represents an offset in code section.
	BodyOffsetInCodeSection uint64
}

type DataSegment struct {
	OffsetExpression ConstantExpression
	Init             []byte
	Passive          bool
}

// IsPassive returns true if this data segment is "passive" in the sense that memory offset and
// index is determined at runtime and used by OpcodeMemoryInitName instruction in the bulk memory
// operations proposal.
//
// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
func ( *DataSegment) () bool {
	return .Passive
}

// NameSection represent the known custom name subsections defined in the WebAssembly Binary Format
//
// Note: This can be nil if no names were decoded for any reason including configuration.
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0
type NameSection struct {
	// ModuleName is the symbolic identifier for a module. e.g. math
	//
	// Note: This can be empty for any reason including configuration.
	ModuleName string

	// FunctionNames is an association of a function index to its symbolic identifier. e.g. add
	//
	// * the key (idx) is in the function index, where module defined functions are preceded by imported ones.
	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#functions%E2%91%A7
	//
	// For example, assuming the below text format is the second import, you would expect FunctionNames[1] = "mul"
	//	(import "Math" "Mul" (func $mul (param $x f32) (param $y f32) (result f32)))
	//
	// Note: FunctionNames are only used for debugging. At runtime, functions are called based on raw numeric index.
	// Note: This can be nil for any reason including configuration.
	FunctionNames NameMap

	// LocalNames contains symbolic names for function parameters or locals that have one.
	//
	// Note: In the Text Format, function local names can inherit parameter
	// names from their type. Here are some examples:
	//  * (module (import (func (param $x i32) (param i32))) (func (type 0))) = [{0, {x,0}}]
	//  * (module (import (func (param i32) (param $y i32))) (func (type 0) (local $z i32))) = [0, [{y,1},{z,2}]]
	//  * (module (func (param $x i32) (local $y i32) (local $z i32))) = [{x,0},{y,1},{z,2}]
	//
	// Note: LocalNames are only used for debugging. At runtime, locals are called based on raw numeric index.
	// Note: This can be nil for any reason including configuration.
	LocalNames IndirectNameMap

	// ResultNames is a wazero-specific mechanism to store result names.
	ResultNames IndirectNameMap
}

// CustomSection contains the name and raw data of a custom section.
type CustomSection struct {
	Name string
	Data []byte
}

// NameMap associates an index with any associated names.
//
// Note: Often the index bridges multiple sections. For example, the function index starts with any
// ExternTypeFunc in the Module.ImportSection followed by the Module.FunctionSection
//
// Note: NameMap is unique by NameAssoc.Index, but NameAssoc.Name needn't be unique.
// Note: When encoding in the Binary format, this must be ordered by NameAssoc.Index
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-namemap
type NameMap []NameAssoc

type NameAssoc struct {
	Index Index
	Name  string
}

// IndirectNameMap associates an index with an association of names.
//
// Note: IndirectNameMap is unique by NameMapAssoc.Index, but NameMapAssoc.NameMap needn't be unique.
// Note: When encoding in the Binary format, this must be ordered by NameMapAssoc.Index
// https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-indirectnamemap
type IndirectNameMap []NameMapAssoc

type NameMapAssoc struct {
	Index   Index
	NameMap NameMap
}

// AllDeclarations returns all declarations for functions, globals, memories and tables in a module including imported ones.
func ( *Module) () ( []Index,  []GlobalType,  *Memory,  []Table,  error) {
	for  := range .ImportSection {
		 := &.ImportSection[]
		switch .Type {
		case ExternTypeFunc:
			 = append(, .DescFunc)
		case ExternTypeGlobal:
			 = append(, .DescGlobal)
		case ExternTypeMemory:
			 = .DescMem
		case ExternTypeTable:
			 = append(, .DescTable)
		}
	}

	 = append(, .FunctionSection...)
	for  := range .GlobalSection {
		 := &.GlobalSection[]
		 = append(, .Type)
	}
	if .MemorySection != nil {
		if  != nil { // shouldn't be possible due to Validate
			 = errors.New("at most one table allowed in module")
			return
		}
		 = .MemorySection
	}
	if .TableSection != nil {
		 = append(, .TableSection...)
	}
	return
}

// SectionID identifies the sections of a Module in the WebAssembly 1.0 (20191205) Binary Format.
//
// Note: these are defined in the wasm package, instead of the binary package, as a key per section is needed regardless
// of format, and deferring to the binary type avoids confusion.
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
type SectionID = byte

const (
	// SectionIDCustom includes the standard defined NameSection and possibly others not defined in the standard.
	SectionIDCustom SectionID = iota // don't add anything not in https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
	SectionIDType
	SectionIDImport
	SectionIDFunction
	SectionIDTable
	SectionIDMemory
	SectionIDGlobal
	SectionIDExport
	SectionIDStart
	SectionIDElement
	SectionIDCode
	SectionIDData

	// SectionIDDataCount may exist in WebAssembly 2.0 or WebAssembly 1.0 with CoreFeatureBulkMemoryOperations enabled.
	//
	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section
	// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions
	SectionIDDataCount
)

// SectionIDName returns the canonical name of a module section.
// https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
func ( SectionID) string {
	switch  {
	case SectionIDCustom:
		return "custom"
	case SectionIDType:
		return "type"
	case SectionIDImport:
		return "import"
	case SectionIDFunction:
		return "function"
	case SectionIDTable:
		return "table"
	case SectionIDMemory:
		return "memory"
	case SectionIDGlobal:
		return "global"
	case SectionIDExport:
		return "export"
	case SectionIDStart:
		return "start"
	case SectionIDElement:
		return "element"
	case SectionIDCode:
		return "code"
	case SectionIDData:
		return "data"
	case SectionIDDataCount:
		return "data_count"
	}
	return "unknown"
}

// ValueType is an alias of api.ValueType defined to simplify imports.
type ValueType = api.ValueType

const (
	ValueTypeI32 = api.ValueTypeI32
	ValueTypeI64 = api.ValueTypeI64
	ValueTypeF32 = api.ValueTypeF32
	ValueTypeF64 = api.ValueTypeF64
	// TODO: ValueTypeV128 is not exposed in the api pkg yet.
	ValueTypeV128 ValueType = 0x7b
	// TODO: ValueTypeFuncref is not exposed in the api pkg yet.
	ValueTypeFuncref   ValueType = 0x70
	ValueTypeExternref           = api.ValueTypeExternref
)

// ValueTypeName is an alias of api.ValueTypeName defined to simplify imports.
func ( ValueType) string {
	if  == ValueTypeFuncref {
		return "funcref"
	} else if  == ValueTypeV128 {
		return "v128"
	}
	return api.ValueTypeName()
}

func isReferenceValueType( ValueType) bool {
	return  == ValueTypeExternref ||  == ValueTypeFuncref
}

// ExternType is an alias of api.ExternType defined to simplify imports.
type ExternType = api.ExternType

const (
	ExternTypeFunc       = api.ExternTypeFunc
	ExternTypeFuncName   = api.ExternTypeFuncName
	ExternTypeTable      = api.ExternTypeTable
	ExternTypeTableName  = api.ExternTypeTableName
	ExternTypeMemory     = api.ExternTypeMemory
	ExternTypeMemoryName = api.ExternTypeMemoryName
	ExternTypeGlobal     = api.ExternTypeGlobal
	ExternTypeGlobalName = api.ExternTypeGlobalName
)

// ExternTypeName is an alias of api.ExternTypeName defined to simplify imports.
func ( ValueType) string {
	return api.ExternTypeName()
}