package wasm

import (
	
	
	
	
	
	

	
	
	
)

// The wazero specific limitation described at RATIONALE.md.
const maximumValuesOnStack = 1 << 27

// validateFunction validates the instruction sequence of a function.
// following the specification https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#instructions%E2%91%A2.
//
// * idx is the index in the FunctionSection
// * functions are the function index, which is prefixed by imports. The value is the TypeSection index.
// * globals are the global index, which is prefixed by imports.
// * memory is the potentially imported memory and can be nil.
// * table is the potentially imported table and can be nil.
// * declaredFunctionIndexes is the set of function indexes declared by declarative element segments which can be acceed by OpcodeRefFunc instruction.
//
// Returns an error if the instruction sequence is not valid,
// or potentially it can exceed the maximum number of values on the stack.
func ( *Module) ( *stacks,  api.CoreFeatures,  Index,  []Index,
	 []GlobalType,  *Memory,  []Table,  map[Index]struct{},  *bytes.Reader,
) error {
	return .validateFunctionWithMaxStackValues(, , , , , , , maximumValuesOnStack, , )
}

func readMemArg( uint64,  []byte) (,  uint32,  uint64,  error) {
	, ,  := leb128.LoadUint32([:])
	if  != nil {
		 = fmt.Errorf("read memory align: %v", )
		return
	}
	if  >= 32 {
		// Prevent 1<<align uint32 overflow.
		 = fmt.Errorf("invalid memory alignment")
		return
	}
	 += 

	, ,  = leb128.LoadUint32([+:])
	if  != nil {
		 = fmt.Errorf("read memory offset: %v", )
		return
	}

	 += 
	return , , , nil
}

// validateFunctionWithMaxStackValues is like validateFunction, but allows overriding maxStackValues for testing.
//
// * stacks is to track the state of Wasm value and control frame stacks at anypoint of execution, and reused to reduce allocation.
// * maxStackValues is the maximum height of values stack which the target is allowed to reach.
func ( *Module) (
	 *stacks,
	 api.CoreFeatures,
	 Index,
	 []Index,
	 []GlobalType,
	 *Memory,
	 []Table,
	 int,
	 map[Index]struct{},
	 *bytes.Reader,
) error {
	 := &.TypeSection[.FunctionSection[]]
	 := &.CodeSection[]
	 := .Body
	 := .LocalTypes

	.reset()
	 := &.vs
	// We start with the outermost control block which is for function return if the code branches into it.
	 := &.cs

	// Now start walking through all the instructions in the body while tracking
	// control blocks and value types to check the validity of all instructions.
	for  := uint64(0);  < uint64(len()); ++ {
		 := []
		if false {
			var  string
			if  == OpcodeMiscPrefix {
				 = MiscInstructionName([+1])
			} else if  == OpcodeVecPrefix {
				 = VectorInstructionName([+1])
			} else if  == OpcodeAtomicPrefix {
				 = AtomicInstructionName([+1])
			} else {
				 = InstructionName()
			}
			fmt.Printf("handling %s, stack=%s, blocks: %v\n", , .stack, )
		}

		if len(.stack) == 0 {
			return fmt.Errorf("unexpected end of function at pc=%#x", )
		}

		if OpcodeI32Load <=  &&  <= OpcodeI64Store32 {
			if  == nil {
				return fmt.Errorf("memory must exist for %s", InstructionName())
			}
			++
			, , ,  := readMemArg(, )
			if  != nil {
				return 
			}
			 +=  - 1
			switch  {
			case OpcodeI32Load:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeF32Load:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeF32)
			case OpcodeI32Store:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeF32Store:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeF32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeI64Load:
				if 1<< > 64/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeF64Load:
				if 1<< > 64/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeF64)
			case OpcodeI64Store:
				if 1<< > 64/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeF64Store:
				if 1<< > 64/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeF64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeI32Load8S:
				if 1<< > 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeI32Load8U:
				if 1<< > 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeI64Load8S, OpcodeI64Load8U:
				if 1<< > 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeI32Store8:
				if 1<< > 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeI64Store8:
				if 1<< > 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeI32Load16S, OpcodeI32Load16U:
				if 1<< > 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeI64Load16S, OpcodeI64Load16U:
				if 1<< > 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeI32Store16:
				if 1<< > 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeI64Store16:
				if 1<< > 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeI64Load32S, OpcodeI64Load32U:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeI64Store32:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			}
		} else if OpcodeMemorySize <=  &&  <= OpcodeMemoryGrow {
			if  == nil {
				return fmt.Errorf("memory must exist for %s", InstructionName())
			}
			++
			, ,  := leb128.LoadUint32([:])
			if  != nil {
				return fmt.Errorf("read immediate: %v", )
			}
			if  != 0 ||  != 1 {
				return fmt.Errorf("memory instruction reserved bytes not zero with 1 byte")
			}
			switch Opcode() {
			case OpcodeMemoryGrow:
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeMemorySize:
				.push(ValueTypeI32)
			}
			 +=  - 1
		} else if OpcodeI32Const <=  &&  <= OpcodeF64Const {
			++
			switch Opcode() {
			case OpcodeI32Const:
				, ,  := leb128.LoadInt32([:])
				if  != nil {
					return fmt.Errorf("read i32 immediate: %s", )
				}
				 +=  - 1
				.push(ValueTypeI32)
			case OpcodeI64Const:
				, ,  := leb128.LoadInt64([:])
				if  != nil {
					return fmt.Errorf("read i64 immediate: %v", )
				}
				.push(ValueTypeI64)
				 +=  - 1
			case OpcodeF32Const:
				.push(ValueTypeF32)
				 += 3
			case OpcodeF64Const:
				.push(ValueTypeF64)
				 += 7
			}
		} else if OpcodeLocalGet <=  &&  <= OpcodeGlobalSet {
			++
			, ,  := leb128.LoadUint32([:])
			if  != nil {
				return fmt.Errorf("read immediate: %v", )
			}
			 +=  - 1
			switch  {
			case OpcodeLocalGet:
				 := uint32(len(.Params))
				if  := uint32(len()) + ;  >=  {
					return fmt.Errorf("invalid local index for %s %d >= %d(=len(locals)+len(parameters))",
						OpcodeLocalGetName, , )
				}
				if  <  {
					.push(.Params[])
				} else {
					.push([-])
				}
			case OpcodeLocalSet:
				 := uint32(len(.Params))
				if  := uint32(len()) + ;  >=  {
					return fmt.Errorf("invalid local index for %s %d >= %d(=len(locals)+len(parameters))",
						OpcodeLocalSetName, , )
				}
				var  ValueType
				if  <  {
					 = .Params[]
				} else {
					 = [-]
				}
				if  := .popAndVerifyType();  != nil {
					return 
				}
			case OpcodeLocalTee:
				 := uint32(len(.Params))
				if  := uint32(len()) + ;  >=  {
					return fmt.Errorf("invalid local index for %s %d >= %d(=len(locals)+len(parameters))",
						OpcodeLocalTeeName, , )
				}
				var  ValueType
				if  <  {
					 = .Params[]
				} else {
					 = [-]
				}
				if  := .popAndVerifyType();  != nil {
					return 
				}
				.push()
			case OpcodeGlobalGet:
				if  >= uint32(len()) {
					return fmt.Errorf("invalid index for %s", OpcodeGlobalGetName)
				}
				.push([].ValType)
			case OpcodeGlobalSet:
				if  >= uint32(len()) {
					return fmt.Errorf("invalid global index")
				} else if ![].Mutable {
					return fmt.Errorf("%s when not mutable", OpcodeGlobalSetName)
				} else if  := .popAndVerifyType(
					[].ValType);  != nil {
					return 
				}
			}
		} else if  == OpcodeBr {
			++
			, ,  := leb128.LoadUint32([:])
			if  != nil {
				return fmt.Errorf("read immediate: %v", )
			} else if int() >= len(.stack) {
				return fmt.Errorf("invalid %s operation: index out of range", OpcodeBrName)
			}
			 +=  - 1
			// Check type soundness.
			 := &.stack[len(.stack)-int()-1]
			var  []ValueType
			if .op == OpcodeLoop {
				 = .blockType.Params
			} else {
				 = .blockType.Results
			}
			if  = .popResults(, , false);  != nil {
				return 
			}
			// br instruction is stack-polymorphic.
			.unreachable()
		} else if  == OpcodeBrIf {
			++
			, ,  := leb128.LoadUint32([:])
			if  != nil {
				return fmt.Errorf("read immediate: %v", )
			} else if int() >= len(.stack) {
				return fmt.Errorf(
					"invalid ln param given for %s: index=%d with %d for the current label stack length",
					OpcodeBrIfName, , len(.stack))
			}
			 +=  - 1
			if  := .popAndVerifyType(ValueTypeI32);  != nil {
				return fmt.Errorf("cannot pop the required operand for %s", OpcodeBrIfName)
			}
			// Check type soundness.
			 := &.stack[len(.stack)-int()-1]
			var  []ValueType
			if .op == OpcodeLoop {
				 = .blockType.Params
			} else {
				 = .blockType.Results
			}
			if  := .popResults(, , false);  != nil {
				return 
			}
			// Push back the result
			for ,  := range  {
				.push()
			}
		} else if  == OpcodeBrTable {
			++
			.Reset([:])
			, ,  := leb128.DecodeUint32()
			if  != nil {
				return fmt.Errorf("read immediate: %w", )
			}

			.ls = .ls[:0]
			for  := uint32(0);  < ; ++ {
				, ,  := leb128.DecodeUint32()
				if  != nil {
					return fmt.Errorf("read immediate: %w", )
				}
				 += 
				.ls = append(.ls, )
			}
			, ,  := leb128.DecodeUint32()
			if  != nil {
				return fmt.Errorf("read immediate: %w", )
			} else if int() >= len(.stack) {
				return fmt.Errorf(
					"invalid ln param given for %s: ln=%d with %d for the current label stack length",
					OpcodeBrTableName, , len(.stack))
			}
			 +=  +  - 1
			// Check type soundness.
			if  := .popAndVerifyType(ValueTypeI32);  != nil {
				return fmt.Errorf("cannot pop the required operand for %s", OpcodeBrTableName)
			}
			 := &.stack[len(.stack)-1-int()]
			var  []ValueType
			// Below, we might modify the slice in case of unreachable. Therefore,
			// we have to copy the content of block result types, otherwise the original
			// function type might result in invalid value types if the block is the outermost label
			// which equals the function's type.
			if .op != OpcodeLoop { // Loop operation doesn't require results since the continuation is the beginning of the loop.
				 = slices.Clone(.blockType.Results)
			} else {
				 = slices.Clone(.blockType.Params)
			}

			if .IsEnabled(api.CoreFeatureReferenceTypes) {
				// As of reference-types proposal, br_table on unreachable state
				// can choose unknown types for expected parameter types for each label.
				// https://github.com/WebAssembly/reference-types/pull/116
				for  := range  {
					 := len() - 1 - 
					 := []
					,  := .pop()
					if  != nil {
						return 
					}
					if  == valueTypeUnknown {
						// Re-assign the expected type to unknown.
						[] = valueTypeUnknown
					} else if  !=  {
						return typeMismatchError(true, OpcodeBrTableName, , , )
					}
				}
			} else {
				if  = .popResults(, , false);  != nil {
					return 
				}
			}

			for ,  := range .ls {
				if int() >= len(.stack) {
					return fmt.Errorf("invalid l param given for %s", OpcodeBrTableName)
				}
				 := &.stack[len(.stack)-1-int()]
				var  []ValueType
				if .op != OpcodeLoop {
					 = .blockType.Results
				} else {
					 = .blockType.Params
				}
				if len() != len() {
					return fmt.Errorf("inconsistent block type length for %s at %d; %v (ln=%d) != %v (l=%d)", OpcodeBrTableName, , , , , )
				}
				for  := range  {
					if [] != valueTypeUnknown && [] != [] {
						return fmt.Errorf("incosistent block type for %s at %d", OpcodeBrTableName, )
					}
				}
			}

			// br_table instruction is stack-polymorphic.
			.unreachable()
		} else if  == OpcodeCall ||  == OpcodeTailCallReturnCall {
			++
			, ,  := leb128.LoadUint32([:])
			if  != nil {
				return fmt.Errorf("read immediate: %v", )
			}
			 +=  - 1
			if int() >= len() {
				return fmt.Errorf("invalid function index")
			}

			var  string
			if  == OpcodeCall {
				 = OpcodeCallName
			} else {
				 = OpcodeTailCallReturnCallName
			}

			 := &.TypeSection[[]]
			for  := 0;  < len(.Params); ++ {
				if  := .popAndVerifyType(.Params[len(.Params)-1-]);  != nil {
					return fmt.Errorf("type mismatch on %s operation param type: %v", , )
				}
			}
			for ,  := range .Results {
				.push()
			}
			if  == OpcodeTailCallReturnCall {
				if  := .RequireEnabled(experimental.CoreFeaturesTailCall);  != nil {
					return fmt.Errorf("%s invalid as %v", OpcodeTailCallReturnCallName, )
				}
				// Same formatting as OpcodeEnd on the outer-most block
				if  := .requireStackValues(false, "", .Results, false);  != nil {
					return 
				}
				// behaves as a jump.
				.unreachable()
			}
		} else if  == OpcodeCallIndirect ||  == OpcodeTailCallReturnCallIndirect {
			++
			, ,  := leb128.LoadUint32([:])
			if  != nil {
				return fmt.Errorf("read immediate: %v", )
			}
			 += 

			var  string
			if  == OpcodeCallIndirect {
				 = OpcodeCallIndirectName
			} else {
				 = OpcodeTailCallReturnCallIndirectName
			}

			if int() >= len(.TypeSection) {
				return fmt.Errorf("invalid type index at %s: %d", , )
			}

			, ,  := leb128.LoadUint32([:])
			if  != nil {
				return fmt.Errorf("read table index: %v", )
			}
			 +=  - 1
			if  != 0 {
				if  := .RequireEnabled(api.CoreFeatureReferenceTypes);  != nil {
					return fmt.Errorf("table index must be zero but was %d: %w", , )
				}
			}

			if  >= uint32(len()) {
				return fmt.Errorf("unknown table index: %d", )
			}

			 := []
			if .Type != RefTypeFuncref {
				return fmt.Errorf("table is not funcref type but was %s for %s", RefTypeName(.Type), )
			}

			if  = .popAndVerifyType(ValueTypeI32);  != nil {
				return fmt.Errorf("cannot pop the offset in table for %s", )
			}
			 := &.TypeSection[]
			for  := 0;  < len(.Params); ++ {
				if  = .popAndVerifyType(.Params[len(.Params)-1-]);  != nil {
					return fmt.Errorf("type mismatch on %s operation input type", )
				}
			}
			for ,  := range .Results {
				.push()
			}

			if  == OpcodeTailCallReturnCallIndirect {
				if  := .RequireEnabled(experimental.CoreFeaturesTailCall);  != nil {
					return fmt.Errorf("%s invalid as %v", OpcodeTailCallReturnCallIndirectName, )
				}
				// Same formatting as OpcodeEnd on the outer-most block
				if  := .requireStackValues(false, "", .Results, false);  != nil {
					return 
				}
				// behaves as a jump.
				.unreachable()
			}
		} else if OpcodeI32Eqz <=  &&  <= OpcodeI64Extend32S {
			switch  {
			case OpcodeI32Eqz:
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI32EqzName, )
				}
				.push(ValueTypeI32)
			case OpcodeI32Eq, OpcodeI32Ne, OpcodeI32LtS,
				OpcodeI32LtU, OpcodeI32GtS, OpcodeI32GtU, OpcodeI32LeS,
				OpcodeI32LeU, OpcodeI32GeS, OpcodeI32GeU:
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the 1st i32 operand for %s: %v", InstructionName(), )
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the 2nd i32 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI32)
			case OpcodeI64Eqz:
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI64EqzName, )
				}
				.push(ValueTypeI32)
			case OpcodeI64Eq, OpcodeI64Ne, OpcodeI64LtS,
				OpcodeI64LtU, OpcodeI64GtS, OpcodeI64GtU,
				OpcodeI64LeS, OpcodeI64LeU, OpcodeI64GeS, OpcodeI64GeU:
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return fmt.Errorf("cannot pop the 1st i64 operand for %s: %v", InstructionName(), )
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return fmt.Errorf("cannot pop the 2nd i64 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI32)
			case OpcodeF32Eq, OpcodeF32Ne, OpcodeF32Lt, OpcodeF32Gt, OpcodeF32Le, OpcodeF32Ge:
				if  := .popAndVerifyType(ValueTypeF32);  != nil {
					return fmt.Errorf("cannot pop the 1st f32 operand for %s: %v", InstructionName(), )
				}
				if  := .popAndVerifyType(ValueTypeF32);  != nil {
					return fmt.Errorf("cannot pop the 2nd f32 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI32)
			case OpcodeF64Eq, OpcodeF64Ne, OpcodeF64Lt, OpcodeF64Gt, OpcodeF64Le, OpcodeF64Ge:
				if  := .popAndVerifyType(ValueTypeF64);  != nil {
					return fmt.Errorf("cannot pop the 1st f64 operand for %s: %v", InstructionName(), )
				}
				if  := .popAndVerifyType(ValueTypeF64);  != nil {
					return fmt.Errorf("cannot pop the 2nd f64 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI32)
			case OpcodeI32Clz, OpcodeI32Ctz, OpcodeI32Popcnt:
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI32)
			case OpcodeI32Add, OpcodeI32Sub, OpcodeI32Mul, OpcodeI32DivS,
				OpcodeI32DivU, OpcodeI32RemS, OpcodeI32RemU, OpcodeI32And,
				OpcodeI32Or, OpcodeI32Xor, OpcodeI32Shl, OpcodeI32ShrS,
				OpcodeI32ShrU, OpcodeI32Rotl, OpcodeI32Rotr:
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the 1st operand for %s: %v", InstructionName(), )
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the 2nd operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI32)
			case OpcodeI64Clz, OpcodeI64Ctz, OpcodeI64Popcnt:
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return fmt.Errorf("cannot pop the i64 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI64)
			case OpcodeI64Add, OpcodeI64Sub, OpcodeI64Mul, OpcodeI64DivS,
				OpcodeI64DivU, OpcodeI64RemS, OpcodeI64RemU, OpcodeI64And,
				OpcodeI64Or, OpcodeI64Xor, OpcodeI64Shl, OpcodeI64ShrS,
				OpcodeI64ShrU, OpcodeI64Rotl, OpcodeI64Rotr:
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return fmt.Errorf("cannot pop the 1st i64 operand for %s: %v", InstructionName(), )
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return fmt.Errorf("cannot pop the 2nd i64 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI64)
			case OpcodeF32Abs, OpcodeF32Neg, OpcodeF32Ceil,
				OpcodeF32Floor, OpcodeF32Trunc, OpcodeF32Nearest,
				OpcodeF32Sqrt:
				if  := .popAndVerifyType(ValueTypeF32);  != nil {
					return fmt.Errorf("cannot pop the 1st f32 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeF32)
			case OpcodeF32Add, OpcodeF32Sub, OpcodeF32Mul,
				OpcodeF32Div, OpcodeF32Min, OpcodeF32Max,
				OpcodeF32Copysign:
				if  := .popAndVerifyType(ValueTypeF32);  != nil {
					return fmt.Errorf("cannot pop the 1st f32 operand for %s: %v", InstructionName(), )
				}
				if  := .popAndVerifyType(ValueTypeF32);  != nil {
					return fmt.Errorf("cannot pop the 2nd f32 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeF32)
			case OpcodeF64Abs, OpcodeF64Neg, OpcodeF64Ceil,
				OpcodeF64Floor, OpcodeF64Trunc, OpcodeF64Nearest,
				OpcodeF64Sqrt:
				if  := .popAndVerifyType(ValueTypeF64);  != nil {
					return fmt.Errorf("cannot pop the 1st f64 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeF64)
			case OpcodeF64Add, OpcodeF64Sub, OpcodeF64Mul,
				OpcodeF64Div, OpcodeF64Min, OpcodeF64Max,
				OpcodeF64Copysign:
				if  := .popAndVerifyType(ValueTypeF64);  != nil {
					return fmt.Errorf("cannot pop the 1st f64 operand for %s: %v", InstructionName(), )
				}
				if  := .popAndVerifyType(ValueTypeF64);  != nil {
					return fmt.Errorf("cannot pop the 2nd f64 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeF64)
			case OpcodeI32WrapI64:
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI32WrapI64Name, )
				}
				.push(ValueTypeI32)
			case OpcodeI32TruncF32S, OpcodeI32TruncF32U:
				if  := .popAndVerifyType(ValueTypeF32);  != nil {
					return fmt.Errorf("cannot pop the f32 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI32)
			case OpcodeI32TruncF64S, OpcodeI32TruncF64U:
				if  := .popAndVerifyType(ValueTypeF64);  != nil {
					return fmt.Errorf("cannot pop the f64 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI32)
			case OpcodeI64ExtendI32S, OpcodeI64ExtendI32U:
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI64)
			case OpcodeI64TruncF32S, OpcodeI64TruncF32U:
				if  := .popAndVerifyType(ValueTypeF32);  != nil {
					return fmt.Errorf("cannot pop the f32 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI64)
			case OpcodeI64TruncF64S, OpcodeI64TruncF64U:
				if  := .popAndVerifyType(ValueTypeF64);  != nil {
					return fmt.Errorf("cannot pop the f64 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeI64)
			case OpcodeF32ConvertI32S, OpcodeF32ConvertI32U:
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeF32)
			case OpcodeF32ConvertI64S, OpcodeF32ConvertI64U:
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return fmt.Errorf("cannot pop the i64 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeF32)
			case OpcodeF32DemoteF64:
				if  := .popAndVerifyType(ValueTypeF64);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF32DemoteF64Name, )
				}
				.push(ValueTypeF32)
			case OpcodeF64ConvertI32S, OpcodeF64ConvertI32U:
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeF64)
			case OpcodeF64ConvertI64S, OpcodeF64ConvertI64U:
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return fmt.Errorf("cannot pop the i64 operand for %s: %v", InstructionName(), )
				}
				.push(ValueTypeF64)
			case OpcodeF64PromoteF32:
				if  := .popAndVerifyType(ValueTypeF32);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF64PromoteF32Name, )
				}
				.push(ValueTypeF64)
			case OpcodeI32ReinterpretF32:
				if  := .popAndVerifyType(ValueTypeF32);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI32ReinterpretF32Name, )
				}
				.push(ValueTypeI32)
			case OpcodeI64ReinterpretF64:
				if  := .popAndVerifyType(ValueTypeF64);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI64ReinterpretF64Name, )
				}
				.push(ValueTypeI64)
			case OpcodeF32ReinterpretI32:
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF32ReinterpretI32Name, )
				}
				.push(ValueTypeF32)
			case OpcodeF64ReinterpretI64:
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF64ReinterpretI64Name, )
				}
				.push(ValueTypeF64)
			case OpcodeI32Extend8S, OpcodeI32Extend16S:
				if  := .RequireEnabled(api.CoreFeatureSignExtensionOps);  != nil {
					return fmt.Errorf("%s invalid as %v", instructionNames[], )
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", instructionNames[], )
				}
				.push(ValueTypeI32)
			case OpcodeI64Extend8S, OpcodeI64Extend16S, OpcodeI64Extend32S:
				if  := .RequireEnabled(api.CoreFeatureSignExtensionOps);  != nil {
					return fmt.Errorf("%s invalid as %v", instructionNames[], )
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", instructionNames[], )
				}
				.push(ValueTypeI64)
			default:
				return fmt.Errorf("invalid numeric instruction 0x%x", )
			}
		} else if  >= OpcodeRefNull &&  <= OpcodeRefFunc {
			if  := .RequireEnabled(api.CoreFeatureReferenceTypes);  != nil {
				return fmt.Errorf("%s invalid as %v", instructionNames[], )
			}
			switch  {
			case OpcodeRefNull:
				++
				switch  := [];  {
				case ValueTypeExternref:
					.push(ValueTypeExternref)
				case ValueTypeFuncref:
					.push(ValueTypeFuncref)
				default:
					return fmt.Errorf("unknown type for ref.null: 0x%x", )
				}
			case OpcodeRefIsNull:
				,  := .pop()
				if  != nil {
					return fmt.Errorf("cannot pop the operand for ref.is_null: %v", )
				} else if !isReferenceValueType() &&  != valueTypeUnknown {
					return fmt.Errorf("type mismatch: expected reference type but was %s", ValueTypeName())
				}
				.push(ValueTypeI32)
			case OpcodeRefFunc:
				++
				, ,  := leb128.LoadUint32([:])
				if  != nil {
					return fmt.Errorf("failed to read function index for ref.func: %v", )
				}
				if ,  := []; ! {
					return fmt.Errorf("undeclared function index %d for ref.func", )
				}
				 +=  - 1
				.push(ValueTypeFuncref)
			}
		} else if  == OpcodeTableGet ||  == OpcodeTableSet {
			if  := .RequireEnabled(api.CoreFeatureReferenceTypes);  != nil {
				return fmt.Errorf("%s is invalid as %v", InstructionName(), )
			}
			++
			, ,  := leb128.LoadUint32([:])
			if  != nil {
				return fmt.Errorf("read immediate: %v", )
			}
			if  >= uint32(len()) {
				return fmt.Errorf("table of index %d not found", )
			}

			 := [].Type
			if  == OpcodeTableGet {
				if  := .popAndVerifyType(api.ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the operand for table.get: %v", )
				}
				.push()
			} else {
				if  := .popAndVerifyType();  != nil {
					return fmt.Errorf("cannot pop the operand for table.set: %v", )
				}
				if  := .popAndVerifyType(api.ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the operand for table.set: %v", )
				}
			}
			 +=  - 1
		} else if  == OpcodeMiscPrefix {
			++
			// A misc opcode is encoded as an unsigned variable 32-bit integer.
			, ,  := leb128.LoadUint32([:])
			if  != nil {
				return fmt.Errorf("failed to read misc opcode: %v", )
			}
			 +=  - 1
			 := byte()
			// If the misc opcode is beyond byte range, it is highly likely this is an invalid binary, or
			// it is due to the new opcode from a new proposal. In the latter case, we have to
			// change the alias type of OpcodeMisc (which is currently byte) to uint32.
			if uint32(byte()) !=  {
				return fmt.Errorf("invalid misc opcode: %#x", )
			}
			if  >= OpcodeMiscI32TruncSatF32S &&  <= OpcodeMiscI64TruncSatF64U {
				if  := .RequireEnabled(api.CoreFeatureNonTrappingFloatToIntConversion);  != nil {
					return fmt.Errorf("%s invalid as %v", miscInstructionNames[], )
				}
				var ,  ValueType
				switch  {
				case OpcodeMiscI32TruncSatF32S, OpcodeMiscI32TruncSatF32U:
					,  = ValueTypeF32, ValueTypeI32
				case OpcodeMiscI32TruncSatF64S, OpcodeMiscI32TruncSatF64U:
					,  = ValueTypeF64, ValueTypeI32
				case OpcodeMiscI64TruncSatF32S, OpcodeMiscI64TruncSatF32U:
					,  = ValueTypeF32, ValueTypeI64
				case OpcodeMiscI64TruncSatF64S, OpcodeMiscI64TruncSatF64U:
					,  = ValueTypeF64, ValueTypeI64
				}
				if  := .popAndVerifyType();  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", miscInstructionNames[], )
				}
				.push()
			} else if  >= OpcodeMiscMemoryInit &&  <= OpcodeMiscTableCopy {
				if  := .RequireEnabled(api.CoreFeatureBulkMemoryOperations);  != nil {
					return fmt.Errorf("%s invalid as %v", miscInstructionNames[], )
				}
				var  []ValueType
				// Handle opcodes added in bulk-memory-operations/WebAssembly 2.0.
				switch  {
				case OpcodeMiscDataDrop:
					if .DataCountSection == nil {
						return fmt.Errorf("%s requires data count section", MiscInstructionName())
					}

					// We need to read the index to the data section.
					++
					, ,  := leb128.LoadUint32([:])
					if  != nil {
						return fmt.Errorf("failed to read data segment index for %s: %v", MiscInstructionName(), )
					}
					if int() >= len(.DataSection) {
						return fmt.Errorf("index %d out of range of data section(len=%d)", , len(.DataSection))
					}
					 +=  - 1
				case OpcodeMiscMemoryInit, OpcodeMiscMemoryCopy, OpcodeMiscMemoryFill:
					if  == nil {
						return fmt.Errorf("memory must exist for %s", MiscInstructionName())
					}
					 = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}

					if  == OpcodeMiscMemoryInit {
						if .DataCountSection == nil {
							return fmt.Errorf("%s requires data count section", MiscInstructionName())
						}

						// We need to read the index to the data section.
						++
						, ,  := leb128.LoadUint32([:])
						if  != nil {
							return fmt.Errorf("failed to read data segment index for %s: %v", MiscInstructionName(), )
						}
						if int() >= len(.DataSection) {
							return fmt.Errorf("index %d out of range of data section(len=%d)", , len(.DataSection))
						}
						 +=  - 1
					}

					++
					, ,  := leb128.LoadUint32([:])
					if  != nil {
						return fmt.Errorf("failed to read memory index for %s: %v", MiscInstructionName(), )
					}
					if  != 0 ||  != 1 {
						return fmt.Errorf("%s reserved byte must be zero encoded with 1 byte", MiscInstructionName())
					}
					if  == OpcodeMiscMemoryCopy {
						++
						// memory.copy needs two memory index which are reserved as zero.
						, ,  := leb128.LoadUint32([:])
						if  != nil {
							return fmt.Errorf("failed to read memory index for %s: %v", MiscInstructionName(), )
						}
						if  != 0 ||  != 1 {
							return fmt.Errorf("%s reserved byte must be zero encoded with 1 byte", MiscInstructionName())
						}
					}

				case OpcodeMiscTableInit:
					 = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
					++
					, ,  := leb128.LoadUint32([:])
					if  != nil {
						return fmt.Errorf("failed to read element segment index for %s: %v", MiscInstructionName(), )
					}
					if int() >= len(.ElementSection) {
						return fmt.Errorf("index %d out of range of element section(len=%d)", , len(.ElementSection))
					}
					 += 

					, ,  := leb128.LoadUint32([:])
					if  != nil {
						return fmt.Errorf("failed to read source table index for %s: %v", MiscInstructionName(), )
					}
					if  != 0 {
						if  := .RequireEnabled(api.CoreFeatureReferenceTypes);  != nil {
							return fmt.Errorf("source table index must be zero for %s as %v", MiscInstructionName(), )
						}
					}
					if  >= uint32(len()) {
						return fmt.Errorf("table of index %d not found", )
					}

					if .ElementSection[].Type != [].Type {
						return fmt.Errorf("type mismatch for table.init: element type %s does not match table type %s",
							RefTypeName(.ElementSection[].Type),
							RefTypeName([].Type),
						)
					}
					 +=  - 1
				case OpcodeMiscElemDrop:
					++
					, ,  := leb128.LoadUint32([:])
					if  != nil {
						return fmt.Errorf("failed to read element segment index for %s: %v", MiscInstructionName(), )
					} else if int() >= len(.ElementSection) {
						return fmt.Errorf("index %d out of range of element section(len=%d)", , len(.ElementSection))
					}
					 +=  - 1
				case OpcodeMiscTableCopy:
					 = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
					++

					, ,  := leb128.LoadUint32([:])
					if  != nil {
						return fmt.Errorf("failed to read destination table index for %s: %v", MiscInstructionName(), )
					}
					if  != 0 {
						if  := .RequireEnabled(api.CoreFeatureReferenceTypes);  != nil {
							return fmt.Errorf("destination table index must be zero for %s as %v", MiscInstructionName(), )
						}
					}
					if  >= uint32(len()) {
						return fmt.Errorf("table of index %d not found", )
					}
					 += 

					, ,  := leb128.LoadUint32([:])
					if  != nil {
						return fmt.Errorf("failed to read source table index for %s: %v", MiscInstructionName(), )
					}
					if  != 0 {
						if  := .RequireEnabled(api.CoreFeatureReferenceTypes);  != nil {
							return fmt.Errorf("source table index must be zero for %s as %v", MiscInstructionName(), )
						}
					}
					if  >= uint32(len()) {
						return fmt.Errorf("table of index %d not found", )
					}

					if [].Type != [].Type {
						return fmt.Errorf("table type mismatch for table.copy: %s (src) != %s (dst)",
							RefTypeName([].Type), RefTypeName([].Type))
					}

					 +=  - 1
				}
				for ,  := range  {
					if  := .popAndVerifyType();  != nil {
						return fmt.Errorf("cannot pop the operand for %s: %v", miscInstructionNames[], )
					}
				}
			} else if  >= OpcodeMiscTableGrow &&  <= OpcodeMiscTableFill {
				if  := .RequireEnabled(api.CoreFeatureReferenceTypes);  != nil {
					return fmt.Errorf("%s invalid as %v", miscInstructionNames[], )
				}

				++
				, ,  := leb128.LoadUint32([:])
				if  != nil {
					return fmt.Errorf("failed to read table index for %s: %v", MiscInstructionName(), )
				}
				if  >= uint32(len()) {
					return fmt.Errorf("table of index %d not found", )
				}
				 +=  - 1

				var ,  []ValueType
				 := [].Type
				if  == OpcodeMiscTableGrow {
					 = []ValueType{ValueTypeI32, }
					 = []ValueType{ValueTypeI32}
				} else if  == OpcodeMiscTableSize {
					 = []ValueType{ValueTypeI32}
				} else if  == OpcodeMiscTableFill {
					 = []ValueType{ValueTypeI32, , ValueTypeI32}
				}

				for ,  := range  {
					if  := .popAndVerifyType();  != nil {
						return fmt.Errorf("cannot pop the operand for %s: %v", miscInstructionNames[], )
					}
				}
				for ,  := range  {
					.push()
				}
			} else {
				return fmt.Errorf("unknown misc opcode %#x", )
			}
		} else if  == OpcodeVecPrefix {
			++
			// Vector instructions come with two bytes where the first byte is always OpcodeVecPrefix,
			// and the second byte determines the actual instruction.
			 := []
			if  := .RequireEnabled(api.CoreFeatureSIMD);  != nil {
				return fmt.Errorf("%s invalid as %v", vectorInstructionName[], )
			}

			switch  {
			case OpcodeVecV128Const:
				// Read 128-bit = 16 bytes constants
				if int(+16) >= len() {
					return fmt.Errorf("cannot read constant vector value for %s", vectorInstructionName[])
				}
				 += 16
				.push(ValueTypeV128)
			case OpcodeVecV128AnyTrue, OpcodeVecI8x16AllTrue, OpcodeVecI16x8AllTrue, OpcodeVecI32x4AllTrue, OpcodeVecI64x2AllTrue,
				OpcodeVecI8x16BitMask, OpcodeVecI16x8BitMask, OpcodeVecI32x4BitMask, OpcodeVecI64x2BitMask:
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeI32)
			case OpcodeVecV128Load, OpcodeVecV128Load8x8s, OpcodeVecV128Load8x8u, OpcodeVecV128Load16x4s, OpcodeVecV128Load16x4u,
				OpcodeVecV128Load32x2s, OpcodeVecV128Load32x2u, OpcodeVecV128Load8Splat, OpcodeVecV128Load16Splat,
				OpcodeVecV128Load32Splat, OpcodeVecV128Load64Splat,
				OpcodeVecV128Load32zero, OpcodeVecV128Load64zero:
				if  == nil {
					return fmt.Errorf("memory must exist for %s", VectorInstructionName())
				}
				++
				, , ,  := readMemArg(, )
				if  != nil {
					return 
				}
				 +=  - 1
				var  uint32
				switch  {
				case OpcodeVecV128Load:
					 = 128 / 8
				case OpcodeVecV128Load8x8s, OpcodeVecV128Load8x8u, OpcodeVecV128Load16x4s, OpcodeVecV128Load16x4u,
					OpcodeVecV128Load32x2s, OpcodeVecV128Load32x2u:
					 = 64 / 8
				case OpcodeVecV128Load8Splat:
					 = 1
				case OpcodeVecV128Load16Splat:
					 = 16 / 8
				case OpcodeVecV128Load32Splat:
					 = 32 / 8
				case OpcodeVecV128Load64Splat:
					 = 64 / 8
				case OpcodeVecV128Load32zero:
					 = 32 / 8
				case OpcodeVecV128Load64zero:
					 = 64 / 8
				}

				if 1<< >  {
					return fmt.Errorf("invalid memory alignment %d for %s", , VectorInstructionName())
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", VectorInstructionName(), )
				}
				.push(ValueTypeV128)
			case OpcodeVecV128Store:
				if  == nil {
					return fmt.Errorf("memory must exist for %s", VectorInstructionName())
				}
				++
				, , ,  := readMemArg(, )
				if  != nil {
					return 
				}
				 +=  - 1
				if 1<< > 128/8 {
					return fmt.Errorf("invalid memory alignment %d for %s", , OpcodeVecV128StoreName)
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeVecV128StoreName, )
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeVecV128StoreName, )
				}
			case OpcodeVecV128Load8Lane, OpcodeVecV128Load16Lane, OpcodeVecV128Load32Lane, OpcodeVecV128Load64Lane:
				if  == nil {
					return fmt.Errorf("memory must exist for %s", VectorInstructionName())
				}
				 := vecLoadLanes[]
				++
				, , ,  := readMemArg(, )
				if  != nil {
					return 
				}
				if 1<< > .alignMax {
					return fmt.Errorf("invalid memory alignment %d for %s", , vectorInstructionName[])
				}
				 += 
				if  >= uint64(len()) {
					return fmt.Errorf("lane for %s not found", OpcodeVecV128Load64LaneName)
				}
				 := []
				if  >= .laneCeil {
					return fmt.Errorf("invalid lane index %d >= %d for %s", , .laneCeil, vectorInstructionName[])
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeV128)
			case OpcodeVecV128Store8Lane, OpcodeVecV128Store16Lane, OpcodeVecV128Store32Lane, OpcodeVecV128Store64Lane:
				if  == nil {
					return fmt.Errorf("memory must exist for %s", VectorInstructionName())
				}
				 := vecStoreLanes[]
				++
				, , ,  := readMemArg(, )
				if  != nil {
					return 
				}
				if 1<< > .alignMax {
					return fmt.Errorf("invalid memory alignment %d for %s", , vectorInstructionName[])
				}
				 += 
				if  >= uint64(len()) {
					return fmt.Errorf("lane for %s not found", vectorInstructionName[])
				}
				 := []
				if  >= .laneCeil {
					return fmt.Errorf("invalid lane index %d >= %d for %s", , .laneCeil, vectorInstructionName[])
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
			case OpcodeVecI8x16ExtractLaneS,
				OpcodeVecI8x16ExtractLaneU,
				OpcodeVecI16x8ExtractLaneS,
				OpcodeVecI16x8ExtractLaneU,
				OpcodeVecI32x4ExtractLane,
				OpcodeVecI64x2ExtractLane,
				OpcodeVecF32x4ExtractLane,
				OpcodeVecF64x2ExtractLane:
				++
				if  >= uint64(len()) {
					return fmt.Errorf("lane for %s not found", vectorInstructionName[])
				}
				 := vecExtractLanes[]
				 := []
				if  >= .laneCeil {
					return fmt.Errorf("invalid lane index %d >= %d for %s", , .laneCeil, vectorInstructionName[])
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(.resultType)
			case OpcodeVecI8x16ReplaceLane, OpcodeVecI16x8ReplaceLane, OpcodeVecI32x4ReplaceLane,
				OpcodeVecI64x2ReplaceLane, OpcodeVecF32x4ReplaceLane, OpcodeVecF64x2ReplaceLane:
				++
				if  >= uint64(len()) {
					return fmt.Errorf("lane for %s not found", vectorInstructionName[])
				}
				 := vecReplaceLanes[]
				 := []
				if  >= .laneCeil {
					return fmt.Errorf("invalid lane index %d >= %d for %s", , .laneCeil, vectorInstructionName[])
				}
				if  := .popAndVerifyType(.paramType);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeV128)
			case OpcodeVecI8x16Splat, OpcodeVecI16x8Splat, OpcodeVecI32x4Splat,
				OpcodeVecI64x2Splat, OpcodeVecF32x4Splat, OpcodeVecF64x2Splat:
				 := vecSplatValueTypes[]
				if  := .popAndVerifyType();  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeV128)
			case OpcodeVecI8x16Swizzle, OpcodeVecV128And, OpcodeVecV128Or, OpcodeVecV128Xor, OpcodeVecV128AndNot:
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeV128)
			case OpcodeVecV128Bitselect:
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeV128)
			case OpcodeVecV128Not:
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeV128)
			case OpcodeVecV128i8x16Shuffle:
				++
				if +15 >= uint64(len()) {
					return fmt.Errorf("16 lane indexes for %s not found", vectorInstructionName[])
				}
				 := [ : +16]
				for ,  := range  {
					if  >= 32 {
						return fmt.Errorf("invalid lane index[%d] %d >= %d for %s", , , 32, vectorInstructionName[])
					}
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeV128)
				 += 15
			case OpcodeVecI8x16Shl, OpcodeVecI8x16ShrS, OpcodeVecI8x16ShrU,
				OpcodeVecI16x8Shl, OpcodeVecI16x8ShrS, OpcodeVecI16x8ShrU,
				OpcodeVecI32x4Shl, OpcodeVecI32x4ShrS, OpcodeVecI32x4ShrU,
				OpcodeVecI64x2Shl, OpcodeVecI64x2ShrS, OpcodeVecI64x2ShrU:
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeV128)
			case OpcodeVecI8x16Eq, OpcodeVecI8x16Ne, OpcodeVecI8x16LtS, OpcodeVecI8x16LtU, OpcodeVecI8x16GtS,
				OpcodeVecI8x16GtU, OpcodeVecI8x16LeS, OpcodeVecI8x16LeU, OpcodeVecI8x16GeS, OpcodeVecI8x16GeU,
				OpcodeVecI16x8Eq, OpcodeVecI16x8Ne, OpcodeVecI16x8LtS, OpcodeVecI16x8LtU, OpcodeVecI16x8GtS,
				OpcodeVecI16x8GtU, OpcodeVecI16x8LeS, OpcodeVecI16x8LeU, OpcodeVecI16x8GeS, OpcodeVecI16x8GeU,
				OpcodeVecI32x4Eq, OpcodeVecI32x4Ne, OpcodeVecI32x4LtS, OpcodeVecI32x4LtU, OpcodeVecI32x4GtS,
				OpcodeVecI32x4GtU, OpcodeVecI32x4LeS, OpcodeVecI32x4LeU, OpcodeVecI32x4GeS, OpcodeVecI32x4GeU,
				OpcodeVecI64x2Eq, OpcodeVecI64x2Ne, OpcodeVecI64x2LtS, OpcodeVecI64x2GtS, OpcodeVecI64x2LeS,
				OpcodeVecI64x2GeS, OpcodeVecF32x4Eq, OpcodeVecF32x4Ne, OpcodeVecF32x4Lt, OpcodeVecF32x4Gt,
				OpcodeVecF32x4Le, OpcodeVecF32x4Ge, OpcodeVecF64x2Eq, OpcodeVecF64x2Ne, OpcodeVecF64x2Lt,
				OpcodeVecF64x2Gt, OpcodeVecF64x2Le, OpcodeVecF64x2Ge,
				OpcodeVecI32x4DotI16x8S,
				OpcodeVecI8x16NarrowI16x8S, OpcodeVecI8x16NarrowI16x8U, OpcodeVecI16x8NarrowI32x4S, OpcodeVecI16x8NarrowI32x4U:
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeV128)
			case OpcodeVecI8x16Neg, OpcodeVecI16x8Neg, OpcodeVecI32x4Neg, OpcodeVecI64x2Neg, OpcodeVecF32x4Neg, OpcodeVecF64x2Neg,
				OpcodeVecF32x4Sqrt, OpcodeVecF64x2Sqrt,
				OpcodeVecI8x16Abs, OpcodeVecI8x16Popcnt, OpcodeVecI16x8Abs, OpcodeVecI32x4Abs, OpcodeVecI64x2Abs,
				OpcodeVecF32x4Abs, OpcodeVecF64x2Abs,
				OpcodeVecF32x4Ceil, OpcodeVecF32x4Floor, OpcodeVecF32x4Trunc, OpcodeVecF32x4Nearest,
				OpcodeVecF64x2Ceil, OpcodeVecF64x2Floor, OpcodeVecF64x2Trunc, OpcodeVecF64x2Nearest,
				OpcodeVecI16x8ExtendLowI8x16S, OpcodeVecI16x8ExtendHighI8x16S, OpcodeVecI16x8ExtendLowI8x16U, OpcodeVecI16x8ExtendHighI8x16U,
				OpcodeVecI32x4ExtendLowI16x8S, OpcodeVecI32x4ExtendHighI16x8S, OpcodeVecI32x4ExtendLowI16x8U, OpcodeVecI32x4ExtendHighI16x8U,
				OpcodeVecI64x2ExtendLowI32x4S, OpcodeVecI64x2ExtendHighI32x4S, OpcodeVecI64x2ExtendLowI32x4U, OpcodeVecI64x2ExtendHighI32x4U,
				OpcodeVecI16x8ExtaddPairwiseI8x16S, OpcodeVecI16x8ExtaddPairwiseI8x16U,
				OpcodeVecI32x4ExtaddPairwiseI16x8S, OpcodeVecI32x4ExtaddPairwiseI16x8U,
				OpcodeVecF64x2PromoteLowF32x4Zero, OpcodeVecF32x4DemoteF64x2Zero,
				OpcodeVecF32x4ConvertI32x4S, OpcodeVecF32x4ConvertI32x4U,
				OpcodeVecF64x2ConvertLowI32x4S, OpcodeVecF64x2ConvertLowI32x4U,
				OpcodeVecI32x4TruncSatF32x4S, OpcodeVecI32x4TruncSatF32x4U, OpcodeVecI32x4TruncSatF64x2SZero, OpcodeVecI32x4TruncSatF64x2UZero:
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeV128)

			case OpcodeVecI8x16Add, OpcodeVecI8x16AddSatS, OpcodeVecI8x16AddSatU, OpcodeVecI8x16Sub, OpcodeVecI8x16SubSatS, OpcodeVecI8x16SubSatU,
				OpcodeVecI16x8Add, OpcodeVecI16x8AddSatS, OpcodeVecI16x8AddSatU, OpcodeVecI16x8Sub, OpcodeVecI16x8SubSatS, OpcodeVecI16x8SubSatU, OpcodeVecI16x8Mul,
				OpcodeVecI32x4Add, OpcodeVecI32x4Sub, OpcodeVecI32x4Mul,
				OpcodeVecI64x2Add, OpcodeVecI64x2Sub, OpcodeVecI64x2Mul,
				OpcodeVecF32x4Add, OpcodeVecF32x4Sub, OpcodeVecF32x4Mul, OpcodeVecF32x4Div,
				OpcodeVecF64x2Add, OpcodeVecF64x2Sub, OpcodeVecF64x2Mul, OpcodeVecF64x2Div,
				OpcodeVecI8x16MinS, OpcodeVecI8x16MinU, OpcodeVecI8x16MaxS, OpcodeVecI8x16MaxU,
				OpcodeVecI8x16AvgrU,
				OpcodeVecI16x8MinS, OpcodeVecI16x8MinU, OpcodeVecI16x8MaxS, OpcodeVecI16x8MaxU,
				OpcodeVecI16x8AvgrU,
				OpcodeVecI32x4MinS, OpcodeVecI32x4MinU, OpcodeVecI32x4MaxS, OpcodeVecI32x4MaxU,
				OpcodeVecF32x4Min, OpcodeVecF32x4Max, OpcodeVecF64x2Min, OpcodeVecF64x2Max,
				OpcodeVecF32x4Pmin, OpcodeVecF32x4Pmax, OpcodeVecF64x2Pmin, OpcodeVecF64x2Pmax,
				OpcodeVecI16x8Q15mulrSatS,
				OpcodeVecI16x8ExtMulLowI8x16S, OpcodeVecI16x8ExtMulHighI8x16S, OpcodeVecI16x8ExtMulLowI8x16U, OpcodeVecI16x8ExtMulHighI8x16U,
				OpcodeVecI32x4ExtMulLowI16x8S, OpcodeVecI32x4ExtMulHighI16x8S, OpcodeVecI32x4ExtMulLowI16x8U, OpcodeVecI32x4ExtMulHighI16x8U,
				OpcodeVecI64x2ExtMulLowI32x4S, OpcodeVecI64x2ExtMulHighI32x4S, OpcodeVecI64x2ExtMulLowI32x4U, OpcodeVecI64x2ExtMulHighI32x4U:
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				if  := .popAndVerifyType(ValueTypeV128);  != nil {
					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[], )
				}
				.push(ValueTypeV128)
			default:
				return fmt.Errorf("unknown SIMD instruction %s", vectorInstructionName[])
			}
		} else if  == OpcodeBlock {
			.Reset([+1:])
			, ,  := DecodeBlockType(.TypeSection, , )
			if  != nil {
				return fmt.Errorf("read block: %w", )
			}
			.push(, 0, 0, , , 0)
			if  = .popParams(, .Params, false);  != nil {
				return 
			}
			// Plus we have to push any block params again.
			for ,  := range .Params {
				.push()
			}
			.pushStackLimit(len(.Params))
			 += 
		} else if  == OpcodeAtomicPrefix {
			++
			// Atomic instructions come with two bytes where the first byte is always OpcodeAtomicPrefix,
			// and the second byte determines the actual instruction.
			 := []
			if  := .RequireEnabled(experimental.CoreFeaturesThreads);  != nil {
				return fmt.Errorf("%s invalid as %v", atomicInstructionName[], )
			}
			++

			if  == OpcodeAtomicFence {
				// No memory requirement and no arguments or return, however the immediate byte value must be 0.
				 := []
				if  != 0x0 {
					return fmt.Errorf("invalid immediate value for %s", AtomicInstructionName())
				}
				continue
			}

			// All atomic operations except fence (checked above) require memory
			if  == nil {
				return fmt.Errorf("memory must exist for %s", AtomicInstructionName())
			}
			, , ,  := readMemArg(, )
			if  != nil {
				return 
			}
			 +=  - 1
			switch  {
			case OpcodeAtomicMemoryNotify:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicMemoryWait32:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicMemoryWait64:
				if 1<< > 64/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicI32Load:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicI64Load:
				if 1<< > 64/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeAtomicI32Load8U:
				if 1<< != 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicI32Load16U:
				if 1<< != 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicI64Load8U:
				if 1<< != 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeAtomicI64Load16U:
				if 1<< > 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeAtomicI64Load32U:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeAtomicI32Store:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeAtomicI64Store:
				if 1<< > 64/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeAtomicI32Store8:
				if 1<< > 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeAtomicI32Store16:
				if 1<< > 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeAtomicI64Store8:
				if 1<< > 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeAtomicI64Store16:
				if 1<< > 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeAtomicI64Store32:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
			case OpcodeAtomicI32RmwAdd, OpcodeAtomicI32RmwSub, OpcodeAtomicI32RmwAnd, OpcodeAtomicI32RmwOr, OpcodeAtomicI32RmwXor, OpcodeAtomicI32RmwXchg:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicI32Rmw8AddU, OpcodeAtomicI32Rmw8SubU, OpcodeAtomicI32Rmw8AndU, OpcodeAtomicI32Rmw8OrU, OpcodeAtomicI32Rmw8XorU, OpcodeAtomicI32Rmw8XchgU:
				if 1<< > 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicI32Rmw16AddU, OpcodeAtomicI32Rmw16SubU, OpcodeAtomicI32Rmw16AndU, OpcodeAtomicI32Rmw16OrU, OpcodeAtomicI32Rmw16XorU, OpcodeAtomicI32Rmw16XchgU:
				if 1<< > 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicI64RmwAdd, OpcodeAtomicI64RmwSub, OpcodeAtomicI64RmwAnd, OpcodeAtomicI64RmwOr, OpcodeAtomicI64RmwXor, OpcodeAtomicI64RmwXchg:
				if 1<< > 64/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeAtomicI64Rmw8AddU, OpcodeAtomicI64Rmw8SubU, OpcodeAtomicI64Rmw8AndU, OpcodeAtomicI64Rmw8OrU, OpcodeAtomicI64Rmw8XorU, OpcodeAtomicI64Rmw8XchgU:
				if 1<< > 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeAtomicI64Rmw16AddU, OpcodeAtomicI64Rmw16SubU, OpcodeAtomicI64Rmw16AndU, OpcodeAtomicI64Rmw16OrU, OpcodeAtomicI64Rmw16XorU, OpcodeAtomicI64Rmw16XchgU:
				if 1<< > 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeAtomicI64Rmw32AddU, OpcodeAtomicI64Rmw32SubU, OpcodeAtomicI64Rmw32AndU, OpcodeAtomicI64Rmw32OrU, OpcodeAtomicI64Rmw32XorU, OpcodeAtomicI64Rmw32XchgU:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeAtomicI32RmwCmpxchg:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicI32Rmw8CmpxchgU:
				if 1<< > 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicI32Rmw16CmpxchgU:
				if 1<< > 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI32)
			case OpcodeAtomicI64RmwCmpxchg:
				if 1<< > 64/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeAtomicI64Rmw8CmpxchgU:
				if 1<< > 1 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeAtomicI64Rmw16CmpxchgU:
				if 1<< > 16/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			case OpcodeAtomicI64Rmw32CmpxchgU:
				if 1<< > 32/8 {
					return fmt.Errorf("invalid memory alignment")
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI64);  != nil {
					return 
				}
				if  := .popAndVerifyType(ValueTypeI32);  != nil {
					return 
				}
				.push(ValueTypeI64)
			default:
				return fmt.Errorf("invalid atomic opcode: 0x%x", )
			}
		} else if  == OpcodeLoop {
			.Reset([+1:])
			, ,  := DecodeBlockType(.TypeSection, , )
			if  != nil {
				return fmt.Errorf("read block: %w", )
			}
			.push(, 0, 0, , , )
			if  = .popParams(, .Params, false);  != nil {
				return 
			}
			// Plus we have to push any block params again.
			for ,  := range .Params {
				.push()
			}
			.pushStackLimit(len(.Params))
			 += 
		} else if  == OpcodeIf {
			.Reset([+1:])
			, ,  := DecodeBlockType(.TypeSection, , )
			if  != nil {
				return fmt.Errorf("read block: %w", )
			}
			.push(, 0, 0, , , )
			if  = .popAndVerifyType(ValueTypeI32);  != nil {
				return fmt.Errorf("cannot pop the operand for 'if': %v", )
			}
			if  = .popParams(, .Params, false);  != nil {
				return 
			}
			// Plus we have to push any block params again.
			for ,  := range .Params {
				.push()
			}
			.pushStackLimit(len(.Params))
			 += 
		} else if  == OpcodeElse {
			 := &.stack[len(.stack)-1]
			if .op != OpcodeIf {
				return fmt.Errorf("else instruction must be used in if block: %#x", )
			}
			.op = OpcodeElse
			.elseAt = 
			// Check the type soundness of the instructions *before* entering this else Op.
			if  := .popResults(OpcodeIf, .blockType.Results, true);  != nil {
				return 
			}
			// Before entering instructions inside else, we pop all the values pushed by then block.
			.resetAtStackLimit()
			// Plus we have to push any block params again.
			for ,  := range .blockType.Params {
				.push()
			}
		} else if  == OpcodeEnd {
			 := .pop()
			.endAt = 

			// OpcodeEnd can end a block or the function itself. Check to see what it is:

			 := .op == OpcodeIf && .elseAt <= .startAt
			if  {
				// If this is the end of block without else, the number of block's results and params must be same.
				// Otherwise, the value stack would result in the inconsistent state at runtime.
				if !bytes.Equal(.blockType.Results, .blockType.Params) {
					return typeCountError(false, OpcodeElseName, .blockType.Params, .blockType.Results)
				}
				// -1 skips else, to handle if block without else properly.
				.elseAt = .endAt - 1
			}

			// Determine the block context
			 := "" // the outer-most block: the function return
			if .op == OpcodeIf && ! && .elseAt > 0 {
				 = OpcodeElseName
			} else if .op != 0 {
				 = InstructionName(.op)
			}

			// Check return types match
			if  := .requireStackValues(false, , .blockType.Results, true);  != nil {
				return 
			}

			// Put the result types at the end after resetting at the stack limit
			// since we might have Any type between the limit and the current top.
			.resetAtStackLimit()
			for ,  := range .blockType.Results {
				.push()
			}
			// We exit if/loop/block, so reset the constraints on the stack manipulation
			// on values previously pushed by outer blocks.
			.popStackLimit()
		} else if  == OpcodeReturn {
			// Same formatting as OpcodeEnd on the outer-most block
			if  := .requireStackValues(false, "", .Results, false);  != nil {
				return 
			}
			// return instruction is stack-polymorphic.
			.unreachable()
		} else if  == OpcodeDrop {
			,  := .pop()
			if  != nil {
				return fmt.Errorf("invalid drop: %v", )
			}
		} else if  == OpcodeSelect ||  == OpcodeTypedSelect {
			if  := .popAndVerifyType(ValueTypeI32);  != nil {
				return fmt.Errorf("type mismatch on 3rd select operand: %v", )
			}
			,  := .pop()
			if  != nil {
				return fmt.Errorf("invalid select: %v", )
			}
			,  := .pop()
			if  != nil {
				return fmt.Errorf("invalid select: %v", )
			}

			if  == OpcodeTypedSelect {
				if  := .RequireEnabled(api.CoreFeatureReferenceTypes);  != nil {
					return fmt.Errorf("%s is invalid as %w", InstructionName(), )
				}
				++
				if  := [];  != 1 {
					return fmt.Errorf("too many type immediates for %s", InstructionName())
				}
				++
				 := []
				if  != ValueTypeI32 &&  != ValueTypeI64 &&  != ValueTypeF32 &&  != ValueTypeF64 &&
					 != api.ValueTypeExternref &&  != ValueTypeFuncref &&  != ValueTypeV128 {
					return fmt.Errorf("invalid type %s for %s", ValueTypeName(), OpcodeTypedSelectName)
				}
			} else if isReferenceValueType() || isReferenceValueType() {
				return fmt.Errorf("reference types cannot be used for non typed select instruction")
			}

			if  !=  &&  != valueTypeUnknown &&  != valueTypeUnknown {
				return fmt.Errorf("type mismatch on 1st and 2nd select operands")
			}
			if  == valueTypeUnknown {
				.push()
			} else {
				.push()
			}
		} else if  == OpcodeUnreachable {
			// unreachable instruction is stack-polymorphic.
			.unreachable()
		} else if  == OpcodeNop {
		} else {
			return fmt.Errorf("invalid instruction 0x%x", )
		}
	}

	if len(.stack) > 0 {
		return fmt.Errorf("ill-nested block exists")
	}
	if .maximumStackPointer >  {
		return fmt.Errorf("function may have %d stack values, which exceeds limit %d", .maximumStackPointer, )
	}
	return nil
}

var vecExtractLanes = [...]struct {
	laneCeil   byte
	resultType ValueType
}{
	OpcodeVecI8x16ExtractLaneS: {laneCeil: 16, resultType: ValueTypeI32},
	OpcodeVecI8x16ExtractLaneU: {laneCeil: 16, resultType: ValueTypeI32},
	OpcodeVecI16x8ExtractLaneS: {laneCeil: 8, resultType: ValueTypeI32},
	OpcodeVecI16x8ExtractLaneU: {laneCeil: 8, resultType: ValueTypeI32},
	OpcodeVecI32x4ExtractLane:  {laneCeil: 4, resultType: ValueTypeI32},
	OpcodeVecI64x2ExtractLane:  {laneCeil: 2, resultType: ValueTypeI64},
	OpcodeVecF32x4ExtractLane:  {laneCeil: 4, resultType: ValueTypeF32},
	OpcodeVecF64x2ExtractLane:  {laneCeil: 2, resultType: ValueTypeF64},
}

var vecReplaceLanes = [...]struct {
	laneCeil  byte
	paramType ValueType
}{
	OpcodeVecI8x16ReplaceLane: {laneCeil: 16, paramType: ValueTypeI32},
	OpcodeVecI16x8ReplaceLane: {laneCeil: 8, paramType: ValueTypeI32},
	OpcodeVecI32x4ReplaceLane: {laneCeil: 4, paramType: ValueTypeI32},
	OpcodeVecI64x2ReplaceLane: {laneCeil: 2, paramType: ValueTypeI64},
	OpcodeVecF32x4ReplaceLane: {laneCeil: 4, paramType: ValueTypeF32},
	OpcodeVecF64x2ReplaceLane: {laneCeil: 2, paramType: ValueTypeF64},
}

var vecStoreLanes = [...]struct {
	alignMax uint32
	laneCeil byte
}{
	OpcodeVecV128Store64Lane: {alignMax: 64 / 8, laneCeil: 128 / 64},
	OpcodeVecV128Store32Lane: {alignMax: 32 / 8, laneCeil: 128 / 32},
	OpcodeVecV128Store16Lane: {alignMax: 16 / 8, laneCeil: 128 / 16},
	OpcodeVecV128Store8Lane:  {alignMax: 1, laneCeil: 128 / 8},
}

var vecLoadLanes = [...]struct {
	alignMax uint32
	laneCeil byte
}{
	OpcodeVecV128Load64Lane: {alignMax: 64 / 8, laneCeil: 128 / 64},
	OpcodeVecV128Load32Lane: {alignMax: 32 / 8, laneCeil: 128 / 32},
	OpcodeVecV128Load16Lane: {alignMax: 16 / 8, laneCeil: 128 / 16},
	OpcodeVecV128Load8Lane:  {alignMax: 1, laneCeil: 128 / 8},
}

var vecSplatValueTypes = [...]ValueType{
	OpcodeVecI8x16Splat: ValueTypeI32,
	OpcodeVecI16x8Splat: ValueTypeI32,
	OpcodeVecI32x4Splat: ValueTypeI32,
	OpcodeVecI64x2Splat: ValueTypeI64,
	OpcodeVecF32x4Splat: ValueTypeF32,
	OpcodeVecF64x2Splat: ValueTypeF64,
}

type stacks struct {
	vs valueTypeStack
	cs controlBlockStack
	// ls is the label slice that is reused for each br_table instruction.
	ls []uint32
}

func ( *stacks) ( *FunctionType) {
	// Reset valueStack for reuse.
	.vs.stack = .vs.stack[:0]
	.vs.stackLimits = .vs.stackLimits[:0]
	.vs.maximumStackPointer = 0
	.cs.stack = .cs.stack[:0]
	.cs.stack = append(.cs.stack, controlBlock{blockType: })
	.ls = .ls[:0]
}

type controlBlockStack struct {
	stack []controlBlock
}

func ( *controlBlockStack) () *controlBlock {
	 := len(.stack) - 1
	 := &.stack[]
	.stack = .stack[:]
	return 
}

func ( *controlBlockStack) (, ,  uint64,  *FunctionType,  uint64,  Opcode) {
	.stack = append(.stack, controlBlock{
		startAt:        ,
		elseAt:         ,
		endAt:          ,
		blockType:      ,
		blockTypeBytes: ,
		op:             ,
	})
}

type valueTypeStack struct {
	stack               []ValueType
	stackLimits         []int
	maximumStackPointer int
	// requireStackValuesTmp is used in requireStackValues function to reduce the allocation.
	requireStackValuesTmp []ValueType
}

// Only used in the analyzeFunction below.
const valueTypeUnknown = ValueType(0xFF)

func ( *valueTypeStack) () ( ValueType,  int,  bool) {
	if len(.stackLimits) > 0 {
		 = .stackLimits[len(.stackLimits)-1]
	}
	 := len(.stack)
	if  <=  {
		return
	} else if  == +1 && .stack[] == valueTypeUnknown {
		 = valueTypeUnknown
		 = true
		return
	} else {
		 = .stack[-1]
		.stack = .stack[:-1]
		 = true
		return
	}
}

func ( *valueTypeStack) () (ValueType, error) {
	if , ,  := .tryPop();  {
		return , nil
	} else {
		return 0, fmt.Errorf("invalid operation: trying to pop at %d with limit %d", len(.stack), )
	}
}

// popAndVerifyType returns an error if the stack value is unexpected.
func ( *valueTypeStack) ( ValueType) error {
	, ,  := .tryPop()
	if ! {
		return fmt.Errorf("%s missing", ValueTypeName())
	}
	if  !=  &&  != valueTypeUnknown &&  != valueTypeUnknown {
		return fmt.Errorf("type mismatch: expected %s, but was %s", ValueTypeName(), ValueTypeName())
	}
	return nil
}

func ( *valueTypeStack) ( ValueType) {
	.stack = append(.stack, )
	if  := len(.stack);  > .maximumStackPointer {
		.maximumStackPointer = 
	}
}

func ( *valueTypeStack) () {
	.resetAtStackLimit()
	.stack = append(.stack, valueTypeUnknown)
}

func ( *valueTypeStack) () {
	if len(.stackLimits) != 0 {
		.stack = .stack[:.stackLimits[len(.stackLimits)-1]]
	} else {
		.stack = .stack[:0]
	}
}

func ( *valueTypeStack) () {
	if len(.stackLimits) != 0 {
		.stackLimits = .stackLimits[:len(.stackLimits)-1]
	}
}

// pushStackLimit pushes the control frame's bottom of the stack.
func ( *valueTypeStack) ( int) {
	 := len(.stack) - 
	.stackLimits = append(.stackLimits, )
}

func ( *valueTypeStack) ( Opcode,  []ValueType,  bool) error {
	return .requireStackValues(true, InstructionName(), , )
}

func ( *valueTypeStack) ( Opcode,  []ValueType,  bool) error {
	return .requireStackValues(false, InstructionName(), , )
}

func ( *valueTypeStack) (
	 bool,
	 string,
	 []ValueType,
	 bool,
) error {
	 := 0
	if len(.stackLimits) > 0 {
		 = .stackLimits[len(.stackLimits)-1]
	}
	// Iterate backwards as we are comparing the desired slice against stack value types.
	 := len()

	// First, check if there are enough values on the stack.
	.requireStackValuesTmp = .requireStackValuesTmp[:0]
	for  :=  - 1;  >= 0; -- {
		, ,  := .tryPop()
		if ! {
			if len(.requireStackValuesTmp) > len() {
				return typeCountError(, , .requireStackValuesTmp, )
			}
			return typeCountError(, , .requireStackValuesTmp, )
		}
		.requireStackValuesTmp = append(.requireStackValuesTmp, )
	}

	// Now, check if there are too many values.
	if  {
		if !( == len(.stack) || (+1 == len(.stack) && .stack[] == valueTypeUnknown)) {
			return typeCountError(, , append(.stack, ...), )
		}
	}

	// Finally, check the types of the values:
	for ,  := range .requireStackValuesTmp {
		 := [--1] // have is in reverse order (stack)
		if  !=  &&  != valueTypeUnknown &&  != valueTypeUnknown {
			return typeMismatchError(, , , , )
		}
	}
	return nil
}

// typeMismatchError returns an error similar to go compiler's error on type mismatch.
func typeMismatchError( bool,  string,  ValueType,  ValueType,  int) error {
	var  strings.Builder
	.WriteString("cannot use ")
	.WriteString(ValueTypeName())
	if  != "" {
		.WriteString(" in ")
		.WriteString()
		.WriteString(" block")
	}
	if  {
		.WriteString(" as param")
	} else {
		.WriteString(" as result")
	}
	.WriteString("[")
	.WriteString(strconv.Itoa())
	.WriteString("] type ")
	.WriteString(ValueTypeName())
	return errors.New(.String())
}

// typeCountError returns an error similar to go compiler's error on type count mismatch.
func typeCountError( bool,  string,  []ValueType,  []ValueType) error {
	var  strings.Builder
	if len() > len() {
		.WriteString("too many ")
	} else {
		.WriteString("not enough ")
	}
	if  {
		.WriteString("params")
	} else {
		.WriteString("results")
	}
	if  != "" {
		if  {
			.WriteString(" for ")
		} else {
			.WriteString(" in ")
		}
		.WriteString()
		.WriteString(" block")
	}
	.WriteString("\n\thave (")
	writeValueTypes(, &)
	.WriteString(")\n\twant (")
	writeValueTypes(, &)
	.WriteByte(')')
	return errors.New(.String())
}

func writeValueTypes( []ValueType,  *strings.Builder) {
	switch len() {
	case 0:
	case 1:
		.WriteString(ValueTypeName([0]))
	default:
		.WriteString(ValueTypeName([0]))
		for ,  := range [1:] {
			.WriteString(", ")
			.WriteString(ValueTypeName())
		}
	}
}

func ( *valueTypeStack) () string {
	var ,  []string
	for ,  := range .stack {
		var  string
		if  == valueTypeUnknown {
			 = "unknown"
		} else {
			 = ValueTypeName()
		}
		 = append(, )
	}
	for ,  := range .stackLimits {
		 = append(, fmt.Sprintf("%d", ))
	}
	return fmt.Sprintf("{stack: [%s], limits: [%s]}",
		strings.Join(, ", "), strings.Join(, ","))
}

type controlBlock struct {
	startAt, elseAt, endAt uint64
	blockType              *FunctionType
	blockTypeBytes         uint64
	// op is zero when the outermost block
	op Opcode
}

// DecodeBlockType decodes the type index from a positive 33-bit signed integer. Negative numbers indicate up to one
// WebAssembly 1.0 (20191205) compatible result type. Positive numbers are decoded when `enabledFeatures` include
// CoreFeatureMultiValue and include an index in the Module.TypeSection.
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-blocktype
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/multi-value/Overview.md
func ( []FunctionType,  *bytes.Reader,  api.CoreFeatures) (*FunctionType, uint64, error) {
	, ,  := leb128.DecodeInt33AsInt64()
	if  != nil {
		return nil, 0, fmt.Errorf("decode int33: %w", )
	}

	var  *FunctionType
	switch  {
	case -64: // 0x40 in original byte = nil
		 = blockType_v_v
	case -1: // 0x7f in original byte = i32
		 = blockType_v_i32
	case -2: // 0x7e in original byte = i64
		 = blockType_v_i64
	case -3: // 0x7d in original byte = f32
		 = blockType_v_f32
	case -4: // 0x7c in original byte = f64
		 = blockType_v_f64
	case -5: // 0x7b in original byte = v128
		 = blockType_v_v128
	case -16: // 0x70 in original byte = funcref
		 = blockType_v_funcref
	case -17: // 0x6f in original byte = externref
		 = blockType_v_externref
	default:
		if  = .RequireEnabled(api.CoreFeatureMultiValue);  != nil {
			return nil, , fmt.Errorf("block with function type return invalid as %v", )
		}
		if  < 0 || ( >= int64(len())) {
			return nil, 0, fmt.Errorf("type index out of range: %d", )
		}
		 = &[]
	}
	return , , 
}

// These block types are defined as globals in order to avoid allocations in DecodeBlockType.
var (
	blockType_v_v         = &FunctionType{}
	blockType_v_i32       = &FunctionType{Results: []ValueType{ValueTypeI32}, ResultNumInUint64: 1}
	blockType_v_i64       = &FunctionType{Results: []ValueType{ValueTypeI64}, ResultNumInUint64: 1}
	blockType_v_f32       = &FunctionType{Results: []ValueType{ValueTypeF32}, ResultNumInUint64: 1}
	blockType_v_f64       = &FunctionType{Results: []ValueType{ValueTypeF64}, ResultNumInUint64: 1}
	blockType_v_v128      = &FunctionType{Results: []ValueType{ValueTypeV128}, ResultNumInUint64: 2}
	blockType_v_funcref   = &FunctionType{Results: []ValueType{ValueTypeFuncref}, ResultNumInUint64: 1}
	blockType_v_externref = &FunctionType{Results: []ValueType{ValueTypeExternref}, ResultNumInUint64: 1}
)

// SplitCallStack returns the input stack resliced to the count of params and
// results, or errors if it isn't long enough for either.
func ( *FunctionType,  []uint64) ( []uint64,  []uint64,  error) {
	 := len()
	if  := .ParamNumInUint64;  >  {
		return nil, nil, fmt.Errorf("need %d params, but stack size is %d", , )
	} else if  > 0 {
		 = [:]
	}
	if  := .ResultNumInUint64;  >  {
		return nil, nil, fmt.Errorf("need %d results, but stack size is %d", , )
	} else if  > 0 {
		 = [:]
	}
	return
}