github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/wasm/func_validation.go (about)

     1  package wasm
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/bananabytelabs/wazero/api"
    11  	"github.com/bananabytelabs/wazero/internal/leb128"
    12  )
    13  
    14  // The wazero specific limitation described at RATIONALE.md.
    15  const maximumValuesOnStack = 1 << 27
    16  
    17  // validateFunction validates the instruction sequence of a function.
    18  // following the specification https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#instructions%E2%91%A2.
    19  //
    20  // * idx is the index in the FunctionSection
    21  // * functions are the function index, which is prefixed by imports. The value is the TypeSection index.
    22  // * globals are the global index, which is prefixed by imports.
    23  // * memory is the potentially imported memory and can be nil.
    24  // * table is the potentially imported table and can be nil.
    25  // * declaredFunctionIndexes is the set of function indexes declared by declarative element segments which can be acceed by OpcodeRefFunc instruction.
    26  //
    27  // Returns an error if the instruction sequence is not valid,
    28  // or potentially it can exceed the maximum number of values on the stack.
    29  func (m *Module) validateFunction(sts *stacks, enabledFeatures api.CoreFeatures, idx Index, functions []Index,
    30  	globals []GlobalType, memory *Memory, tables []Table, declaredFunctionIndexes map[Index]struct{}, br *bytes.Reader,
    31  ) error {
    32  	return m.validateFunctionWithMaxStackValues(sts, enabledFeatures, idx, functions, globals, memory, tables, maximumValuesOnStack, declaredFunctionIndexes, br)
    33  }
    34  
    35  func readMemArg(pc uint64, body []byte) (align, offset uint32, read uint64, err error) {
    36  	align, num, err := leb128.LoadUint32(body[pc:])
    37  	if err != nil {
    38  		err = fmt.Errorf("read memory align: %v", err)
    39  		return
    40  	}
    41  	read += num
    42  
    43  	offset, num, err = leb128.LoadUint32(body[pc+num:])
    44  	if err != nil {
    45  		err = fmt.Errorf("read memory offset: %v", err)
    46  		return
    47  	}
    48  
    49  	read += num
    50  	return align, offset, read, nil
    51  }
    52  
    53  // validateFunctionWithMaxStackValues is like validateFunction, but allows overriding maxStackValues for testing.
    54  //
    55  // * stacks is to track the state of Wasm value and control frame stacks at anypoint of execution, and reused to reduce allocation.
    56  // * maxStackValues is the maximum height of values stack which the target is allowed to reach.
    57  func (m *Module) validateFunctionWithMaxStackValues(
    58  	sts *stacks,
    59  	enabledFeatures api.CoreFeatures,
    60  	idx Index,
    61  	functions []Index,
    62  	globals []GlobalType,
    63  	memory *Memory,
    64  	tables []Table,
    65  	maxStackValues int,
    66  	declaredFunctionIndexes map[Index]struct{},
    67  	br *bytes.Reader,
    68  ) error {
    69  	functionType := &m.TypeSection[m.FunctionSection[idx]]
    70  	code := &m.CodeSection[idx]
    71  	body := code.Body
    72  	localTypes := code.LocalTypes
    73  
    74  	sts.reset(functionType)
    75  	valueTypeStack := &sts.vs
    76  	// We start with the outermost control block which is for function return if the code branches into it.
    77  	controlBlockStack := &sts.cs
    78  
    79  	// Now start walking through all the instructions in the body while tracking
    80  	// control blocks and value types to check the validity of all instructions.
    81  	for pc := uint64(0); pc < uint64(len(body)); pc++ {
    82  		op := body[pc]
    83  		if false {
    84  			var instName string
    85  			if op == OpcodeMiscPrefix {
    86  				instName = MiscInstructionName(body[pc+1])
    87  			} else if op == OpcodeVecPrefix {
    88  				instName = VectorInstructionName(body[pc+1])
    89  			} else if op == OpcodeAtomicPrefix {
    90  				instName = AtomicInstructionName(body[pc+1])
    91  			} else {
    92  				instName = InstructionName(op)
    93  			}
    94  			fmt.Printf("handling %s, stack=%s, blocks: %v\n", instName, valueTypeStack.stack, controlBlockStack)
    95  		}
    96  
    97  		if OpcodeI32Load <= op && op <= OpcodeI64Store32 {
    98  			if memory == nil {
    99  				return fmt.Errorf("memory must exist for %s", InstructionName(op))
   100  			}
   101  			pc++
   102  			align, _, read, err := readMemArg(pc, body)
   103  			if err != nil {
   104  				return err
   105  			}
   106  			pc += read - 1
   107  			switch op {
   108  			case OpcodeI32Load:
   109  				if 1<<align > 32/8 {
   110  					return fmt.Errorf("invalid memory alignment")
   111  				}
   112  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   113  					return err
   114  				}
   115  				valueTypeStack.push(ValueTypeI32)
   116  			case OpcodeF32Load:
   117  				if 1<<align > 32/8 {
   118  					return fmt.Errorf("invalid memory alignment")
   119  				}
   120  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   121  					return err
   122  				}
   123  				valueTypeStack.push(ValueTypeF32)
   124  			case OpcodeI32Store:
   125  				if 1<<align > 32/8 {
   126  					return fmt.Errorf("invalid memory alignment")
   127  				}
   128  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   129  					return err
   130  				}
   131  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   132  					return err
   133  				}
   134  			case OpcodeF32Store:
   135  				if 1<<align > 32/8 {
   136  					return fmt.Errorf("invalid memory alignment")
   137  				}
   138  				if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
   139  					return err
   140  				}
   141  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   142  					return err
   143  				}
   144  			case OpcodeI64Load:
   145  				if 1<<align > 64/8 {
   146  					return fmt.Errorf("invalid memory alignment")
   147  				}
   148  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   149  					return err
   150  				}
   151  				valueTypeStack.push(ValueTypeI64)
   152  			case OpcodeF64Load:
   153  				if 1<<align > 64/8 {
   154  					return fmt.Errorf("invalid memory alignment")
   155  				}
   156  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   157  					return err
   158  				}
   159  				valueTypeStack.push(ValueTypeF64)
   160  			case OpcodeI64Store:
   161  				if 1<<align > 64/8 {
   162  					return fmt.Errorf("invalid memory alignment")
   163  				}
   164  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   165  					return err
   166  				}
   167  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   168  					return err
   169  				}
   170  			case OpcodeF64Store:
   171  				if 1<<align > 64/8 {
   172  					return fmt.Errorf("invalid memory alignment")
   173  				}
   174  				if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
   175  					return err
   176  				}
   177  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   178  					return err
   179  				}
   180  			case OpcodeI32Load8S:
   181  				if 1<<align > 1 {
   182  					return fmt.Errorf("invalid memory alignment")
   183  				}
   184  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   185  					return err
   186  				}
   187  				valueTypeStack.push(ValueTypeI32)
   188  			case OpcodeI32Load8U:
   189  				if 1<<align > 1 {
   190  					return fmt.Errorf("invalid memory alignment")
   191  				}
   192  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   193  					return err
   194  				}
   195  				valueTypeStack.push(ValueTypeI32)
   196  			case OpcodeI64Load8S, OpcodeI64Load8U:
   197  				if 1<<align > 1 {
   198  					return fmt.Errorf("invalid memory alignment")
   199  				}
   200  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   201  					return err
   202  				}
   203  				valueTypeStack.push(ValueTypeI64)
   204  			case OpcodeI32Store8:
   205  				if 1<<align > 1 {
   206  					return fmt.Errorf("invalid memory alignment")
   207  				}
   208  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   209  					return err
   210  				}
   211  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   212  					return err
   213  				}
   214  			case OpcodeI64Store8:
   215  				if 1<<align > 1 {
   216  					return fmt.Errorf("invalid memory alignment")
   217  				}
   218  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   219  					return err
   220  				}
   221  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   222  					return err
   223  				}
   224  			case OpcodeI32Load16S, OpcodeI32Load16U:
   225  				if 1<<align > 16/8 {
   226  					return fmt.Errorf("invalid memory alignment")
   227  				}
   228  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   229  					return err
   230  				}
   231  				valueTypeStack.push(ValueTypeI32)
   232  			case OpcodeI64Load16S, OpcodeI64Load16U:
   233  				if 1<<align > 16/8 {
   234  					return fmt.Errorf("invalid memory alignment")
   235  				}
   236  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   237  					return err
   238  				}
   239  				valueTypeStack.push(ValueTypeI64)
   240  			case OpcodeI32Store16:
   241  				if 1<<align > 16/8 {
   242  					return fmt.Errorf("invalid memory alignment")
   243  				}
   244  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   245  					return err
   246  				}
   247  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   248  					return err
   249  				}
   250  			case OpcodeI64Store16:
   251  				if 1<<align > 16/8 {
   252  					return fmt.Errorf("invalid memory alignment")
   253  				}
   254  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   255  					return err
   256  				}
   257  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   258  					return err
   259  				}
   260  			case OpcodeI64Load32S, OpcodeI64Load32U:
   261  				if 1<<align > 32/8 {
   262  					return fmt.Errorf("invalid memory alignment")
   263  				}
   264  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   265  					return err
   266  				}
   267  				valueTypeStack.push(ValueTypeI64)
   268  			case OpcodeI64Store32:
   269  				if 1<<align > 32/8 {
   270  					return fmt.Errorf("invalid memory alignment")
   271  				}
   272  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   273  					return err
   274  				}
   275  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   276  					return err
   277  				}
   278  			}
   279  		} else if OpcodeMemorySize <= op && op <= OpcodeMemoryGrow {
   280  			if memory == nil {
   281  				return fmt.Errorf("memory must exist for %s", InstructionName(op))
   282  			}
   283  			pc++
   284  			val, num, err := leb128.LoadUint32(body[pc:])
   285  			if err != nil {
   286  				return fmt.Errorf("read immediate: %v", err)
   287  			}
   288  			if val != 0 || num != 1 {
   289  				return fmt.Errorf("memory instruction reserved bytes not zero with 1 byte")
   290  			}
   291  			switch Opcode(op) {
   292  			case OpcodeMemoryGrow:
   293  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   294  					return err
   295  				}
   296  				valueTypeStack.push(ValueTypeI32)
   297  			case OpcodeMemorySize:
   298  				valueTypeStack.push(ValueTypeI32)
   299  			}
   300  			pc += num - 1
   301  		} else if OpcodeI32Const <= op && op <= OpcodeF64Const {
   302  			pc++
   303  			switch Opcode(op) {
   304  			case OpcodeI32Const:
   305  				_, num, err := leb128.LoadInt32(body[pc:])
   306  				if err != nil {
   307  					return fmt.Errorf("read i32 immediate: %s", err)
   308  				}
   309  				pc += num - 1
   310  				valueTypeStack.push(ValueTypeI32)
   311  			case OpcodeI64Const:
   312  				_, num, err := leb128.LoadInt64(body[pc:])
   313  				if err != nil {
   314  					return fmt.Errorf("read i64 immediate: %v", err)
   315  				}
   316  				valueTypeStack.push(ValueTypeI64)
   317  				pc += num - 1
   318  			case OpcodeF32Const:
   319  				valueTypeStack.push(ValueTypeF32)
   320  				pc += 3
   321  			case OpcodeF64Const:
   322  				valueTypeStack.push(ValueTypeF64)
   323  				pc += 7
   324  			}
   325  		} else if OpcodeLocalGet <= op && op <= OpcodeGlobalSet {
   326  			pc++
   327  			index, num, err := leb128.LoadUint32(body[pc:])
   328  			if err != nil {
   329  				return fmt.Errorf("read immediate: %v", err)
   330  			}
   331  			pc += num - 1
   332  			switch op {
   333  			case OpcodeLocalGet:
   334  				inputLen := uint32(len(functionType.Params))
   335  				if l := uint32(len(localTypes)) + inputLen; index >= l {
   336  					return fmt.Errorf("invalid local index for %s %d >= %d(=len(locals)+len(parameters))",
   337  						OpcodeLocalGetName, index, l)
   338  				}
   339  				if index < inputLen {
   340  					valueTypeStack.push(functionType.Params[index])
   341  				} else {
   342  					valueTypeStack.push(localTypes[index-inputLen])
   343  				}
   344  			case OpcodeLocalSet:
   345  				inputLen := uint32(len(functionType.Params))
   346  				if l := uint32(len(localTypes)) + inputLen; index >= l {
   347  					return fmt.Errorf("invalid local index for %s %d >= %d(=len(locals)+len(parameters))",
   348  						OpcodeLocalSetName, index, l)
   349  				}
   350  				var expType ValueType
   351  				if index < inputLen {
   352  					expType = functionType.Params[index]
   353  				} else {
   354  					expType = localTypes[index-inputLen]
   355  				}
   356  				if err := valueTypeStack.popAndVerifyType(expType); err != nil {
   357  					return err
   358  				}
   359  			case OpcodeLocalTee:
   360  				inputLen := uint32(len(functionType.Params))
   361  				if l := uint32(len(localTypes)) + inputLen; index >= l {
   362  					return fmt.Errorf("invalid local index for %s %d >= %d(=len(locals)+len(parameters))",
   363  						OpcodeLocalTeeName, index, l)
   364  				}
   365  				var expType ValueType
   366  				if index < inputLen {
   367  					expType = functionType.Params[index]
   368  				} else {
   369  					expType = localTypes[index-inputLen]
   370  				}
   371  				if err := valueTypeStack.popAndVerifyType(expType); err != nil {
   372  					return err
   373  				}
   374  				valueTypeStack.push(expType)
   375  			case OpcodeGlobalGet:
   376  				if index >= uint32(len(globals)) {
   377  					return fmt.Errorf("invalid index for %s", OpcodeGlobalGetName)
   378  				}
   379  				valueTypeStack.push(globals[index].ValType)
   380  			case OpcodeGlobalSet:
   381  				if index >= uint32(len(globals)) {
   382  					return fmt.Errorf("invalid global index")
   383  				} else if !globals[index].Mutable {
   384  					return fmt.Errorf("%s when not mutable", OpcodeGlobalSetName)
   385  				} else if err := valueTypeStack.popAndVerifyType(
   386  					globals[index].ValType); err != nil {
   387  					return err
   388  				}
   389  			}
   390  		} else if op == OpcodeBr {
   391  			pc++
   392  			index, num, err := leb128.LoadUint32(body[pc:])
   393  			if err != nil {
   394  				return fmt.Errorf("read immediate: %v", err)
   395  			} else if int(index) >= len(controlBlockStack.stack) {
   396  				return fmt.Errorf("invalid %s operation: index out of range", OpcodeBrName)
   397  			}
   398  			pc += num - 1
   399  			// Check type soundness.
   400  			target := &controlBlockStack.stack[len(controlBlockStack.stack)-int(index)-1]
   401  			var targetResultType []ValueType
   402  			if target.op == OpcodeLoop {
   403  				targetResultType = target.blockType.Params
   404  			} else {
   405  				targetResultType = target.blockType.Results
   406  			}
   407  			if err = valueTypeStack.popResults(op, targetResultType, false); err != nil {
   408  				return err
   409  			}
   410  			// br instruction is stack-polymorphic.
   411  			valueTypeStack.unreachable()
   412  		} else if op == OpcodeBrIf {
   413  			pc++
   414  			index, num, err := leb128.LoadUint32(body[pc:])
   415  			if err != nil {
   416  				return fmt.Errorf("read immediate: %v", err)
   417  			} else if int(index) >= len(controlBlockStack.stack) {
   418  				return fmt.Errorf(
   419  					"invalid ln param given for %s: index=%d with %d for the current label stack length",
   420  					OpcodeBrIfName, index, len(controlBlockStack.stack))
   421  			}
   422  			pc += num - 1
   423  			if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   424  				return fmt.Errorf("cannot pop the required operand for %s", OpcodeBrIfName)
   425  			}
   426  			// Check type soundness.
   427  			target := &controlBlockStack.stack[len(controlBlockStack.stack)-int(index)-1]
   428  			var targetResultType []ValueType
   429  			if target.op == OpcodeLoop {
   430  				targetResultType = target.blockType.Params
   431  			} else {
   432  				targetResultType = target.blockType.Results
   433  			}
   434  			if err := valueTypeStack.popResults(op, targetResultType, false); err != nil {
   435  				return err
   436  			}
   437  			// Push back the result
   438  			for _, t := range targetResultType {
   439  				valueTypeStack.push(t)
   440  			}
   441  		} else if op == OpcodeBrTable {
   442  			pc++
   443  			br.Reset(body[pc:])
   444  			nl, num, err := leb128.DecodeUint32(br)
   445  			if err != nil {
   446  				return fmt.Errorf("read immediate: %w", err)
   447  			}
   448  
   449  			list := make([]uint32, nl)
   450  			for i := uint32(0); i < nl; i++ {
   451  				l, n, err := leb128.DecodeUint32(br)
   452  				if err != nil {
   453  					return fmt.Errorf("read immediate: %w", err)
   454  				}
   455  				num += n
   456  				list[i] = l
   457  			}
   458  			ln, n, err := leb128.DecodeUint32(br)
   459  			if err != nil {
   460  				return fmt.Errorf("read immediate: %w", err)
   461  			} else if int(ln) >= len(controlBlockStack.stack) {
   462  				return fmt.Errorf(
   463  					"invalid ln param given for %s: ln=%d with %d for the current label stack length",
   464  					OpcodeBrTableName, ln, len(controlBlockStack.stack))
   465  			}
   466  			pc += n + num - 1
   467  			// Check type soundness.
   468  			if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   469  				return fmt.Errorf("cannot pop the required operand for %s", OpcodeBrTableName)
   470  			}
   471  			lnLabel := &controlBlockStack.stack[len(controlBlockStack.stack)-1-int(ln)]
   472  			var defaultLabelType []ValueType
   473  			// Below, we might modify the slice in case of unreachable. Therefore,
   474  			// we have to copy the content of block result types, otherwise the original
   475  			// function type might result in invalid value types if the block is the outermost label
   476  			// which equals the function's type.
   477  			if lnLabel.op != OpcodeLoop { // Loop operation doesn't require results since the continuation is the beginning of the loop.
   478  				defaultLabelType = make([]ValueType, len(lnLabel.blockType.Results))
   479  				copy(defaultLabelType, lnLabel.blockType.Results)
   480  			} else {
   481  				defaultLabelType = make([]ValueType, len(lnLabel.blockType.Params))
   482  				copy(defaultLabelType, lnLabel.blockType.Params)
   483  			}
   484  
   485  			if enabledFeatures.IsEnabled(api.CoreFeatureReferenceTypes) {
   486  				// As of reference-types proposal, br_table on unreachable state
   487  				// can choose unknown types for expected parameter types for each label.
   488  				// https://github.com/WebAssembly/reference-types/pull/116
   489  				for i := range defaultLabelType {
   490  					index := len(defaultLabelType) - 1 - i
   491  					exp := defaultLabelType[index]
   492  					actual, err := valueTypeStack.pop()
   493  					if err != nil {
   494  						return err
   495  					}
   496  					if actual == valueTypeUnknown {
   497  						// Re-assign the expected type to unknown.
   498  						defaultLabelType[index] = valueTypeUnknown
   499  					} else if actual != exp {
   500  						return typeMismatchError(true, OpcodeBrTableName, actual, exp, i)
   501  					}
   502  				}
   503  			} else {
   504  				if err = valueTypeStack.popResults(op, defaultLabelType, false); err != nil {
   505  					return err
   506  				}
   507  			}
   508  
   509  			for _, l := range list {
   510  				if int(l) >= len(controlBlockStack.stack) {
   511  					return fmt.Errorf("invalid l param given for %s", OpcodeBrTableName)
   512  				}
   513  				label := &controlBlockStack.stack[len(controlBlockStack.stack)-1-int(l)]
   514  				var tableLabelType []ValueType
   515  				if label.op != OpcodeLoop {
   516  					tableLabelType = label.blockType.Results
   517  				} else {
   518  					tableLabelType = label.blockType.Params
   519  				}
   520  				if len(defaultLabelType) != len(tableLabelType) {
   521  					return fmt.Errorf("inconsistent block type length for %s at %d; %v (ln=%d) != %v (l=%d)", OpcodeBrTableName, l, defaultLabelType, ln, tableLabelType, l)
   522  				}
   523  				for i := range defaultLabelType {
   524  					if defaultLabelType[i] != valueTypeUnknown && defaultLabelType[i] != tableLabelType[i] {
   525  						return fmt.Errorf("incosistent block type for %s at %d", OpcodeBrTableName, l)
   526  					}
   527  				}
   528  			}
   529  
   530  			// br_table instruction is stack-polymorphic.
   531  			valueTypeStack.unreachable()
   532  		} else if op == OpcodeCall {
   533  			pc++
   534  			index, num, err := leb128.LoadUint32(body[pc:])
   535  			if err != nil {
   536  				return fmt.Errorf("read immediate: %v", err)
   537  			}
   538  			pc += num - 1
   539  			if int(index) >= len(functions) {
   540  				return fmt.Errorf("invalid function index")
   541  			}
   542  			funcType := &m.TypeSection[functions[index]]
   543  			for i := 0; i < len(funcType.Params); i++ {
   544  				if err := valueTypeStack.popAndVerifyType(funcType.Params[len(funcType.Params)-1-i]); err != nil {
   545  					return fmt.Errorf("type mismatch on %s operation param type: %v", OpcodeCallName, err)
   546  				}
   547  			}
   548  			for _, exp := range funcType.Results {
   549  				valueTypeStack.push(exp)
   550  			}
   551  		} else if op == OpcodeCallIndirect {
   552  			pc++
   553  			typeIndex, num, err := leb128.LoadUint32(body[pc:])
   554  			if err != nil {
   555  				return fmt.Errorf("read immediate: %v", err)
   556  			}
   557  			pc += num
   558  
   559  			if int(typeIndex) >= len(m.TypeSection) {
   560  				return fmt.Errorf("invalid type index at %s: %d", OpcodeCallIndirectName, typeIndex)
   561  			}
   562  
   563  			tableIndex, num, err := leb128.LoadUint32(body[pc:])
   564  			if err != nil {
   565  				return fmt.Errorf("read table index: %v", err)
   566  			}
   567  			pc += num - 1
   568  			if tableIndex != 0 {
   569  				if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
   570  					return fmt.Errorf("table index must be zero but was %d: %w", tableIndex, err)
   571  				}
   572  			}
   573  
   574  			if tableIndex >= uint32(len(tables)) {
   575  				return fmt.Errorf("unknown table index: %d", tableIndex)
   576  			}
   577  
   578  			table := tables[tableIndex]
   579  			if table.Type != RefTypeFuncref {
   580  				return fmt.Errorf("table is not funcref type but was %s for %s", RefTypeName(table.Type), OpcodeCallIndirectName)
   581  			}
   582  
   583  			if err = valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   584  				return fmt.Errorf("cannot pop the offset in table for %s", OpcodeCallIndirectName)
   585  			}
   586  			funcType := &m.TypeSection[typeIndex]
   587  			for i := 0; i < len(funcType.Params); i++ {
   588  				if err = valueTypeStack.popAndVerifyType(funcType.Params[len(funcType.Params)-1-i]); err != nil {
   589  					return fmt.Errorf("type mismatch on %s operation input type", OpcodeCallIndirectName)
   590  				}
   591  			}
   592  			for _, exp := range funcType.Results {
   593  				valueTypeStack.push(exp)
   594  			}
   595  		} else if OpcodeI32Eqz <= op && op <= OpcodeI64Extend32S {
   596  			switch op {
   597  			case OpcodeI32Eqz:
   598  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   599  					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI32EqzName, err)
   600  				}
   601  				valueTypeStack.push(ValueTypeI32)
   602  			case OpcodeI32Eq, OpcodeI32Ne, OpcodeI32LtS,
   603  				OpcodeI32LtU, OpcodeI32GtS, OpcodeI32GtU, OpcodeI32LeS,
   604  				OpcodeI32LeU, OpcodeI32GeS, OpcodeI32GeU:
   605  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   606  					return fmt.Errorf("cannot pop the 1st i32 operand for %s: %v", InstructionName(op), err)
   607  				}
   608  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   609  					return fmt.Errorf("cannot pop the 2nd i32 operand for %s: %v", InstructionName(op), err)
   610  				}
   611  				valueTypeStack.push(ValueTypeI32)
   612  			case OpcodeI64Eqz:
   613  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   614  					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI64EqzName, err)
   615  				}
   616  				valueTypeStack.push(ValueTypeI32)
   617  			case OpcodeI64Eq, OpcodeI64Ne, OpcodeI64LtS,
   618  				OpcodeI64LtU, OpcodeI64GtS, OpcodeI64GtU,
   619  				OpcodeI64LeS, OpcodeI64LeU, OpcodeI64GeS, OpcodeI64GeU:
   620  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   621  					return fmt.Errorf("cannot pop the 1st i64 operand for %s: %v", InstructionName(op), err)
   622  				}
   623  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   624  					return fmt.Errorf("cannot pop the 2nd i64 operand for %s: %v", InstructionName(op), err)
   625  				}
   626  				valueTypeStack.push(ValueTypeI32)
   627  			case OpcodeF32Eq, OpcodeF32Ne, OpcodeF32Lt, OpcodeF32Gt, OpcodeF32Le, OpcodeF32Ge:
   628  				if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
   629  					return fmt.Errorf("cannot pop the 1st f32 operand for %s: %v", InstructionName(op), err)
   630  				}
   631  				if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
   632  					return fmt.Errorf("cannot pop the 2nd f32 operand for %s: %v", InstructionName(op), err)
   633  				}
   634  				valueTypeStack.push(ValueTypeI32)
   635  			case OpcodeF64Eq, OpcodeF64Ne, OpcodeF64Lt, OpcodeF64Gt, OpcodeF64Le, OpcodeF64Ge:
   636  				if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
   637  					return fmt.Errorf("cannot pop the 1st f64 operand for %s: %v", InstructionName(op), err)
   638  				}
   639  				if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
   640  					return fmt.Errorf("cannot pop the 2nd f64 operand for %s: %v", InstructionName(op), err)
   641  				}
   642  				valueTypeStack.push(ValueTypeI32)
   643  			case OpcodeI32Clz, OpcodeI32Ctz, OpcodeI32Popcnt:
   644  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   645  					return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(op), err)
   646  				}
   647  				valueTypeStack.push(ValueTypeI32)
   648  			case OpcodeI32Add, OpcodeI32Sub, OpcodeI32Mul, OpcodeI32DivS,
   649  				OpcodeI32DivU, OpcodeI32RemS, OpcodeI32RemU, OpcodeI32And,
   650  				OpcodeI32Or, OpcodeI32Xor, OpcodeI32Shl, OpcodeI32ShrS,
   651  				OpcodeI32ShrU, OpcodeI32Rotl, OpcodeI32Rotr:
   652  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   653  					return fmt.Errorf("cannot pop the 1st operand for %s: %v", InstructionName(op), err)
   654  				}
   655  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   656  					return fmt.Errorf("cannot pop the 2nd operand for %s: %v", InstructionName(op), err)
   657  				}
   658  				valueTypeStack.push(ValueTypeI32)
   659  			case OpcodeI64Clz, OpcodeI64Ctz, OpcodeI64Popcnt:
   660  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   661  					return fmt.Errorf("cannot pop the i64 operand for %s: %v", InstructionName(op), err)
   662  				}
   663  				valueTypeStack.push(ValueTypeI64)
   664  			case OpcodeI64Add, OpcodeI64Sub, OpcodeI64Mul, OpcodeI64DivS,
   665  				OpcodeI64DivU, OpcodeI64RemS, OpcodeI64RemU, OpcodeI64And,
   666  				OpcodeI64Or, OpcodeI64Xor, OpcodeI64Shl, OpcodeI64ShrS,
   667  				OpcodeI64ShrU, OpcodeI64Rotl, OpcodeI64Rotr:
   668  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   669  					return fmt.Errorf("cannot pop the 1st i64 operand for %s: %v", InstructionName(op), err)
   670  				}
   671  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   672  					return fmt.Errorf("cannot pop the 2nd i64 operand for %s: %v", InstructionName(op), err)
   673  				}
   674  				valueTypeStack.push(ValueTypeI64)
   675  			case OpcodeF32Abs, OpcodeF32Neg, OpcodeF32Ceil,
   676  				OpcodeF32Floor, OpcodeF32Trunc, OpcodeF32Nearest,
   677  				OpcodeF32Sqrt:
   678  				if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
   679  					return fmt.Errorf("cannot pop the 1st f32 operand for %s: %v", InstructionName(op), err)
   680  				}
   681  				valueTypeStack.push(ValueTypeF32)
   682  			case OpcodeF32Add, OpcodeF32Sub, OpcodeF32Mul,
   683  				OpcodeF32Div, OpcodeF32Min, OpcodeF32Max,
   684  				OpcodeF32Copysign:
   685  				if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
   686  					return fmt.Errorf("cannot pop the 1st f32 operand for %s: %v", InstructionName(op), err)
   687  				}
   688  				if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
   689  					return fmt.Errorf("cannot pop the 2nd f32 operand for %s: %v", InstructionName(op), err)
   690  				}
   691  				valueTypeStack.push(ValueTypeF32)
   692  			case OpcodeF64Abs, OpcodeF64Neg, OpcodeF64Ceil,
   693  				OpcodeF64Floor, OpcodeF64Trunc, OpcodeF64Nearest,
   694  				OpcodeF64Sqrt:
   695  				if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
   696  					return fmt.Errorf("cannot pop the 1st f64 operand for %s: %v", InstructionName(op), err)
   697  				}
   698  				valueTypeStack.push(ValueTypeF64)
   699  			case OpcodeF64Add, OpcodeF64Sub, OpcodeF64Mul,
   700  				OpcodeF64Div, OpcodeF64Min, OpcodeF64Max,
   701  				OpcodeF64Copysign:
   702  				if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
   703  					return fmt.Errorf("cannot pop the 1st f64 operand for %s: %v", InstructionName(op), err)
   704  				}
   705  				if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
   706  					return fmt.Errorf("cannot pop the 2nd f64 operand for %s: %v", InstructionName(op), err)
   707  				}
   708  				valueTypeStack.push(ValueTypeF64)
   709  			case OpcodeI32WrapI64:
   710  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   711  					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI32WrapI64Name, err)
   712  				}
   713  				valueTypeStack.push(ValueTypeI32)
   714  			case OpcodeI32TruncF32S, OpcodeI32TruncF32U:
   715  				if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
   716  					return fmt.Errorf("cannot pop the f32 operand for %s: %v", InstructionName(op), err)
   717  				}
   718  				valueTypeStack.push(ValueTypeI32)
   719  			case OpcodeI32TruncF64S, OpcodeI32TruncF64U:
   720  				if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
   721  					return fmt.Errorf("cannot pop the f64 operand for %s: %v", InstructionName(op), err)
   722  				}
   723  				valueTypeStack.push(ValueTypeI32)
   724  			case OpcodeI64ExtendI32S, OpcodeI64ExtendI32U:
   725  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   726  					return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(op), err)
   727  				}
   728  				valueTypeStack.push(ValueTypeI64)
   729  			case OpcodeI64TruncF32S, OpcodeI64TruncF32U:
   730  				if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
   731  					return fmt.Errorf("cannot pop the f32 operand for %s: %v", InstructionName(op), err)
   732  				}
   733  				valueTypeStack.push(ValueTypeI64)
   734  			case OpcodeI64TruncF64S, OpcodeI64TruncF64U:
   735  				if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
   736  					return fmt.Errorf("cannot pop the f64 operand for %s: %v", InstructionName(op), err)
   737  				}
   738  				valueTypeStack.push(ValueTypeI64)
   739  			case OpcodeF32ConvertI32S, OpcodeF32ConvertI32U:
   740  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   741  					return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(op), err)
   742  				}
   743  				valueTypeStack.push(ValueTypeF32)
   744  			case OpcodeF32ConvertI64S, OpcodeF32ConvertI64U:
   745  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   746  					return fmt.Errorf("cannot pop the i64 operand for %s: %v", InstructionName(op), err)
   747  				}
   748  				valueTypeStack.push(ValueTypeF32)
   749  			case OpcodeF32DemoteF64:
   750  				if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
   751  					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF32DemoteF64Name, err)
   752  				}
   753  				valueTypeStack.push(ValueTypeF32)
   754  			case OpcodeF64ConvertI32S, OpcodeF64ConvertI32U:
   755  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   756  					return fmt.Errorf("cannot pop the i32 operand for %s: %v", InstructionName(op), err)
   757  				}
   758  				valueTypeStack.push(ValueTypeF64)
   759  			case OpcodeF64ConvertI64S, OpcodeF64ConvertI64U:
   760  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   761  					return fmt.Errorf("cannot pop the i64 operand for %s: %v", InstructionName(op), err)
   762  				}
   763  				valueTypeStack.push(ValueTypeF64)
   764  			case OpcodeF64PromoteF32:
   765  				if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
   766  					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF64PromoteF32Name, err)
   767  				}
   768  				valueTypeStack.push(ValueTypeF64)
   769  			case OpcodeI32ReinterpretF32:
   770  				if err := valueTypeStack.popAndVerifyType(ValueTypeF32); err != nil {
   771  					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI32ReinterpretF32Name, err)
   772  				}
   773  				valueTypeStack.push(ValueTypeI32)
   774  			case OpcodeI64ReinterpretF64:
   775  				if err := valueTypeStack.popAndVerifyType(ValueTypeF64); err != nil {
   776  					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeI64ReinterpretF64Name, err)
   777  				}
   778  				valueTypeStack.push(ValueTypeI64)
   779  			case OpcodeF32ReinterpretI32:
   780  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   781  					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF32ReinterpretI32Name, err)
   782  				}
   783  				valueTypeStack.push(ValueTypeF32)
   784  			case OpcodeF64ReinterpretI64:
   785  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   786  					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeF64ReinterpretI64Name, err)
   787  				}
   788  				valueTypeStack.push(ValueTypeF64)
   789  			case OpcodeI32Extend8S, OpcodeI32Extend16S:
   790  				if err := enabledFeatures.RequireEnabled(api.CoreFeatureSignExtensionOps); err != nil {
   791  					return fmt.Errorf("%s invalid as %v", instructionNames[op], err)
   792  				}
   793  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
   794  					return fmt.Errorf("cannot pop the operand for %s: %v", instructionNames[op], err)
   795  				}
   796  				valueTypeStack.push(ValueTypeI32)
   797  			case OpcodeI64Extend8S, OpcodeI64Extend16S, OpcodeI64Extend32S:
   798  				if err := enabledFeatures.RequireEnabled(api.CoreFeatureSignExtensionOps); err != nil {
   799  					return fmt.Errorf("%s invalid as %v", instructionNames[op], err)
   800  				}
   801  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
   802  					return fmt.Errorf("cannot pop the operand for %s: %v", instructionNames[op], err)
   803  				}
   804  				valueTypeStack.push(ValueTypeI64)
   805  			default:
   806  				return fmt.Errorf("invalid numeric instruction 0x%x", op)
   807  			}
   808  		} else if op >= OpcodeRefNull && op <= OpcodeRefFunc {
   809  			if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
   810  				return fmt.Errorf("%s invalid as %v", instructionNames[op], err)
   811  			}
   812  			switch op {
   813  			case OpcodeRefNull:
   814  				pc++
   815  				switch reftype := body[pc]; reftype {
   816  				case ValueTypeExternref:
   817  					valueTypeStack.push(ValueTypeExternref)
   818  				case ValueTypeFuncref:
   819  					valueTypeStack.push(ValueTypeFuncref)
   820  				default:
   821  					return fmt.Errorf("unknown type for ref.null: 0x%x", reftype)
   822  				}
   823  			case OpcodeRefIsNull:
   824  				tp, err := valueTypeStack.pop()
   825  				if err != nil {
   826  					return fmt.Errorf("cannot pop the operand for ref.is_null: %v", err)
   827  				} else if !isReferenceValueType(tp) && tp != valueTypeUnknown {
   828  					return fmt.Errorf("type mismatch: expected reference type but was %s", ValueTypeName(tp))
   829  				}
   830  				valueTypeStack.push(ValueTypeI32)
   831  			case OpcodeRefFunc:
   832  				pc++
   833  				index, num, err := leb128.LoadUint32(body[pc:])
   834  				if err != nil {
   835  					return fmt.Errorf("failed to read function index for ref.func: %v", err)
   836  				}
   837  				if _, ok := declaredFunctionIndexes[index]; !ok {
   838  					return fmt.Errorf("undeclared function index %d for ref.func", index)
   839  				}
   840  				pc += num - 1
   841  				valueTypeStack.push(ValueTypeFuncref)
   842  			}
   843  		} else if op == OpcodeTableGet || op == OpcodeTableSet {
   844  			if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
   845  				return fmt.Errorf("%s is invalid as %v", InstructionName(op), err)
   846  			}
   847  			pc++
   848  			tableIndex, num, err := leb128.LoadUint32(body[pc:])
   849  			if err != nil {
   850  				return fmt.Errorf("read immediate: %v", err)
   851  			}
   852  			if tableIndex >= uint32(len(tables)) {
   853  				return fmt.Errorf("table of index %d not found", tableIndex)
   854  			}
   855  
   856  			refType := tables[tableIndex].Type
   857  			if op == OpcodeTableGet {
   858  				if err := valueTypeStack.popAndVerifyType(api.ValueTypeI32); err != nil {
   859  					return fmt.Errorf("cannot pop the operand for table.get: %v", err)
   860  				}
   861  				valueTypeStack.push(refType)
   862  			} else {
   863  				if err := valueTypeStack.popAndVerifyType(refType); err != nil {
   864  					return fmt.Errorf("cannot pop the operand for table.set: %v", err)
   865  				}
   866  				if err := valueTypeStack.popAndVerifyType(api.ValueTypeI32); err != nil {
   867  					return fmt.Errorf("cannot pop the operand for table.set: %v", err)
   868  				}
   869  			}
   870  			pc += num - 1
   871  		} else if op == OpcodeMiscPrefix {
   872  			pc++
   873  			// A misc opcode is encoded as an unsigned variable 32-bit integer.
   874  			miscOp32, num, err := leb128.LoadUint32(body[pc:])
   875  			if err != nil {
   876  				return fmt.Errorf("failed to read misc opcode: %v", err)
   877  			}
   878  			pc += num - 1
   879  			miscOpcode := byte(miscOp32)
   880  			// If the misc opcode is beyond byte range, it is highly likely this is an invalid binary, or
   881  			// it is due to the new opcode from a new proposal. In the latter case, we have to
   882  			// change the alias type of OpcodeMisc (which is currently byte) to uint32.
   883  			if uint32(byte(miscOp32)) != miscOp32 {
   884  				return fmt.Errorf("invalid misc opcode: %#x", miscOp32)
   885  			}
   886  			if miscOpcode >= OpcodeMiscI32TruncSatF32S && miscOpcode <= OpcodeMiscI64TruncSatF64U {
   887  				if err := enabledFeatures.RequireEnabled(api.CoreFeatureNonTrappingFloatToIntConversion); err != nil {
   888  					return fmt.Errorf("%s invalid as %v", miscInstructionNames[miscOpcode], err)
   889  				}
   890  				var inType, outType ValueType
   891  				switch miscOpcode {
   892  				case OpcodeMiscI32TruncSatF32S, OpcodeMiscI32TruncSatF32U:
   893  					inType, outType = ValueTypeF32, ValueTypeI32
   894  				case OpcodeMiscI32TruncSatF64S, OpcodeMiscI32TruncSatF64U:
   895  					inType, outType = ValueTypeF64, ValueTypeI32
   896  				case OpcodeMiscI64TruncSatF32S, OpcodeMiscI64TruncSatF32U:
   897  					inType, outType = ValueTypeF32, ValueTypeI64
   898  				case OpcodeMiscI64TruncSatF64S, OpcodeMiscI64TruncSatF64U:
   899  					inType, outType = ValueTypeF64, ValueTypeI64
   900  				}
   901  				if err := valueTypeStack.popAndVerifyType(inType); err != nil {
   902  					return fmt.Errorf("cannot pop the operand for %s: %v", miscInstructionNames[miscOpcode], err)
   903  				}
   904  				valueTypeStack.push(outType)
   905  			} else if miscOpcode >= OpcodeMiscMemoryInit && miscOpcode <= OpcodeMiscTableCopy {
   906  				if err := enabledFeatures.RequireEnabled(api.CoreFeatureBulkMemoryOperations); err != nil {
   907  					return fmt.Errorf("%s invalid as %v", miscInstructionNames[miscOpcode], err)
   908  				}
   909  				var params []ValueType
   910  				// Handle opcodes added in bulk-memory-operations/WebAssembly 2.0.
   911  				switch miscOpcode {
   912  				case OpcodeMiscDataDrop:
   913  					if m.DataCountSection == nil {
   914  						return fmt.Errorf("%s requires data count section", MiscInstructionName(miscOpcode))
   915  					}
   916  
   917  					// We need to read the index to the data section.
   918  					pc++
   919  					index, num, err := leb128.LoadUint32(body[pc:])
   920  					if err != nil {
   921  						return fmt.Errorf("failed to read data segment index for %s: %v", MiscInstructionName(miscOpcode), err)
   922  					}
   923  					if int(index) >= len(m.DataSection) {
   924  						return fmt.Errorf("index %d out of range of data section(len=%d)", index, len(m.DataSection))
   925  					}
   926  					pc += num - 1
   927  				case OpcodeMiscMemoryInit, OpcodeMiscMemoryCopy, OpcodeMiscMemoryFill:
   928  					if memory == nil {
   929  						return fmt.Errorf("memory must exist for %s", MiscInstructionName(miscOpcode))
   930  					}
   931  					params = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
   932  
   933  					if miscOpcode == OpcodeMiscMemoryInit {
   934  						if m.DataCountSection == nil {
   935  							return fmt.Errorf("%s requires data count section", MiscInstructionName(miscOpcode))
   936  						}
   937  
   938  						// We need to read the index to the data section.
   939  						pc++
   940  						index, num, err := leb128.LoadUint32(body[pc:])
   941  						if err != nil {
   942  							return fmt.Errorf("failed to read data segment index for %s: %v", MiscInstructionName(miscOpcode), err)
   943  						}
   944  						if int(index) >= len(m.DataSection) {
   945  							return fmt.Errorf("index %d out of range of data section(len=%d)", index, len(m.DataSection))
   946  						}
   947  						pc += num - 1
   948  					}
   949  
   950  					pc++
   951  					val, num, err := leb128.LoadUint32(body[pc:])
   952  					if err != nil {
   953  						return fmt.Errorf("failed to read memory index for %s: %v", MiscInstructionName(miscOpcode), err)
   954  					}
   955  					if val != 0 || num != 1 {
   956  						return fmt.Errorf("%s reserved byte must be zero encoded with 1 byte", MiscInstructionName(miscOpcode))
   957  					}
   958  					if miscOpcode == OpcodeMiscMemoryCopy {
   959  						pc++
   960  						// memory.copy needs two memory index which are reserved as zero.
   961  						val, num, err := leb128.LoadUint32(body[pc:])
   962  						if err != nil {
   963  							return fmt.Errorf("failed to read memory index for %s: %v", MiscInstructionName(miscOpcode), err)
   964  						}
   965  						if val != 0 || num != 1 {
   966  							return fmt.Errorf("%s reserved byte must be zero encoded with 1 byte", MiscInstructionName(miscOpcode))
   967  						}
   968  					}
   969  
   970  				case OpcodeMiscTableInit:
   971  					params = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
   972  					pc++
   973  					elementIndex, num, err := leb128.LoadUint32(body[pc:])
   974  					if err != nil {
   975  						return fmt.Errorf("failed to read element segment index for %s: %v", MiscInstructionName(miscOpcode), err)
   976  					}
   977  					if int(elementIndex) >= len(m.ElementSection) {
   978  						return fmt.Errorf("index %d out of range of element section(len=%d)", elementIndex, len(m.ElementSection))
   979  					}
   980  					pc += num
   981  
   982  					tableIndex, num, err := leb128.LoadUint32(body[pc:])
   983  					if err != nil {
   984  						return fmt.Errorf("failed to read source table index for %s: %v", MiscInstructionName(miscOpcode), err)
   985  					}
   986  					if tableIndex != 0 {
   987  						if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
   988  							return fmt.Errorf("source table index must be zero for %s as %v", MiscInstructionName(miscOpcode), err)
   989  						}
   990  					}
   991  					if tableIndex >= uint32(len(tables)) {
   992  						return fmt.Errorf("table of index %d not found", tableIndex)
   993  					}
   994  
   995  					if m.ElementSection[elementIndex].Type != tables[tableIndex].Type {
   996  						return fmt.Errorf("type mismatch for table.init: element type %s does not match table type %s",
   997  							RefTypeName(m.ElementSection[elementIndex].Type),
   998  							RefTypeName(tables[tableIndex].Type),
   999  						)
  1000  					}
  1001  					pc += num - 1
  1002  				case OpcodeMiscElemDrop:
  1003  					pc++
  1004  					elementIndex, num, err := leb128.LoadUint32(body[pc:])
  1005  					if err != nil {
  1006  						return fmt.Errorf("failed to read element segment index for %s: %v", MiscInstructionName(miscOpcode), err)
  1007  					} else if int(elementIndex) >= len(m.ElementSection) {
  1008  						return fmt.Errorf("index %d out of range of element section(len=%d)", elementIndex, len(m.ElementSection))
  1009  					}
  1010  					pc += num - 1
  1011  				case OpcodeMiscTableCopy:
  1012  					params = []ValueType{ValueTypeI32, ValueTypeI32, ValueTypeI32}
  1013  					pc++
  1014  
  1015  					dstTableIndex, num, err := leb128.LoadUint32(body[pc:])
  1016  					if err != nil {
  1017  						return fmt.Errorf("failed to read destination table index for %s: %v", MiscInstructionName(miscOpcode), err)
  1018  					}
  1019  					if dstTableIndex != 0 {
  1020  						if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
  1021  							return fmt.Errorf("destination table index must be zero for %s as %v", MiscInstructionName(miscOpcode), err)
  1022  						}
  1023  					}
  1024  					if dstTableIndex >= uint32(len(tables)) {
  1025  						return fmt.Errorf("table of index %d not found", dstTableIndex)
  1026  					}
  1027  					pc += num
  1028  
  1029  					srcTableIndex, num, err := leb128.LoadUint32(body[pc:])
  1030  					if err != nil {
  1031  						return fmt.Errorf("failed to read source table index for %s: %v", MiscInstructionName(miscOpcode), err)
  1032  					}
  1033  					if srcTableIndex != 0 {
  1034  						if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
  1035  							return fmt.Errorf("source table index must be zero for %s as %v", MiscInstructionName(miscOpcode), err)
  1036  						}
  1037  					}
  1038  					if srcTableIndex >= uint32(len(tables)) {
  1039  						return fmt.Errorf("table of index %d not found", srcTableIndex)
  1040  					}
  1041  
  1042  					if tables[srcTableIndex].Type != tables[dstTableIndex].Type {
  1043  						return fmt.Errorf("table type mismatch for table.copy: %s (src) != %s (dst)",
  1044  							RefTypeName(tables[srcTableIndex].Type), RefTypeName(tables[dstTableIndex].Type))
  1045  					}
  1046  
  1047  					pc += num - 1
  1048  				}
  1049  				for _, p := range params {
  1050  					if err := valueTypeStack.popAndVerifyType(p); err != nil {
  1051  						return fmt.Errorf("cannot pop the operand for %s: %v", miscInstructionNames[miscOpcode], err)
  1052  					}
  1053  				}
  1054  			} else if miscOpcode >= OpcodeMiscTableGrow && miscOpcode <= OpcodeMiscTableFill {
  1055  				if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
  1056  					return fmt.Errorf("%s invalid as %v", miscInstructionNames[miscOpcode], err)
  1057  				}
  1058  
  1059  				pc++
  1060  				tableIndex, num, err := leb128.LoadUint32(body[pc:])
  1061  				if err != nil {
  1062  					return fmt.Errorf("failed to read table index for %s: %v", MiscInstructionName(miscOpcode), err)
  1063  				}
  1064  				if tableIndex >= uint32(len(tables)) {
  1065  					return fmt.Errorf("table of index %d not found", tableIndex)
  1066  				}
  1067  				pc += num - 1
  1068  
  1069  				var params, results []ValueType
  1070  				reftype := tables[tableIndex].Type
  1071  				if miscOpcode == OpcodeMiscTableGrow {
  1072  					params = []ValueType{ValueTypeI32, reftype}
  1073  					results = []ValueType{ValueTypeI32}
  1074  				} else if miscOpcode == OpcodeMiscTableSize {
  1075  					results = []ValueType{ValueTypeI32}
  1076  				} else if miscOpcode == OpcodeMiscTableFill {
  1077  					params = []ValueType{ValueTypeI32, reftype, ValueTypeI32}
  1078  				}
  1079  
  1080  				for _, p := range params {
  1081  					if err := valueTypeStack.popAndVerifyType(p); err != nil {
  1082  						return fmt.Errorf("cannot pop the operand for %s: %v", miscInstructionNames[miscOpcode], err)
  1083  					}
  1084  				}
  1085  				for _, r := range results {
  1086  					valueTypeStack.push(r)
  1087  				}
  1088  			}
  1089  		} else if op == OpcodeVecPrefix {
  1090  			pc++
  1091  			// Vector instructions come with two bytes where the first byte is always OpcodeVecPrefix,
  1092  			// and the second byte determines the actual instruction.
  1093  			vecOpcode := body[pc]
  1094  			if err := enabledFeatures.RequireEnabled(api.CoreFeatureSIMD); err != nil {
  1095  				return fmt.Errorf("%s invalid as %v", vectorInstructionName[vecOpcode], err)
  1096  			}
  1097  
  1098  			switch vecOpcode {
  1099  			case OpcodeVecV128Const:
  1100  				// Read 128-bit = 16 bytes constants
  1101  				if int(pc+16) >= len(body) {
  1102  					return fmt.Errorf("cannot read constant vector value for %s", vectorInstructionName[vecOpcode])
  1103  				}
  1104  				pc += 16
  1105  				valueTypeStack.push(ValueTypeV128)
  1106  			case OpcodeVecV128AnyTrue, OpcodeVecI8x16AllTrue, OpcodeVecI16x8AllTrue, OpcodeVecI32x4AllTrue, OpcodeVecI64x2AllTrue,
  1107  				OpcodeVecI8x16BitMask, OpcodeVecI16x8BitMask, OpcodeVecI32x4BitMask, OpcodeVecI64x2BitMask:
  1108  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1109  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1110  				}
  1111  				valueTypeStack.push(ValueTypeI32)
  1112  			case OpcodeVecV128Load, OpcodeVecV128Load8x8s, OpcodeVecV128Load8x8u, OpcodeVecV128Load16x4s, OpcodeVecV128Load16x4u,
  1113  				OpcodeVecV128Load32x2s, OpcodeVecV128Load32x2u, OpcodeVecV128Load8Splat, OpcodeVecV128Load16Splat,
  1114  				OpcodeVecV128Load32Splat, OpcodeVecV128Load64Splat,
  1115  				OpcodeVecV128Load32zero, OpcodeVecV128Load64zero:
  1116  				if memory == nil {
  1117  					return fmt.Errorf("memory must exist for %s", VectorInstructionName(vecOpcode))
  1118  				}
  1119  				pc++
  1120  				align, _, read, err := readMemArg(pc, body)
  1121  				if err != nil {
  1122  					return err
  1123  				}
  1124  				pc += read - 1
  1125  				var maxAlign uint32
  1126  				switch vecOpcode {
  1127  				case OpcodeVecV128Load:
  1128  					maxAlign = 128 / 8
  1129  				case OpcodeVecV128Load8x8s, OpcodeVecV128Load8x8u, OpcodeVecV128Load16x4s, OpcodeVecV128Load16x4u,
  1130  					OpcodeVecV128Load32x2s, OpcodeVecV128Load32x2u:
  1131  					maxAlign = 64 / 8
  1132  				case OpcodeVecV128Load8Splat:
  1133  					maxAlign = 1
  1134  				case OpcodeVecV128Load16Splat:
  1135  					maxAlign = 16 / 8
  1136  				case OpcodeVecV128Load32Splat:
  1137  					maxAlign = 32 / 8
  1138  				case OpcodeVecV128Load64Splat:
  1139  					maxAlign = 64 / 8
  1140  				case OpcodeVecV128Load32zero:
  1141  					maxAlign = 32 / 8
  1142  				case OpcodeVecV128Load64zero:
  1143  					maxAlign = 64 / 8
  1144  				}
  1145  
  1146  				if 1<<align > maxAlign {
  1147  					return fmt.Errorf("invalid memory alignment %d for %s", align, VectorInstructionName(vecOpcode))
  1148  				}
  1149  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1150  					return fmt.Errorf("cannot pop the operand for %s: %v", VectorInstructionName(vecOpcode), err)
  1151  				}
  1152  				valueTypeStack.push(ValueTypeV128)
  1153  			case OpcodeVecV128Store:
  1154  				if memory == nil {
  1155  					return fmt.Errorf("memory must exist for %s", VectorInstructionName(vecOpcode))
  1156  				}
  1157  				pc++
  1158  				align, _, read, err := readMemArg(pc, body)
  1159  				if err != nil {
  1160  					return err
  1161  				}
  1162  				pc += read - 1
  1163  				if 1<<align > 128/8 {
  1164  					return fmt.Errorf("invalid memory alignment %d for %s", align, OpcodeVecV128StoreName)
  1165  				}
  1166  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1167  					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeVecV128StoreName, err)
  1168  				}
  1169  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1170  					return fmt.Errorf("cannot pop the operand for %s: %v", OpcodeVecV128StoreName, err)
  1171  				}
  1172  			case OpcodeVecV128Load8Lane, OpcodeVecV128Load16Lane, OpcodeVecV128Load32Lane, OpcodeVecV128Load64Lane:
  1173  				if memory == nil {
  1174  					return fmt.Errorf("memory must exist for %s", VectorInstructionName(vecOpcode))
  1175  				}
  1176  				attr := vecLoadLanes[vecOpcode]
  1177  				pc++
  1178  				align, _, read, err := readMemArg(pc, body)
  1179  				if err != nil {
  1180  					return err
  1181  				}
  1182  				if 1<<align > attr.alignMax {
  1183  					return fmt.Errorf("invalid memory alignment %d for %s", align, vectorInstructionName[vecOpcode])
  1184  				}
  1185  				pc += read
  1186  				if pc >= uint64(len(body)) {
  1187  					return fmt.Errorf("lane for %s not found", OpcodeVecV128Load64LaneName)
  1188  				}
  1189  				lane := body[pc]
  1190  				if lane >= attr.laneCeil {
  1191  					return fmt.Errorf("invalid lane index %d >= %d for %s", lane, attr.laneCeil, vectorInstructionName[vecOpcode])
  1192  				}
  1193  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1194  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1195  				}
  1196  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1197  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1198  				}
  1199  				valueTypeStack.push(ValueTypeV128)
  1200  			case OpcodeVecV128Store8Lane, OpcodeVecV128Store16Lane, OpcodeVecV128Store32Lane, OpcodeVecV128Store64Lane:
  1201  				if memory == nil {
  1202  					return fmt.Errorf("memory must exist for %s", VectorInstructionName(vecOpcode))
  1203  				}
  1204  				attr := vecStoreLanes[vecOpcode]
  1205  				pc++
  1206  				align, _, read, err := readMemArg(pc, body)
  1207  				if err != nil {
  1208  					return err
  1209  				}
  1210  				if 1<<align > attr.alignMax {
  1211  					return fmt.Errorf("invalid memory alignment %d for %s", align, vectorInstructionName[vecOpcode])
  1212  				}
  1213  				pc += read
  1214  				if pc >= uint64(len(body)) {
  1215  					return fmt.Errorf("lane for %s not found", vectorInstructionName[vecOpcode])
  1216  				}
  1217  				lane := body[pc]
  1218  				if lane >= attr.laneCeil {
  1219  					return fmt.Errorf("invalid lane index %d >= %d for %s", lane, attr.laneCeil, vectorInstructionName[vecOpcode])
  1220  				}
  1221  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1222  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1223  				}
  1224  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1225  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1226  				}
  1227  			case OpcodeVecI8x16ExtractLaneS,
  1228  				OpcodeVecI8x16ExtractLaneU,
  1229  				OpcodeVecI16x8ExtractLaneS,
  1230  				OpcodeVecI16x8ExtractLaneU,
  1231  				OpcodeVecI32x4ExtractLane,
  1232  				OpcodeVecI64x2ExtractLane,
  1233  				OpcodeVecF32x4ExtractLane,
  1234  				OpcodeVecF64x2ExtractLane:
  1235  				pc++
  1236  				if pc >= uint64(len(body)) {
  1237  					return fmt.Errorf("lane for %s not found", vectorInstructionName[vecOpcode])
  1238  				}
  1239  				attr := vecExtractLanes[vecOpcode]
  1240  				lane := body[pc]
  1241  				if lane >= attr.laneCeil {
  1242  					return fmt.Errorf("invalid lane index %d >= %d for %s", lane, attr.laneCeil, vectorInstructionName[vecOpcode])
  1243  				}
  1244  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1245  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1246  				}
  1247  				valueTypeStack.push(attr.resultType)
  1248  			case OpcodeVecI8x16ReplaceLane, OpcodeVecI16x8ReplaceLane, OpcodeVecI32x4ReplaceLane,
  1249  				OpcodeVecI64x2ReplaceLane, OpcodeVecF32x4ReplaceLane, OpcodeVecF64x2ReplaceLane:
  1250  				pc++
  1251  				if pc >= uint64(len(body)) {
  1252  					return fmt.Errorf("lane for %s not found", vectorInstructionName[vecOpcode])
  1253  				}
  1254  				attr := vecReplaceLanes[vecOpcode]
  1255  				lane := body[pc]
  1256  				if lane >= attr.laneCeil {
  1257  					return fmt.Errorf("invalid lane index %d >= %d for %s", lane, attr.laneCeil, vectorInstructionName[vecOpcode])
  1258  				}
  1259  				if err := valueTypeStack.popAndVerifyType(attr.paramType); err != nil {
  1260  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1261  				}
  1262  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1263  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1264  				}
  1265  				valueTypeStack.push(ValueTypeV128)
  1266  			case OpcodeVecI8x16Splat, OpcodeVecI16x8Splat, OpcodeVecI32x4Splat,
  1267  				OpcodeVecI64x2Splat, OpcodeVecF32x4Splat, OpcodeVecF64x2Splat:
  1268  				tp := vecSplatValueTypes[vecOpcode]
  1269  				if err := valueTypeStack.popAndVerifyType(tp); err != nil {
  1270  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1271  				}
  1272  				valueTypeStack.push(ValueTypeV128)
  1273  			case OpcodeVecI8x16Swizzle, OpcodeVecV128And, OpcodeVecV128Or, OpcodeVecV128Xor, OpcodeVecV128AndNot:
  1274  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1275  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1276  				}
  1277  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1278  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1279  				}
  1280  				valueTypeStack.push(ValueTypeV128)
  1281  			case OpcodeVecV128Bitselect:
  1282  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1283  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1284  				}
  1285  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1286  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1287  				}
  1288  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1289  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1290  				}
  1291  				valueTypeStack.push(ValueTypeV128)
  1292  			case OpcodeVecV128Not:
  1293  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1294  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1295  				}
  1296  				valueTypeStack.push(ValueTypeV128)
  1297  			case OpcodeVecV128i8x16Shuffle:
  1298  				pc++
  1299  				if pc+15 >= uint64(len(body)) {
  1300  					return fmt.Errorf("16 lane indexes for %s not found", vectorInstructionName[vecOpcode])
  1301  				}
  1302  				lanes := body[pc : pc+16]
  1303  				for i, l := range lanes {
  1304  					if l >= 32 {
  1305  						return fmt.Errorf("invalid lane index[%d] %d >= %d for %s", i, l, 32, vectorInstructionName[vecOpcode])
  1306  					}
  1307  				}
  1308  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1309  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1310  				}
  1311  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1312  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1313  				}
  1314  				valueTypeStack.push(ValueTypeV128)
  1315  				pc += 15
  1316  			case OpcodeVecI8x16Shl, OpcodeVecI8x16ShrS, OpcodeVecI8x16ShrU,
  1317  				OpcodeVecI16x8Shl, OpcodeVecI16x8ShrS, OpcodeVecI16x8ShrU,
  1318  				OpcodeVecI32x4Shl, OpcodeVecI32x4ShrS, OpcodeVecI32x4ShrU,
  1319  				OpcodeVecI64x2Shl, OpcodeVecI64x2ShrS, OpcodeVecI64x2ShrU:
  1320  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1321  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1322  				}
  1323  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1324  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1325  				}
  1326  				valueTypeStack.push(ValueTypeV128)
  1327  			case OpcodeVecI8x16Eq, OpcodeVecI8x16Ne, OpcodeVecI8x16LtS, OpcodeVecI8x16LtU, OpcodeVecI8x16GtS,
  1328  				OpcodeVecI8x16GtU, OpcodeVecI8x16LeS, OpcodeVecI8x16LeU, OpcodeVecI8x16GeS, OpcodeVecI8x16GeU,
  1329  				OpcodeVecI16x8Eq, OpcodeVecI16x8Ne, OpcodeVecI16x8LtS, OpcodeVecI16x8LtU, OpcodeVecI16x8GtS,
  1330  				OpcodeVecI16x8GtU, OpcodeVecI16x8LeS, OpcodeVecI16x8LeU, OpcodeVecI16x8GeS, OpcodeVecI16x8GeU,
  1331  				OpcodeVecI32x4Eq, OpcodeVecI32x4Ne, OpcodeVecI32x4LtS, OpcodeVecI32x4LtU, OpcodeVecI32x4GtS,
  1332  				OpcodeVecI32x4GtU, OpcodeVecI32x4LeS, OpcodeVecI32x4LeU, OpcodeVecI32x4GeS, OpcodeVecI32x4GeU,
  1333  				OpcodeVecI64x2Eq, OpcodeVecI64x2Ne, OpcodeVecI64x2LtS, OpcodeVecI64x2GtS, OpcodeVecI64x2LeS,
  1334  				OpcodeVecI64x2GeS, OpcodeVecF32x4Eq, OpcodeVecF32x4Ne, OpcodeVecF32x4Lt, OpcodeVecF32x4Gt,
  1335  				OpcodeVecF32x4Le, OpcodeVecF32x4Ge, OpcodeVecF64x2Eq, OpcodeVecF64x2Ne, OpcodeVecF64x2Lt,
  1336  				OpcodeVecF64x2Gt, OpcodeVecF64x2Le, OpcodeVecF64x2Ge,
  1337  				OpcodeVecI32x4DotI16x8S,
  1338  				OpcodeVecI8x16NarrowI16x8S, OpcodeVecI8x16NarrowI16x8U, OpcodeVecI16x8NarrowI32x4S, OpcodeVecI16x8NarrowI32x4U:
  1339  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1340  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1341  				}
  1342  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1343  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1344  				}
  1345  				valueTypeStack.push(ValueTypeV128)
  1346  			case OpcodeVecI8x16Neg, OpcodeVecI16x8Neg, OpcodeVecI32x4Neg, OpcodeVecI64x2Neg, OpcodeVecF32x4Neg, OpcodeVecF64x2Neg,
  1347  				OpcodeVecF32x4Sqrt, OpcodeVecF64x2Sqrt,
  1348  				OpcodeVecI8x16Abs, OpcodeVecI8x16Popcnt, OpcodeVecI16x8Abs, OpcodeVecI32x4Abs, OpcodeVecI64x2Abs,
  1349  				OpcodeVecF32x4Abs, OpcodeVecF64x2Abs,
  1350  				OpcodeVecF32x4Ceil, OpcodeVecF32x4Floor, OpcodeVecF32x4Trunc, OpcodeVecF32x4Nearest,
  1351  				OpcodeVecF64x2Ceil, OpcodeVecF64x2Floor, OpcodeVecF64x2Trunc, OpcodeVecF64x2Nearest,
  1352  				OpcodeVecI16x8ExtendLowI8x16S, OpcodeVecI16x8ExtendHighI8x16S, OpcodeVecI16x8ExtendLowI8x16U, OpcodeVecI16x8ExtendHighI8x16U,
  1353  				OpcodeVecI32x4ExtendLowI16x8S, OpcodeVecI32x4ExtendHighI16x8S, OpcodeVecI32x4ExtendLowI16x8U, OpcodeVecI32x4ExtendHighI16x8U,
  1354  				OpcodeVecI64x2ExtendLowI32x4S, OpcodeVecI64x2ExtendHighI32x4S, OpcodeVecI64x2ExtendLowI32x4U, OpcodeVecI64x2ExtendHighI32x4U,
  1355  				OpcodeVecI16x8ExtaddPairwiseI8x16S, OpcodeVecI16x8ExtaddPairwiseI8x16U,
  1356  				OpcodeVecI32x4ExtaddPairwiseI16x8S, OpcodeVecI32x4ExtaddPairwiseI16x8U,
  1357  				OpcodeVecF64x2PromoteLowF32x4Zero, OpcodeVecF32x4DemoteF64x2Zero,
  1358  				OpcodeVecF32x4ConvertI32x4S, OpcodeVecF32x4ConvertI32x4U,
  1359  				OpcodeVecF64x2ConvertLowI32x4S, OpcodeVecF64x2ConvertLowI32x4U,
  1360  				OpcodeVecI32x4TruncSatF32x4S, OpcodeVecI32x4TruncSatF32x4U, OpcodeVecI32x4TruncSatF64x2SZero, OpcodeVecI32x4TruncSatF64x2UZero:
  1361  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1362  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1363  				}
  1364  				valueTypeStack.push(ValueTypeV128)
  1365  
  1366  			case OpcodeVecI8x16Add, OpcodeVecI8x16AddSatS, OpcodeVecI8x16AddSatU, OpcodeVecI8x16Sub, OpcodeVecI8x16SubSatS, OpcodeVecI8x16SubSatU,
  1367  				OpcodeVecI16x8Add, OpcodeVecI16x8AddSatS, OpcodeVecI16x8AddSatU, OpcodeVecI16x8Sub, OpcodeVecI16x8SubSatS, OpcodeVecI16x8SubSatU, OpcodeVecI16x8Mul,
  1368  				OpcodeVecI32x4Add, OpcodeVecI32x4Sub, OpcodeVecI32x4Mul,
  1369  				OpcodeVecI64x2Add, OpcodeVecI64x2Sub, OpcodeVecI64x2Mul,
  1370  				OpcodeVecF32x4Add, OpcodeVecF32x4Sub, OpcodeVecF32x4Mul, OpcodeVecF32x4Div,
  1371  				OpcodeVecF64x2Add, OpcodeVecF64x2Sub, OpcodeVecF64x2Mul, OpcodeVecF64x2Div,
  1372  				OpcodeVecI8x16MinS, OpcodeVecI8x16MinU, OpcodeVecI8x16MaxS, OpcodeVecI8x16MaxU,
  1373  				OpcodeVecI8x16AvgrU,
  1374  				OpcodeVecI16x8MinS, OpcodeVecI16x8MinU, OpcodeVecI16x8MaxS, OpcodeVecI16x8MaxU,
  1375  				OpcodeVecI16x8AvgrU,
  1376  				OpcodeVecI32x4MinS, OpcodeVecI32x4MinU, OpcodeVecI32x4MaxS, OpcodeVecI32x4MaxU,
  1377  				OpcodeVecF32x4Min, OpcodeVecF32x4Max, OpcodeVecF64x2Min, OpcodeVecF64x2Max,
  1378  				OpcodeVecF32x4Pmin, OpcodeVecF32x4Pmax, OpcodeVecF64x2Pmin, OpcodeVecF64x2Pmax,
  1379  				OpcodeVecI16x8Q15mulrSatS,
  1380  				OpcodeVecI16x8ExtMulLowI8x16S, OpcodeVecI16x8ExtMulHighI8x16S, OpcodeVecI16x8ExtMulLowI8x16U, OpcodeVecI16x8ExtMulHighI8x16U,
  1381  				OpcodeVecI32x4ExtMulLowI16x8S, OpcodeVecI32x4ExtMulHighI16x8S, OpcodeVecI32x4ExtMulLowI16x8U, OpcodeVecI32x4ExtMulHighI16x8U,
  1382  				OpcodeVecI64x2ExtMulLowI32x4S, OpcodeVecI64x2ExtMulHighI32x4S, OpcodeVecI64x2ExtMulLowI32x4U, OpcodeVecI64x2ExtMulHighI32x4U:
  1383  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1384  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1385  				}
  1386  				if err := valueTypeStack.popAndVerifyType(ValueTypeV128); err != nil {
  1387  					return fmt.Errorf("cannot pop the operand for %s: %v", vectorInstructionName[vecOpcode], err)
  1388  				}
  1389  				valueTypeStack.push(ValueTypeV128)
  1390  			default:
  1391  				return fmt.Errorf("TODO: SIMD instruction %s will be implemented in #506", vectorInstructionName[vecOpcode])
  1392  			}
  1393  		} else if op == OpcodeBlock {
  1394  			br.Reset(body[pc+1:])
  1395  			bt, num, err := DecodeBlockType(m.TypeSection, br, enabledFeatures)
  1396  			if err != nil {
  1397  				return fmt.Errorf("read block: %w", err)
  1398  			}
  1399  			controlBlockStack.push(pc, 0, 0, bt, num, 0)
  1400  			if err = valueTypeStack.popParams(op, bt.Params, false); err != nil {
  1401  				return err
  1402  			}
  1403  			// Plus we have to push any block params again.
  1404  			for _, p := range bt.Params {
  1405  				valueTypeStack.push(p)
  1406  			}
  1407  			valueTypeStack.pushStackLimit(len(bt.Params))
  1408  			pc += num
  1409  		} else if op == OpcodeAtomicPrefix {
  1410  			pc++
  1411  			// Atomic instructions come with two bytes where the first byte is always OpcodeAtomicPrefix,
  1412  			// and the second byte determines the actual instruction.
  1413  			atomicOpcode := body[pc]
  1414  			// TODO: Check that CoreFeatureThreads is enabled
  1415  			pc++
  1416  
  1417  			if atomicOpcode == OpcodeAtomicFence {
  1418  				// No memory requirement and no arguments or return, however the immediate byte value must be 0.
  1419  				imm := body[pc]
  1420  				if imm != 0x0 {
  1421  					return fmt.Errorf("invalid immediate value for %s", AtomicInstructionName(atomicOpcode))
  1422  				}
  1423  				continue
  1424  			}
  1425  
  1426  			// All atomic operations except fence (checked above) require memory
  1427  			if memory == nil {
  1428  				return fmt.Errorf("memory must exist for %s", AtomicInstructionName(atomicOpcode))
  1429  			}
  1430  			align, _, read, err := readMemArg(pc, body)
  1431  			if err != nil {
  1432  				return err
  1433  			}
  1434  			pc += read - 1
  1435  			switch atomicOpcode {
  1436  			case OpcodeAtomicMemoryNotify:
  1437  				if 1<<align > 32/8 {
  1438  					return fmt.Errorf("invalid memory alignment")
  1439  				}
  1440  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1441  					return err
  1442  				}
  1443  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1444  					return err
  1445  				}
  1446  				valueTypeStack.push(ValueTypeI32)
  1447  			case OpcodeAtomicMemoryWait32:
  1448  				if 1<<align > 32/8 {
  1449  					return fmt.Errorf("invalid memory alignment")
  1450  				}
  1451  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1452  					return err
  1453  				}
  1454  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1455  					return err
  1456  				}
  1457  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1458  					return err
  1459  				}
  1460  				valueTypeStack.push(ValueTypeI32)
  1461  			case OpcodeAtomicMemoryWait64:
  1462  				if 1<<align > 64/8 {
  1463  					return fmt.Errorf("invalid memory alignment")
  1464  				}
  1465  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1466  					return err
  1467  				}
  1468  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1469  					return err
  1470  				}
  1471  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1472  					return err
  1473  				}
  1474  				valueTypeStack.push(ValueTypeI32)
  1475  			case OpcodeAtomicI32Load:
  1476  				if 1<<align > 32/8 {
  1477  					return fmt.Errorf("invalid memory alignment")
  1478  				}
  1479  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1480  					return err
  1481  				}
  1482  				valueTypeStack.push(ValueTypeI32)
  1483  			case OpcodeAtomicI64Load:
  1484  				if 1<<align > 64/8 {
  1485  					return fmt.Errorf("invalid memory alignment")
  1486  				}
  1487  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1488  					return err
  1489  				}
  1490  				valueTypeStack.push(ValueTypeI64)
  1491  			case OpcodeAtomicI32Load8U:
  1492  				if 1<<align != 1 {
  1493  					return fmt.Errorf("invalid memory alignment")
  1494  				}
  1495  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1496  					return err
  1497  				}
  1498  				valueTypeStack.push(ValueTypeI32)
  1499  			case OpcodeAtomicI32Load16U:
  1500  				if 1<<align != 16/8 {
  1501  					return fmt.Errorf("invalid memory alignment")
  1502  				}
  1503  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1504  					return err
  1505  				}
  1506  				valueTypeStack.push(ValueTypeI32)
  1507  			case OpcodeAtomicI64Load8U:
  1508  				if 1<<align != 1 {
  1509  					return fmt.Errorf("invalid memory alignment")
  1510  				}
  1511  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1512  					return err
  1513  				}
  1514  				valueTypeStack.push(ValueTypeI64)
  1515  			case OpcodeAtomicI64Load16U:
  1516  				if 1<<align > 16/8 {
  1517  					return fmt.Errorf("invalid memory alignment")
  1518  				}
  1519  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1520  					return err
  1521  				}
  1522  				valueTypeStack.push(ValueTypeI64)
  1523  			case OpcodeAtomicI64Load32U:
  1524  				if 1<<align > 32/8 {
  1525  					return fmt.Errorf("invalid memory alignment")
  1526  				}
  1527  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1528  					return err
  1529  				}
  1530  				valueTypeStack.push(ValueTypeI64)
  1531  			case OpcodeAtomicI32Store:
  1532  				if 1<<align > 32/8 {
  1533  					return fmt.Errorf("invalid memory alignment")
  1534  				}
  1535  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1536  					return err
  1537  				}
  1538  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1539  					return err
  1540  				}
  1541  			case OpcodeAtomicI64Store:
  1542  				if 1<<align > 64/8 {
  1543  					return fmt.Errorf("invalid memory alignment")
  1544  				}
  1545  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1546  					return err
  1547  				}
  1548  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1549  					return err
  1550  				}
  1551  			case OpcodeAtomicI32Store8:
  1552  				if 1<<align > 1 {
  1553  					return fmt.Errorf("invalid memory alignment")
  1554  				}
  1555  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1556  					return err
  1557  				}
  1558  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1559  					return err
  1560  				}
  1561  			case OpcodeAtomicI32Store16:
  1562  				if 1<<align > 16/8 {
  1563  					return fmt.Errorf("invalid memory alignment")
  1564  				}
  1565  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1566  					return err
  1567  				}
  1568  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1569  					return err
  1570  				}
  1571  			case OpcodeAtomicI64Store8:
  1572  				if 1<<align > 1 {
  1573  					return fmt.Errorf("invalid memory alignment")
  1574  				}
  1575  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1576  					return err
  1577  				}
  1578  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1579  					return err
  1580  				}
  1581  			case OpcodeAtomicI64Store16:
  1582  				if 1<<align > 16/8 {
  1583  					return fmt.Errorf("invalid memory alignment")
  1584  				}
  1585  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1586  					return err
  1587  				}
  1588  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1589  					return err
  1590  				}
  1591  			case OpcodeAtomicI64Store32:
  1592  				if 1<<align > 32/8 {
  1593  					return fmt.Errorf("invalid memory alignment")
  1594  				}
  1595  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1596  					return err
  1597  				}
  1598  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1599  					return err
  1600  				}
  1601  			case OpcodeAtomicI32RmwAdd, OpcodeAtomicI32RmwSub, OpcodeAtomicI32RmwAnd, OpcodeAtomicI32RmwOr, OpcodeAtomicI32RmwXor, OpcodeAtomicI32RmwXchg:
  1602  				if 1<<align > 32/8 {
  1603  					return fmt.Errorf("invalid memory alignment")
  1604  				}
  1605  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1606  					return err
  1607  				}
  1608  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1609  					return err
  1610  				}
  1611  				valueTypeStack.push(ValueTypeI32)
  1612  			case OpcodeAtomicI32Rmw8AddU, OpcodeAtomicI32Rmw8SubU, OpcodeAtomicI32Rmw8AndU, OpcodeAtomicI32Rmw8OrU, OpcodeAtomicI32Rmw8XorU, OpcodeAtomicI32Rmw8XchgU:
  1613  				if 1<<align > 1 {
  1614  					return fmt.Errorf("invalid memory alignment")
  1615  				}
  1616  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1617  					return err
  1618  				}
  1619  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1620  					return err
  1621  				}
  1622  				valueTypeStack.push(ValueTypeI32)
  1623  			case OpcodeAtomicI32Rmw16AddU, OpcodeAtomicI32Rmw16SubU, OpcodeAtomicI32Rmw16AndU, OpcodeAtomicI32Rmw16OrU, OpcodeAtomicI32Rmw16XorU, OpcodeAtomicI32Rmw16XchgU:
  1624  				if 1<<align > 16/8 {
  1625  					return fmt.Errorf("invalid memory alignment")
  1626  				}
  1627  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1628  					return err
  1629  				}
  1630  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1631  					return err
  1632  				}
  1633  				valueTypeStack.push(ValueTypeI32)
  1634  			case OpcodeAtomicI64RmwAdd, OpcodeAtomicI64RmwSub, OpcodeAtomicI64RmwAnd, OpcodeAtomicI64RmwOr, OpcodeAtomicI64RmwXor, OpcodeAtomicI64RmwXchg:
  1635  				if 1<<align > 64/8 {
  1636  					return fmt.Errorf("invalid memory alignment")
  1637  				}
  1638  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1639  					return err
  1640  				}
  1641  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1642  					return err
  1643  				}
  1644  				valueTypeStack.push(ValueTypeI64)
  1645  			case OpcodeAtomicI64Rmw8AddU, OpcodeAtomicI64Rmw8SubU, OpcodeAtomicI64Rmw8AndU, OpcodeAtomicI64Rmw8OrU, OpcodeAtomicI64Rmw8XorU, OpcodeAtomicI64Rmw8XchgU:
  1646  				if 1<<align > 1 {
  1647  					return fmt.Errorf("invalid memory alignment")
  1648  				}
  1649  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1650  					return err
  1651  				}
  1652  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1653  					return err
  1654  				}
  1655  				valueTypeStack.push(ValueTypeI64)
  1656  			case OpcodeAtomicI64Rmw16AddU, OpcodeAtomicI64Rmw16SubU, OpcodeAtomicI64Rmw16AndU, OpcodeAtomicI64Rmw16OrU, OpcodeAtomicI64Rmw16XorU, OpcodeAtomicI64Rmw16XchgU:
  1657  				if 1<<align > 16/8 {
  1658  					return fmt.Errorf("invalid memory alignment")
  1659  				}
  1660  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1661  					return err
  1662  				}
  1663  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1664  					return err
  1665  				}
  1666  				valueTypeStack.push(ValueTypeI64)
  1667  			case OpcodeAtomicI64Rmw32AddU, OpcodeAtomicI64Rmw32SubU, OpcodeAtomicI64Rmw32AndU, OpcodeAtomicI64Rmw32OrU, OpcodeAtomicI64Rmw32XorU, OpcodeAtomicI64Rmw32XchgU:
  1668  				if 1<<align > 32/8 {
  1669  					return fmt.Errorf("invalid memory alignment")
  1670  				}
  1671  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1672  					return err
  1673  				}
  1674  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1675  					return err
  1676  				}
  1677  				valueTypeStack.push(ValueTypeI64)
  1678  			case OpcodeAtomicI32RmwCmpxchg:
  1679  				if 1<<align > 32/8 {
  1680  					return fmt.Errorf("invalid memory alignment")
  1681  				}
  1682  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1683  					return err
  1684  				}
  1685  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1686  					return err
  1687  				}
  1688  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1689  					return err
  1690  				}
  1691  				valueTypeStack.push(ValueTypeI32)
  1692  			case OpcodeAtomicI32Rmw8CmpxchgU:
  1693  				if 1<<align > 1 {
  1694  					return fmt.Errorf("invalid memory alignment")
  1695  				}
  1696  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1697  					return err
  1698  				}
  1699  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1700  					return err
  1701  				}
  1702  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1703  					return err
  1704  				}
  1705  				valueTypeStack.push(ValueTypeI32)
  1706  			case OpcodeAtomicI32Rmw16CmpxchgU:
  1707  				if 1<<align > 16/8 {
  1708  					return fmt.Errorf("invalid memory alignment")
  1709  				}
  1710  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1711  					return err
  1712  				}
  1713  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1714  					return err
  1715  				}
  1716  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1717  					return err
  1718  				}
  1719  				valueTypeStack.push(ValueTypeI32)
  1720  			case OpcodeAtomicI64RmwCmpxchg:
  1721  				if 1<<align > 64/8 {
  1722  					return fmt.Errorf("invalid memory alignment")
  1723  				}
  1724  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1725  					return err
  1726  				}
  1727  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1728  					return err
  1729  				}
  1730  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1731  					return err
  1732  				}
  1733  				valueTypeStack.push(ValueTypeI64)
  1734  			case OpcodeAtomicI64Rmw8CmpxchgU:
  1735  				if 1<<align > 1 {
  1736  					return fmt.Errorf("invalid memory alignment")
  1737  				}
  1738  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1739  					return err
  1740  				}
  1741  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1742  					return err
  1743  				}
  1744  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1745  					return err
  1746  				}
  1747  				valueTypeStack.push(ValueTypeI64)
  1748  			case OpcodeAtomicI64Rmw16CmpxchgU:
  1749  				if 1<<align > 16/8 {
  1750  					return fmt.Errorf("invalid memory alignment")
  1751  				}
  1752  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1753  					return err
  1754  				}
  1755  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1756  					return err
  1757  				}
  1758  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1759  					return err
  1760  				}
  1761  				valueTypeStack.push(ValueTypeI64)
  1762  			case OpcodeAtomicI64Rmw32CmpxchgU:
  1763  				if 1<<align > 32/8 {
  1764  					return fmt.Errorf("invalid memory alignment")
  1765  				}
  1766  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1767  					return err
  1768  				}
  1769  				if err := valueTypeStack.popAndVerifyType(ValueTypeI64); err != nil {
  1770  					return err
  1771  				}
  1772  				if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1773  					return err
  1774  				}
  1775  				valueTypeStack.push(ValueTypeI64)
  1776  			default:
  1777  				return fmt.Errorf("invalid atomic opcode: 0x%x", atomicOpcode)
  1778  			}
  1779  		} else if op == OpcodeLoop {
  1780  			br.Reset(body[pc+1:])
  1781  			bt, num, err := DecodeBlockType(m.TypeSection, br, enabledFeatures)
  1782  			if err != nil {
  1783  				return fmt.Errorf("read block: %w", err)
  1784  			}
  1785  			controlBlockStack.push(pc, 0, 0, bt, num, op)
  1786  			if err = valueTypeStack.popParams(op, bt.Params, false); err != nil {
  1787  				return err
  1788  			}
  1789  			// Plus we have to push any block params again.
  1790  			for _, p := range bt.Params {
  1791  				valueTypeStack.push(p)
  1792  			}
  1793  			valueTypeStack.pushStackLimit(len(bt.Params))
  1794  			pc += num
  1795  		} else if op == OpcodeIf {
  1796  			br.Reset(body[pc+1:])
  1797  			bt, num, err := DecodeBlockType(m.TypeSection, br, enabledFeatures)
  1798  			if err != nil {
  1799  				return fmt.Errorf("read block: %w", err)
  1800  			}
  1801  			controlBlockStack.push(pc, 0, 0, bt, num, op)
  1802  			if err = valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1803  				return fmt.Errorf("cannot pop the operand for 'if': %v", err)
  1804  			}
  1805  			if err = valueTypeStack.popParams(op, bt.Params, false); err != nil {
  1806  				return err
  1807  			}
  1808  			// Plus we have to push any block params again.
  1809  			for _, p := range bt.Params {
  1810  				valueTypeStack.push(p)
  1811  			}
  1812  			valueTypeStack.pushStackLimit(len(bt.Params))
  1813  			pc += num
  1814  		} else if op == OpcodeElse {
  1815  			if len(controlBlockStack.stack) == 0 {
  1816  				return fmt.Errorf("redundant Else instruction at %#x", pc)
  1817  			}
  1818  			bl := &controlBlockStack.stack[len(controlBlockStack.stack)-1]
  1819  			bl.elseAt = pc
  1820  			// Check the type soundness of the instructions *before* entering this else Op.
  1821  			if err := valueTypeStack.popResults(OpcodeIf, bl.blockType.Results, true); err != nil {
  1822  				return err
  1823  			}
  1824  			// Before entering instructions inside else, we pop all the values pushed by then block.
  1825  			valueTypeStack.resetAtStackLimit()
  1826  			// Plus we have to push any block params again.
  1827  			for _, p := range bl.blockType.Params {
  1828  				valueTypeStack.push(p)
  1829  			}
  1830  		} else if op == OpcodeEnd {
  1831  			if len(controlBlockStack.stack) == 0 {
  1832  				return fmt.Errorf("redundant End instruction at %#x", pc)
  1833  			}
  1834  			bl := controlBlockStack.pop()
  1835  			bl.endAt = pc
  1836  
  1837  			// OpcodeEnd can end a block or the function itself. Check to see what it is:
  1838  
  1839  			ifMissingElse := bl.op == OpcodeIf && bl.elseAt <= bl.startAt
  1840  			if ifMissingElse {
  1841  				// If this is the end of block without else, the number of block's results and params must be same.
  1842  				// Otherwise, the value stack would result in the inconsistent state at runtime.
  1843  				if !bytes.Equal(bl.blockType.Results, bl.blockType.Params) {
  1844  					return typeCountError(false, OpcodeElseName, bl.blockType.Params, bl.blockType.Results)
  1845  				}
  1846  				// -1 skips else, to handle if block without else properly.
  1847  				bl.elseAt = bl.endAt - 1
  1848  			}
  1849  
  1850  			// Determine the block context
  1851  			ctx := "" // the outer-most block: the function return
  1852  			if bl.op == OpcodeIf && !ifMissingElse && bl.elseAt > 0 {
  1853  				ctx = OpcodeElseName
  1854  			} else if bl.op != 0 {
  1855  				ctx = InstructionName(bl.op)
  1856  			}
  1857  
  1858  			// Check return types match
  1859  			if err := valueTypeStack.requireStackValues(false, ctx, bl.blockType.Results, true); err != nil {
  1860  				return err
  1861  			}
  1862  
  1863  			// Put the result types at the end after resetting at the stack limit
  1864  			// since we might have Any type between the limit and the current top.
  1865  			valueTypeStack.resetAtStackLimit()
  1866  			for _, exp := range bl.blockType.Results {
  1867  				valueTypeStack.push(exp)
  1868  			}
  1869  			// We exit if/loop/block, so reset the constraints on the stack manipulation
  1870  			// on values previously pushed by outer blocks.
  1871  			valueTypeStack.popStackLimit()
  1872  		} else if op == OpcodeReturn {
  1873  			// Same formatting as OpcodeEnd on the outer-most block
  1874  			if err := valueTypeStack.requireStackValues(false, "", functionType.Results, false); err != nil {
  1875  				return err
  1876  			}
  1877  			// return instruction is stack-polymorphic.
  1878  			valueTypeStack.unreachable()
  1879  		} else if op == OpcodeDrop {
  1880  			_, err := valueTypeStack.pop()
  1881  			if err != nil {
  1882  				return fmt.Errorf("invalid drop: %v", err)
  1883  			}
  1884  		} else if op == OpcodeSelect || op == OpcodeTypedSelect {
  1885  			if err := valueTypeStack.popAndVerifyType(ValueTypeI32); err != nil {
  1886  				return fmt.Errorf("type mismatch on 3rd select operand: %v", err)
  1887  			}
  1888  			v1, err := valueTypeStack.pop()
  1889  			if err != nil {
  1890  				return fmt.Errorf("invalid select: %v", err)
  1891  			}
  1892  			v2, err := valueTypeStack.pop()
  1893  			if err != nil {
  1894  				return fmt.Errorf("invalid select: %v", err)
  1895  			}
  1896  
  1897  			if op == OpcodeTypedSelect {
  1898  				if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
  1899  					return fmt.Errorf("%s is invalid as %w", InstructionName(op), err)
  1900  				}
  1901  				pc++
  1902  				if numTypeImmeidates := body[pc]; numTypeImmeidates != 1 {
  1903  					return fmt.Errorf("too many type immediates for %s", InstructionName(op))
  1904  				}
  1905  				pc++
  1906  				tp := body[pc]
  1907  				if tp != ValueTypeI32 && tp != ValueTypeI64 && tp != ValueTypeF32 && tp != ValueTypeF64 &&
  1908  					tp != api.ValueTypeExternref && tp != ValueTypeFuncref && tp != ValueTypeV128 {
  1909  					return fmt.Errorf("invalid type %s for %s", ValueTypeName(tp), OpcodeTypedSelectName)
  1910  				}
  1911  			} else if isReferenceValueType(v1) || isReferenceValueType(v2) {
  1912  				return fmt.Errorf("reference types cannot be used for non typed select instruction")
  1913  			}
  1914  
  1915  			if v1 != v2 && v1 != valueTypeUnknown && v2 != valueTypeUnknown {
  1916  				return fmt.Errorf("type mismatch on 1st and 2nd select operands")
  1917  			}
  1918  			if v1 == valueTypeUnknown {
  1919  				valueTypeStack.push(v2)
  1920  			} else {
  1921  				valueTypeStack.push(v1)
  1922  			}
  1923  		} else if op == OpcodeUnreachable {
  1924  			// unreachable instruction is stack-polymorphic.
  1925  			valueTypeStack.unreachable()
  1926  		} else if op == OpcodeNop {
  1927  		} else {
  1928  			return fmt.Errorf("invalid instruction 0x%x", op)
  1929  		}
  1930  	}
  1931  
  1932  	if len(controlBlockStack.stack) > 0 {
  1933  		return fmt.Errorf("ill-nested block exists")
  1934  	}
  1935  	if valueTypeStack.maximumStackPointer > maxStackValues {
  1936  		return fmt.Errorf("function may have %d stack values, which exceeds limit %d", valueTypeStack.maximumStackPointer, maxStackValues)
  1937  	}
  1938  	return nil
  1939  }
  1940  
  1941  var vecExtractLanes = [...]struct {
  1942  	laneCeil   byte
  1943  	resultType ValueType
  1944  }{
  1945  	OpcodeVecI8x16ExtractLaneS: {laneCeil: 16, resultType: ValueTypeI32},
  1946  	OpcodeVecI8x16ExtractLaneU: {laneCeil: 16, resultType: ValueTypeI32},
  1947  	OpcodeVecI16x8ExtractLaneS: {laneCeil: 8, resultType: ValueTypeI32},
  1948  	OpcodeVecI16x8ExtractLaneU: {laneCeil: 8, resultType: ValueTypeI32},
  1949  	OpcodeVecI32x4ExtractLane:  {laneCeil: 4, resultType: ValueTypeI32},
  1950  	OpcodeVecI64x2ExtractLane:  {laneCeil: 2, resultType: ValueTypeI64},
  1951  	OpcodeVecF32x4ExtractLane:  {laneCeil: 4, resultType: ValueTypeF32},
  1952  	OpcodeVecF64x2ExtractLane:  {laneCeil: 2, resultType: ValueTypeF64},
  1953  }
  1954  
  1955  var vecReplaceLanes = [...]struct {
  1956  	laneCeil  byte
  1957  	paramType ValueType
  1958  }{
  1959  	OpcodeVecI8x16ReplaceLane: {laneCeil: 16, paramType: ValueTypeI32},
  1960  	OpcodeVecI16x8ReplaceLane: {laneCeil: 8, paramType: ValueTypeI32},
  1961  	OpcodeVecI32x4ReplaceLane: {laneCeil: 4, paramType: ValueTypeI32},
  1962  	OpcodeVecI64x2ReplaceLane: {laneCeil: 2, paramType: ValueTypeI64},
  1963  	OpcodeVecF32x4ReplaceLane: {laneCeil: 4, paramType: ValueTypeF32},
  1964  	OpcodeVecF64x2ReplaceLane: {laneCeil: 2, paramType: ValueTypeF64},
  1965  }
  1966  
  1967  var vecStoreLanes = [...]struct {
  1968  	alignMax uint32
  1969  	laneCeil byte
  1970  }{
  1971  	OpcodeVecV128Store64Lane: {alignMax: 64 / 8, laneCeil: 128 / 64},
  1972  	OpcodeVecV128Store32Lane: {alignMax: 32 / 8, laneCeil: 128 / 32},
  1973  	OpcodeVecV128Store16Lane: {alignMax: 16 / 8, laneCeil: 128 / 16},
  1974  	OpcodeVecV128Store8Lane:  {alignMax: 1, laneCeil: 128 / 8},
  1975  }
  1976  
  1977  var vecLoadLanes = [...]struct {
  1978  	alignMax uint32
  1979  	laneCeil byte
  1980  }{
  1981  	OpcodeVecV128Load64Lane: {alignMax: 64 / 8, laneCeil: 128 / 64},
  1982  	OpcodeVecV128Load32Lane: {alignMax: 32 / 8, laneCeil: 128 / 32},
  1983  	OpcodeVecV128Load16Lane: {alignMax: 16 / 8, laneCeil: 128 / 16},
  1984  	OpcodeVecV128Load8Lane:  {alignMax: 1, laneCeil: 128 / 8},
  1985  }
  1986  
  1987  var vecSplatValueTypes = [...]ValueType{
  1988  	OpcodeVecI8x16Splat: ValueTypeI32,
  1989  	OpcodeVecI16x8Splat: ValueTypeI32,
  1990  	OpcodeVecI32x4Splat: ValueTypeI32,
  1991  	OpcodeVecI64x2Splat: ValueTypeI64,
  1992  	OpcodeVecF32x4Splat: ValueTypeF32,
  1993  	OpcodeVecF64x2Splat: ValueTypeF64,
  1994  }
  1995  
  1996  type stacks struct {
  1997  	vs valueTypeStack
  1998  	cs controlBlockStack
  1999  }
  2000  
  2001  func (sts *stacks) reset(functionType *FunctionType) {
  2002  	// Reset valueStack for reuse.
  2003  	sts.vs.stack = sts.vs.stack[:0]
  2004  	sts.vs.stackLimits = sts.vs.stackLimits[:0]
  2005  	sts.vs.maximumStackPointer = 0
  2006  	sts.cs.stack = sts.cs.stack[:0]
  2007  	sts.cs.stack = append(sts.cs.stack, controlBlock{blockType: functionType})
  2008  }
  2009  
  2010  type controlBlockStack struct {
  2011  	stack []controlBlock
  2012  }
  2013  
  2014  func (s *controlBlockStack) pop() *controlBlock {
  2015  	tail := len(s.stack) - 1
  2016  	ret := &s.stack[tail]
  2017  	s.stack = s.stack[:tail]
  2018  	return ret
  2019  }
  2020  
  2021  func (s *controlBlockStack) push(startAt, elseAt, endAt uint64, blockType *FunctionType, blockTypeBytes uint64, op Opcode) {
  2022  	s.stack = append(s.stack, controlBlock{
  2023  		startAt:        startAt,
  2024  		elseAt:         elseAt,
  2025  		endAt:          endAt,
  2026  		blockType:      blockType,
  2027  		blockTypeBytes: blockTypeBytes,
  2028  		op:             op,
  2029  	})
  2030  }
  2031  
  2032  type valueTypeStack struct {
  2033  	stack               []ValueType
  2034  	stackLimits         []int
  2035  	maximumStackPointer int
  2036  	// requireStackValuesTmp is used in requireStackValues function to reduce the allocation.
  2037  	requireStackValuesTmp []ValueType
  2038  }
  2039  
  2040  // Only used in the analyzeFunction below.
  2041  const valueTypeUnknown = ValueType(0xFF)
  2042  
  2043  func (s *valueTypeStack) tryPop() (vt ValueType, limit int, ok bool) {
  2044  	if len(s.stackLimits) > 0 {
  2045  		limit = s.stackLimits[len(s.stackLimits)-1]
  2046  	}
  2047  	stackLen := len(s.stack)
  2048  	if stackLen <= limit {
  2049  		return
  2050  	} else if stackLen == limit+1 && s.stack[limit] == valueTypeUnknown {
  2051  		vt = valueTypeUnknown
  2052  		ok = true
  2053  		return
  2054  	} else {
  2055  		vt = s.stack[stackLen-1]
  2056  		s.stack = s.stack[:stackLen-1]
  2057  		ok = true
  2058  		return
  2059  	}
  2060  }
  2061  
  2062  func (s *valueTypeStack) pop() (ValueType, error) {
  2063  	if vt, limit, ok := s.tryPop(); ok {
  2064  		return vt, nil
  2065  	} else {
  2066  		return 0, fmt.Errorf("invalid operation: trying to pop at %d with limit %d", len(s.stack), limit)
  2067  	}
  2068  }
  2069  
  2070  // popAndVerifyType returns an error if the stack value is unexpected.
  2071  func (s *valueTypeStack) popAndVerifyType(expected ValueType) error {
  2072  	have, _, ok := s.tryPop()
  2073  	if !ok {
  2074  		return fmt.Errorf("%s missing", ValueTypeName(expected))
  2075  	}
  2076  	if have != expected && have != valueTypeUnknown && expected != valueTypeUnknown {
  2077  		return fmt.Errorf("type mismatch: expected %s, but was %s", ValueTypeName(expected), ValueTypeName(have))
  2078  	}
  2079  	return nil
  2080  }
  2081  
  2082  func (s *valueTypeStack) push(v ValueType) {
  2083  	s.stack = append(s.stack, v)
  2084  	if sp := len(s.stack); sp > s.maximumStackPointer {
  2085  		s.maximumStackPointer = sp
  2086  	}
  2087  }
  2088  
  2089  func (s *valueTypeStack) unreachable() {
  2090  	s.resetAtStackLimit()
  2091  	s.stack = append(s.stack, valueTypeUnknown)
  2092  }
  2093  
  2094  func (s *valueTypeStack) resetAtStackLimit() {
  2095  	if len(s.stackLimits) != 0 {
  2096  		s.stack = s.stack[:s.stackLimits[len(s.stackLimits)-1]]
  2097  	} else {
  2098  		s.stack = s.stack[:0]
  2099  	}
  2100  }
  2101  
  2102  func (s *valueTypeStack) popStackLimit() {
  2103  	if len(s.stackLimits) != 0 {
  2104  		s.stackLimits = s.stackLimits[:len(s.stackLimits)-1]
  2105  	}
  2106  }
  2107  
  2108  // pushStackLimit pushes the control frame's bottom of the stack.
  2109  func (s *valueTypeStack) pushStackLimit(params int) {
  2110  	limit := len(s.stack) - params
  2111  	s.stackLimits = append(s.stackLimits, limit)
  2112  }
  2113  
  2114  func (s *valueTypeStack) popParams(oc Opcode, want []ValueType, checkAboveLimit bool) error {
  2115  	return s.requireStackValues(true, InstructionName(oc), want, checkAboveLimit)
  2116  }
  2117  
  2118  func (s *valueTypeStack) popResults(oc Opcode, want []ValueType, checkAboveLimit bool) error {
  2119  	return s.requireStackValues(false, InstructionName(oc), want, checkAboveLimit)
  2120  }
  2121  
  2122  func (s *valueTypeStack) requireStackValues(
  2123  	isParam bool,
  2124  	context string,
  2125  	want []ValueType,
  2126  	checkAboveLimit bool,
  2127  ) error {
  2128  	limit := 0
  2129  	if len(s.stackLimits) > 0 {
  2130  		limit = s.stackLimits[len(s.stackLimits)-1]
  2131  	}
  2132  	// Iterate backwards as we are comparing the desired slice against stack value types.
  2133  	countWanted := len(want)
  2134  
  2135  	// First, check if there are enough values on the stack.
  2136  	s.requireStackValuesTmp = s.requireStackValuesTmp[:0]
  2137  	for i := countWanted - 1; i >= 0; i-- {
  2138  		popped, _, ok := s.tryPop()
  2139  		if !ok {
  2140  			if len(s.requireStackValuesTmp) > len(want) {
  2141  				return typeCountError(isParam, context, s.requireStackValuesTmp, want)
  2142  			}
  2143  			return typeCountError(isParam, context, s.requireStackValuesTmp, want)
  2144  		}
  2145  		s.requireStackValuesTmp = append(s.requireStackValuesTmp, popped)
  2146  	}
  2147  
  2148  	// Now, check if there are too many values.
  2149  	if checkAboveLimit {
  2150  		if !(limit == len(s.stack) || (limit+1 == len(s.stack) && s.stack[limit] == valueTypeUnknown)) {
  2151  			return typeCountError(isParam, context, append(s.stack, want...), want)
  2152  		}
  2153  	}
  2154  
  2155  	// Finally, check the types of the values:
  2156  	for i, v := range s.requireStackValuesTmp {
  2157  		nextWant := want[countWanted-i-1] // have is in reverse order (stack)
  2158  		if v != nextWant && v != valueTypeUnknown && nextWant != valueTypeUnknown {
  2159  			return typeMismatchError(isParam, context, v, nextWant, i)
  2160  		}
  2161  	}
  2162  	return nil
  2163  }
  2164  
  2165  // typeMismatchError returns an error similar to go compiler's error on type mismatch.
  2166  func typeMismatchError(isParam bool, context string, have ValueType, want ValueType, i int) error {
  2167  	var ret strings.Builder
  2168  	ret.WriteString("cannot use ")
  2169  	ret.WriteString(ValueTypeName(have))
  2170  	if context != "" {
  2171  		ret.WriteString(" in ")
  2172  		ret.WriteString(context)
  2173  		ret.WriteString(" block")
  2174  	}
  2175  	if isParam {
  2176  		ret.WriteString(" as param")
  2177  	} else {
  2178  		ret.WriteString(" as result")
  2179  	}
  2180  	ret.WriteString("[")
  2181  	ret.WriteString(strconv.Itoa(i))
  2182  	ret.WriteString("] type ")
  2183  	ret.WriteString(ValueTypeName(want))
  2184  	return errors.New(ret.String())
  2185  }
  2186  
  2187  // typeCountError returns an error similar to go compiler's error on type count mismatch.
  2188  func typeCountError(isParam bool, context string, have []ValueType, want []ValueType) error {
  2189  	var ret strings.Builder
  2190  	if len(have) > len(want) {
  2191  		ret.WriteString("too many ")
  2192  	} else {
  2193  		ret.WriteString("not enough ")
  2194  	}
  2195  	if isParam {
  2196  		ret.WriteString("params")
  2197  	} else {
  2198  		ret.WriteString("results")
  2199  	}
  2200  	if context != "" {
  2201  		if isParam {
  2202  			ret.WriteString(" for ")
  2203  		} else {
  2204  			ret.WriteString(" in ")
  2205  		}
  2206  		ret.WriteString(context)
  2207  		ret.WriteString(" block")
  2208  	}
  2209  	ret.WriteString("\n\thave (")
  2210  	writeValueTypes(have, &ret)
  2211  	ret.WriteString(")\n\twant (")
  2212  	writeValueTypes(want, &ret)
  2213  	ret.WriteByte(')')
  2214  	return errors.New(ret.String())
  2215  }
  2216  
  2217  func writeValueTypes(vts []ValueType, ret *strings.Builder) {
  2218  	switch len(vts) {
  2219  	case 0:
  2220  	case 1:
  2221  		ret.WriteString(ValueTypeName(vts[0]))
  2222  	default:
  2223  		ret.WriteString(ValueTypeName(vts[0]))
  2224  		for _, vt := range vts[1:] {
  2225  			ret.WriteString(", ")
  2226  			ret.WriteString(ValueTypeName(vt))
  2227  		}
  2228  	}
  2229  }
  2230  
  2231  func (s *valueTypeStack) String() string {
  2232  	var typeStrs, limits []string
  2233  	for _, v := range s.stack {
  2234  		var str string
  2235  		if v == valueTypeUnknown {
  2236  			str = "unknown"
  2237  		} else {
  2238  			str = ValueTypeName(v)
  2239  		}
  2240  		typeStrs = append(typeStrs, str)
  2241  	}
  2242  	for _, d := range s.stackLimits {
  2243  		limits = append(limits, fmt.Sprintf("%d", d))
  2244  	}
  2245  	return fmt.Sprintf("{stack: [%s], limits: [%s]}",
  2246  		strings.Join(typeStrs, ", "), strings.Join(limits, ","))
  2247  }
  2248  
  2249  type controlBlock struct {
  2250  	startAt, elseAt, endAt uint64
  2251  	blockType              *FunctionType
  2252  	blockTypeBytes         uint64
  2253  	// op is zero when the outermost block
  2254  	op Opcode
  2255  }
  2256  
  2257  // DecodeBlockType decodes the type index from a positive 33-bit signed integer. Negative numbers indicate up to one
  2258  // WebAssembly 1.0 (20191205) compatible result type. Positive numbers are decoded when `enabledFeatures` include
  2259  // CoreFeatureMultiValue and include an index in the Module.TypeSection.
  2260  //
  2261  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-blocktype
  2262  // See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/multi-value/Overview.md
  2263  func DecodeBlockType(types []FunctionType, r *bytes.Reader, enabledFeatures api.CoreFeatures) (*FunctionType, uint64, error) {
  2264  	raw, num, err := leb128.DecodeInt33AsInt64(r)
  2265  	if err != nil {
  2266  		return nil, 0, fmt.Errorf("decode int33: %w", err)
  2267  	}
  2268  
  2269  	var ret *FunctionType
  2270  	switch raw {
  2271  	case -64: // 0x40 in original byte = nil
  2272  		ret = blockType_v_v
  2273  	case -1: // 0x7f in original byte = i32
  2274  		ret = blockType_v_i32
  2275  	case -2: // 0x7e in original byte = i64
  2276  		ret = blockType_v_i64
  2277  	case -3: // 0x7d in original byte = f32
  2278  		ret = blockType_v_f32
  2279  	case -4: // 0x7c in original byte = f64
  2280  		ret = blockType_v_f64
  2281  	case -5: // 0x7b in original byte = v128
  2282  		ret = blockType_v_v128
  2283  	case -16: // 0x70 in original byte = funcref
  2284  		ret = blockType_v_funcref
  2285  	case -17: // 0x6f in original byte = externref
  2286  		ret = blockType_v_externref
  2287  	default:
  2288  		if err = enabledFeatures.RequireEnabled(api.CoreFeatureMultiValue); err != nil {
  2289  			return nil, num, fmt.Errorf("block with function type return invalid as %v", err)
  2290  		}
  2291  		if raw < 0 || (raw >= int64(len(types))) {
  2292  			return nil, 0, fmt.Errorf("type index out of range: %d", raw)
  2293  		}
  2294  		ret = &types[raw]
  2295  	}
  2296  	return ret, num, err
  2297  }
  2298  
  2299  // These block types are defined as globals in order to avoid allocations in DecodeBlockType.
  2300  var (
  2301  	blockType_v_v         = &FunctionType{}
  2302  	blockType_v_i32       = &FunctionType{Results: []ValueType{ValueTypeI32}, ResultNumInUint64: 1}
  2303  	blockType_v_i64       = &FunctionType{Results: []ValueType{ValueTypeI64}, ResultNumInUint64: 1}
  2304  	blockType_v_f32       = &FunctionType{Results: []ValueType{ValueTypeF32}, ResultNumInUint64: 1}
  2305  	blockType_v_f64       = &FunctionType{Results: []ValueType{ValueTypeF64}, ResultNumInUint64: 1}
  2306  	blockType_v_v128      = &FunctionType{Results: []ValueType{ValueTypeV128}, ResultNumInUint64: 2}
  2307  	blockType_v_funcref   = &FunctionType{Results: []ValueType{ValueTypeFuncref}, ResultNumInUint64: 1}
  2308  	blockType_v_externref = &FunctionType{Results: []ValueType{ValueTypeExternref}, ResultNumInUint64: 1}
  2309  )
  2310  
  2311  // SplitCallStack returns the input stack resliced to the count of params and
  2312  // results, or errors if it isn't long enough for either.
  2313  func SplitCallStack(ft *FunctionType, stack []uint64) (params []uint64, results []uint64, err error) {
  2314  	stackLen := len(stack)
  2315  	if n := ft.ParamNumInUint64; n > stackLen {
  2316  		return nil, nil, fmt.Errorf("need %d params, but stack size is %d", n, stackLen)
  2317  	} else if n > 0 {
  2318  		params = stack[:n]
  2319  	}
  2320  	if n := ft.ResultNumInUint64; n > stackLen {
  2321  		return nil, nil, fmt.Errorf("need %d results, but stack size is %d", n, stackLen)
  2322  	} else if n > 0 {
  2323  		results = stack[:n]
  2324  	}
  2325  	return
  2326  }