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

     1  package wasm
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/bananabytelabs/wazero/api"
     9  	"github.com/bananabytelabs/wazero/internal/leb128"
    10  	"github.com/bananabytelabs/wazero/internal/testing/require"
    11  )
    12  
    13  func TestModule_ValidateFunction_validateFunctionWithMaxStackValues(t *testing.T) {
    14  	const max = 100
    15  	const valuesNum = max + 1
    16  
    17  	// Compile a function which has max+1 const instructions.
    18  	var body []byte
    19  	for i := 0; i < valuesNum; i++ {
    20  		body = append(body, OpcodeI32Const, 1)
    21  	}
    22  
    23  	// Drop all the consts so that if the max is higher, this function body would be sound.
    24  	for i := 0; i < valuesNum; i++ {
    25  		body = append(body, OpcodeDrop)
    26  	}
    27  
    28  	// Plus all functions must end with End opcode.
    29  	body = append(body, OpcodeEnd)
    30  
    31  	m := &Module{
    32  		TypeSection:     []FunctionType{v_v},
    33  		FunctionSection: []Index{0},
    34  		CodeSection:     []Code{{Body: body}},
    35  	}
    36  
    37  	t.Run("not exceed", func(t *testing.T) {
    38  		err := m.validateFunctionWithMaxStackValues(&stacks{}, api.CoreFeaturesV1,
    39  			0, []Index{0}, nil, nil, nil, max+1, nil, bytes.NewReader(nil))
    40  		require.NoError(t, err)
    41  	})
    42  	t.Run("exceed", func(t *testing.T) {
    43  		err := m.validateFunctionWithMaxStackValues(&stacks{}, api.CoreFeaturesV1,
    44  			0, []Index{0}, nil, nil, nil, max, nil, bytes.NewReader(nil))
    45  		require.Error(t, err)
    46  		expMsg := fmt.Sprintf("function may have %d stack values, which exceeds limit %d", valuesNum, max)
    47  		require.Equal(t, expMsg, err.Error())
    48  	})
    49  }
    50  
    51  func TestModule_ValidateFunction_SignExtensionOps(t *testing.T) {
    52  	tests := []struct {
    53  		input                Opcode
    54  		expectedErrOnDisable string
    55  	}{
    56  		{
    57  			input:                OpcodeI32Extend8S,
    58  			expectedErrOnDisable: "i32.extend8_s invalid as feature \"sign-extension-ops\" is disabled",
    59  		},
    60  		{
    61  			input:                OpcodeI32Extend16S,
    62  			expectedErrOnDisable: "i32.extend16_s invalid as feature \"sign-extension-ops\" is disabled",
    63  		},
    64  		{
    65  			input:                OpcodeI64Extend8S,
    66  			expectedErrOnDisable: "i64.extend8_s invalid as feature \"sign-extension-ops\" is disabled",
    67  		},
    68  		{
    69  			input:                OpcodeI64Extend16S,
    70  			expectedErrOnDisable: "i64.extend16_s invalid as feature \"sign-extension-ops\" is disabled",
    71  		},
    72  		{
    73  			input:                OpcodeI64Extend32S,
    74  			expectedErrOnDisable: "i64.extend32_s invalid as feature \"sign-extension-ops\" is disabled",
    75  		},
    76  	}
    77  
    78  	for _, tt := range tests {
    79  		tc := tt
    80  		t.Run(InstructionName(tc.input), func(t *testing.T) {
    81  			t.Run("disabled", func(t *testing.T) {
    82  				m := &Module{
    83  					TypeSection:     []FunctionType{v_v},
    84  					FunctionSection: []Index{0},
    85  					CodeSection:     []Code{{Body: []byte{tc.input}}},
    86  				}
    87  				err := m.validateFunction(&stacks{}, api.CoreFeaturesV1,
    88  					0, []Index{0}, nil, nil, nil, nil,
    89  					bytes.NewReader(nil))
    90  				require.EqualError(t, err, tc.expectedErrOnDisable)
    91  			})
    92  			t.Run("enabled", func(t *testing.T) {
    93  				is32bit := tc.input == OpcodeI32Extend8S || tc.input == OpcodeI32Extend16S
    94  				var body []byte
    95  				if is32bit {
    96  					body = append(body, OpcodeI32Const)
    97  				} else {
    98  					body = append(body, OpcodeI64Const)
    99  				}
   100  				body = append(body, tc.input, 123, OpcodeDrop, OpcodeEnd)
   101  				m := &Module{
   102  					TypeSection:     []FunctionType{v_v},
   103  					FunctionSection: []Index{0},
   104  					CodeSection:     []Code{{Body: body}},
   105  				}
   106  				err := m.validateFunction(&stacks{}, api.CoreFeatureSignExtensionOps,
   107  					0, []Index{0}, nil, nil, nil,
   108  					nil, bytes.NewReader(nil))
   109  				require.NoError(t, err)
   110  			})
   111  		})
   112  	}
   113  }
   114  
   115  func TestModule_ValidateFunction_NonTrappingFloatToIntConversion(t *testing.T) {
   116  	tests := []struct {
   117  		input                Opcode
   118  		expectedErrOnDisable string
   119  	}{
   120  		{
   121  			input:                OpcodeMiscI32TruncSatF32S,
   122  			expectedErrOnDisable: "i32.trunc_sat_f32_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   123  		},
   124  		{
   125  			input:                OpcodeMiscI32TruncSatF32U,
   126  			expectedErrOnDisable: "i32.trunc_sat_f32_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   127  		},
   128  		{
   129  			input:                OpcodeMiscI32TruncSatF64S,
   130  			expectedErrOnDisable: "i32.trunc_sat_f64_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   131  		},
   132  		{
   133  			input:                OpcodeMiscI32TruncSatF64U,
   134  			expectedErrOnDisable: "i32.trunc_sat_f64_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   135  		},
   136  		{
   137  			input:                OpcodeMiscI64TruncSatF32S,
   138  			expectedErrOnDisable: "i64.trunc_sat_f32_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   139  		},
   140  		{
   141  			input:                OpcodeMiscI64TruncSatF32U,
   142  			expectedErrOnDisable: "i64.trunc_sat_f32_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   143  		},
   144  		{
   145  			input:                OpcodeMiscI64TruncSatF64S,
   146  			expectedErrOnDisable: "i64.trunc_sat_f64_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   147  		},
   148  		{
   149  			input:                OpcodeMiscI64TruncSatF64U,
   150  			expectedErrOnDisable: "i64.trunc_sat_f64_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   151  		},
   152  	}
   153  
   154  	for _, tt := range tests {
   155  		tc := tt
   156  		t.Run(InstructionName(tc.input), func(t *testing.T) {
   157  			t.Run("disabled", func(t *testing.T) {
   158  				m := &Module{
   159  					TypeSection:     []FunctionType{v_v},
   160  					FunctionSection: []Index{0},
   161  					CodeSection:     []Code{{Body: []byte{OpcodeMiscPrefix, tc.input}}},
   162  				}
   163  				err := m.validateFunction(&stacks{}, api.CoreFeaturesV1,
   164  					0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
   165  				require.EqualError(t, err, tc.expectedErrOnDisable)
   166  			})
   167  			t.Run("enabled", func(t *testing.T) {
   168  				var body []byte
   169  				switch tc.input {
   170  				case OpcodeMiscI32TruncSatF32S, OpcodeMiscI32TruncSatF32U, OpcodeMiscI64TruncSatF32S, OpcodeMiscI64TruncSatF32U:
   171  					body = []byte{OpcodeF32Const, 1, 2, 3, 4}
   172  				case OpcodeMiscI32TruncSatF64S, OpcodeMiscI32TruncSatF64U, OpcodeMiscI64TruncSatF64S, OpcodeMiscI64TruncSatF64U:
   173  					body = []byte{OpcodeF64Const, 1, 2, 3, 4, 5, 6, 7, 8}
   174  				}
   175  				body = append(body, OpcodeMiscPrefix, tc.input, OpcodeDrop, OpcodeEnd)
   176  
   177  				m := &Module{
   178  					TypeSection:     []FunctionType{v_v},
   179  					FunctionSection: []Index{0},
   180  					CodeSection:     []Code{{Body: body}},
   181  				}
   182  				err := m.validateFunction(&stacks{}, api.CoreFeatureNonTrappingFloatToIntConversion,
   183  					0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
   184  				require.NoError(t, err)
   185  			})
   186  		})
   187  	}
   188  }
   189  
   190  // TestModule_ValidateFunction_MultiValue only tests what can't yet be detected during compilation. These examples are
   191  // from test/core/if.wast from the commit that added "multi-value" support.
   192  //
   193  // See https://github.com/WebAssembly/spec/commit/484180ba3d9d7638ba1cb400b699ffede796927c
   194  func TestModule_ValidateFunction_MultiValue(t *testing.T) {
   195  	tests := []struct {
   196  		name                 string
   197  		module               *Module
   198  		expectedErrOnDisable string
   199  	}{
   200  		{
   201  			name: "block with function type",
   202  			module: &Module{
   203  				TypeSection:     []FunctionType{v_f64f64},
   204  				FunctionSection: []Index{0},
   205  				CodeSection: []Code{{Body: []byte{
   206  					OpcodeBlock, 0, // (block (result f64 f64)
   207  					OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x10, 0x40, // (f64.const 4)
   208  					OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x14, 0x40, // (f64.const 5)
   209  					OpcodeBr, 0,
   210  					OpcodeF64Add,
   211  					OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x18, 0x40, // (f64.const 6)
   212  					OpcodeEnd,
   213  					OpcodeEnd,
   214  				}}},
   215  			},
   216  			expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled",
   217  		},
   218  		{
   219  			name: "if with function type", // a.k.a. "param"
   220  			module: &Module{
   221  				TypeSection:     []FunctionType{i32_i32}, // (func (param i32) (result i32)
   222  				FunctionSection: []Index{0},
   223  				CodeSection: []Code{{Body: []byte{
   224  					OpcodeI32Const, 1, // (i32.const 1)
   225  					OpcodeLocalGet, 0, OpcodeIf, 0, // (if (param i32) (result i32) (local.get 0)
   226  					OpcodeI32Const, 2, OpcodeI32Add, // (then (i32.const 2) (i32.add))
   227  					OpcodeElse, OpcodeI32Const, 0x7e, OpcodeI32Add, // (else (i32.const -2) (i32.add))
   228  					OpcodeEnd, // )
   229  					OpcodeEnd, // )
   230  				}}},
   231  			},
   232  			expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled",
   233  		},
   234  		{
   235  			name: "if with function type - br", // a.k.a. "params-break"
   236  			module: &Module{
   237  				TypeSection: []FunctionType{
   238  					i32_i32,    // (func (param i32) (result i32)
   239  					i32i32_i32, // (if (param i32 i32) (result i32)
   240  				},
   241  				FunctionSection: []Index{0},
   242  				CodeSection: []Code{{Body: []byte{
   243  					OpcodeI32Const, 1, // (i32.const 1)
   244  					OpcodeI32Const, 2, // (i32.const 2)
   245  					OpcodeLocalGet, 0, OpcodeIf, 1, // (if (param i32) (result i32) (local.get 0)
   246  					OpcodeI32Add, OpcodeBr, 0, // (then (i32.add) (br 0))
   247  					OpcodeElse, OpcodeI32Sub, OpcodeBr, 0, // (else (i32.sub) (br 0))
   248  					OpcodeEnd, // )
   249  					OpcodeEnd, // )
   250  				}}},
   251  			},
   252  			expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled",
   253  		},
   254  	}
   255  
   256  	for _, tt := range tests {
   257  		tc := tt
   258  		t.Run(tc.name, func(t *testing.T) {
   259  			t.Run("disabled", func(t *testing.T) {
   260  				err := tc.module.validateFunction(&stacks{}, api.CoreFeaturesV1,
   261  					0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
   262  				require.EqualError(t, err, tc.expectedErrOnDisable)
   263  			})
   264  			t.Run("enabled", func(t *testing.T) {
   265  				err := tc.module.validateFunction(&stacks{}, api.CoreFeatureMultiValue,
   266  					0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
   267  				require.NoError(t, err)
   268  			})
   269  		})
   270  	}
   271  }
   272  
   273  func TestModule_ValidateFunction_BulkMemoryOperations(t *testing.T) {
   274  	t.Run("ok", func(t *testing.T) {
   275  		for _, op := range []OpcodeMisc{
   276  			OpcodeMiscMemoryInit, OpcodeMiscDataDrop, OpcodeMiscMemoryCopy,
   277  			OpcodeMiscMemoryFill, OpcodeMiscTableInit, OpcodeMiscElemDrop, OpcodeMiscTableCopy,
   278  		} {
   279  			t.Run(MiscInstructionName(op), func(t *testing.T) {
   280  				var body []byte
   281  				if op != OpcodeMiscDataDrop && op != OpcodeMiscElemDrop {
   282  					body = append(body, OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeI32Const, 3)
   283  				}
   284  
   285  				body = append(body, OpcodeMiscPrefix, op)
   286  				if op != OpcodeMiscDataDrop && op != OpcodeMiscMemoryFill && op != OpcodeMiscElemDrop {
   287  					body = append(body, 0, 0)
   288  				} else {
   289  					body = append(body, 0)
   290  				}
   291  
   292  				body = append(body, OpcodeEnd)
   293  
   294  				c := uint32(0)
   295  				m := &Module{
   296  					TypeSection:      []FunctionType{v_v},
   297  					FunctionSection:  []Index{0},
   298  					CodeSection:      []Code{{Body: body}},
   299  					DataSection:      []DataSegment{{}},
   300  					ElementSection:   []ElementSegment{{}},
   301  					DataCountSection: &c,
   302  				}
   303  				err := m.validateFunction(&stacks{}, api.CoreFeatureBulkMemoryOperations,
   304  					0, []Index{0}, nil, &Memory{}, []Table{{}, {}}, nil, bytes.NewReader(nil))
   305  				require.NoError(t, err)
   306  			})
   307  		}
   308  	})
   309  	t.Run("errors", func(t *testing.T) {
   310  		tests := []struct {
   311  			body                []byte
   312  			dataSection         []DataSegment
   313  			elementSection      []ElementSegment
   314  			dataCountSectionNil bool
   315  			memory              *Memory
   316  			tables              []Table
   317  			flag                api.CoreFeatures
   318  			expectedErr         string
   319  		}{
   320  			// memory.init
   321  			{
   322  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
   323  				flag:        api.CoreFeatureBulkMemoryOperations,
   324  				memory:      nil,
   325  				expectedErr: "memory must exist for memory.init",
   326  			},
   327  			{
   328  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
   329  				flag:        api.CoreFeaturesV1,
   330  				expectedErr: `memory.init invalid as feature "bulk-memory-operations" is disabled`,
   331  			},
   332  			{
   333  				body:                []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
   334  				flag:                api.CoreFeatureBulkMemoryOperations,
   335  				dataCountSectionNil: true,
   336  				expectedErr:         `memory must exist for memory.init`,
   337  			},
   338  			{
   339  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
   340  				flag:        api.CoreFeatureBulkMemoryOperations,
   341  				memory:      &Memory{},
   342  				expectedErr: "failed to read data segment index for memory.init: EOF",
   343  			},
   344  			{
   345  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 100 /* data section out of range */},
   346  				flag:        api.CoreFeatureBulkMemoryOperations,
   347  				memory:      &Memory{},
   348  				dataSection: []DataSegment{{}},
   349  				expectedErr: "index 100 out of range of data section(len=1)",
   350  			},
   351  			{
   352  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0},
   353  				flag:        api.CoreFeatureBulkMemoryOperations,
   354  				memory:      &Memory{},
   355  				dataSection: []DataSegment{{}},
   356  				expectedErr: "failed to read memory index for memory.init: EOF",
   357  			},
   358  			{
   359  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 1},
   360  				flag:        api.CoreFeatureBulkMemoryOperations,
   361  				memory:      &Memory{},
   362  				dataSection: []DataSegment{{}},
   363  				expectedErr: "memory.init reserved byte must be zero encoded with 1 byte",
   364  			},
   365  			{
   366  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0},
   367  				flag:        api.CoreFeatureBulkMemoryOperations,
   368  				memory:      &Memory{},
   369  				dataSection: []DataSegment{{}},
   370  				expectedErr: "cannot pop the operand for memory.init: i32 missing",
   371  			},
   372  			{
   373  				body:        []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0},
   374  				flag:        api.CoreFeatureBulkMemoryOperations,
   375  				memory:      &Memory{},
   376  				dataSection: []DataSegment{{}},
   377  				expectedErr: "cannot pop the operand for memory.init: i32 missing",
   378  			},
   379  			{
   380  				body:        []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0},
   381  				flag:        api.CoreFeatureBulkMemoryOperations,
   382  				memory:      &Memory{},
   383  				dataSection: []DataSegment{{}},
   384  				expectedErr: "cannot pop the operand for memory.init: i32 missing",
   385  			},
   386  			// data.drop
   387  			{
   388  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop},
   389  				flag:        api.CoreFeaturesV1,
   390  				expectedErr: `data.drop invalid as feature "bulk-memory-operations" is disabled`,
   391  			},
   392  			{
   393  				body:                []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop},
   394  				dataCountSectionNil: true,
   395  				memory:              &Memory{},
   396  				flag:                api.CoreFeatureBulkMemoryOperations,
   397  				expectedErr:         `data.drop requires data count section`,
   398  			},
   399  			{
   400  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop},
   401  				flag:        api.CoreFeatureBulkMemoryOperations,
   402  				memory:      &Memory{},
   403  				expectedErr: "failed to read data segment index for data.drop: EOF",
   404  			},
   405  			{
   406  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop, 100 /* data section out of range */},
   407  				flag:        api.CoreFeatureBulkMemoryOperations,
   408  				memory:      &Memory{},
   409  				dataSection: []DataSegment{{}},
   410  				expectedErr: "index 100 out of range of data section(len=1)",
   411  			},
   412  			// memory.copy
   413  			{
   414  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy},
   415  				flag:        api.CoreFeatureBulkMemoryOperations,
   416  				memory:      nil,
   417  				expectedErr: "memory must exist for memory.copy",
   418  			},
   419  			{
   420  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy},
   421  				flag:        api.CoreFeaturesV1,
   422  				expectedErr: `memory.copy invalid as feature "bulk-memory-operations" is disabled`,
   423  			},
   424  			{
   425  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy},
   426  				flag:        api.CoreFeatureBulkMemoryOperations,
   427  				memory:      &Memory{},
   428  				expectedErr: `failed to read memory index for memory.copy: EOF`,
   429  			},
   430  			{
   431  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0},
   432  				flag:        api.CoreFeatureBulkMemoryOperations,
   433  				memory:      &Memory{},
   434  				expectedErr: "failed to read memory index for memory.copy: EOF",
   435  			},
   436  			{
   437  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 1},
   438  				flag:        api.CoreFeatureBulkMemoryOperations,
   439  				memory:      &Memory{},
   440  				expectedErr: "memory.copy reserved byte must be zero encoded with 1 byte",
   441  			},
   442  			{
   443  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0},
   444  				flag:        api.CoreFeatureBulkMemoryOperations,
   445  				memory:      &Memory{},
   446  				expectedErr: "cannot pop the operand for memory.copy: i32 missing",
   447  			},
   448  			{
   449  				body:        []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0},
   450  				flag:        api.CoreFeatureBulkMemoryOperations,
   451  				memory:      &Memory{},
   452  				expectedErr: "cannot pop the operand for memory.copy: i32 missing",
   453  			},
   454  			{
   455  				body:        []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0},
   456  				flag:        api.CoreFeatureBulkMemoryOperations,
   457  				memory:      &Memory{},
   458  				expectedErr: "cannot pop the operand for memory.copy: i32 missing",
   459  			},
   460  			// memory.fill
   461  			{
   462  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill},
   463  				flag:        api.CoreFeatureBulkMemoryOperations,
   464  				memory:      nil,
   465  				expectedErr: "memory must exist for memory.fill",
   466  			},
   467  			{
   468  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill},
   469  				flag:        api.CoreFeaturesV1,
   470  				expectedErr: `memory.fill invalid as feature "bulk-memory-operations" is disabled`,
   471  			},
   472  			{
   473  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill},
   474  				flag:        api.CoreFeatureBulkMemoryOperations,
   475  				memory:      &Memory{},
   476  				expectedErr: `failed to read memory index for memory.fill: EOF`,
   477  			},
   478  			{
   479  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill, 1},
   480  				flag:        api.CoreFeatureBulkMemoryOperations,
   481  				memory:      &Memory{},
   482  				expectedErr: `memory.fill reserved byte must be zero encoded with 1 byte`,
   483  			},
   484  			{
   485  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0},
   486  				flag:        api.CoreFeatureBulkMemoryOperations,
   487  				memory:      &Memory{},
   488  				expectedErr: "cannot pop the operand for memory.fill: i32 missing",
   489  			},
   490  			{
   491  				body:        []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0},
   492  				flag:        api.CoreFeatureBulkMemoryOperations,
   493  				memory:      &Memory{},
   494  				expectedErr: "cannot pop the operand for memory.fill: i32 missing",
   495  			},
   496  			{
   497  				body:        []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0},
   498  				flag:        api.CoreFeatureBulkMemoryOperations,
   499  				memory:      &Memory{},
   500  				expectedErr: "cannot pop the operand for memory.fill: i32 missing",
   501  			},
   502  			// table.init
   503  			{
   504  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableInit},
   505  				flag:        api.CoreFeaturesV1,
   506  				tables:      []Table{{}},
   507  				expectedErr: `table.init invalid as feature "bulk-memory-operations" is disabled`,
   508  			},
   509  			{
   510  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableInit},
   511  				flag:        api.CoreFeatureBulkMemoryOperations,
   512  				tables:      []Table{{}},
   513  				expectedErr: "failed to read element segment index for table.init: EOF",
   514  			},
   515  			{
   516  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 100 /* data section out of range */},
   517  				flag:           api.CoreFeatureBulkMemoryOperations,
   518  				tables:         []Table{{}},
   519  				elementSection: []ElementSegment{{}},
   520  				expectedErr:    "index 100 out of range of element section(len=1)",
   521  			},
   522  			{
   523  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0},
   524  				flag:           api.CoreFeatureBulkMemoryOperations,
   525  				tables:         []Table{{}},
   526  				elementSection: []ElementSegment{{}},
   527  				expectedErr:    "failed to read source table index for table.init: EOF",
   528  			},
   529  			{
   530  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 10},
   531  				flag:           api.CoreFeatureBulkMemoryOperations,
   532  				tables:         []Table{{}},
   533  				elementSection: []ElementSegment{{}},
   534  				expectedErr:    "source table index must be zero for table.init as feature \"reference-types\" is disabled",
   535  			},
   536  			{
   537  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 10},
   538  				flag:           api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
   539  				tables:         []Table{{}},
   540  				elementSection: []ElementSegment{{}},
   541  				expectedErr:    "table of index 10 not found",
   542  			},
   543  			{
   544  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 1},
   545  				flag:           api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
   546  				tables:         []Table{{}, {Type: RefTypeExternref}},
   547  				elementSection: []ElementSegment{{Type: RefTypeFuncref}},
   548  				expectedErr:    "type mismatch for table.init: element type funcref does not match table type externref",
   549  			},
   550  			{
   551  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0},
   552  				flag:           api.CoreFeatureBulkMemoryOperations,
   553  				tables:         []Table{{}},
   554  				elementSection: []ElementSegment{{}},
   555  				expectedErr:    "cannot pop the operand for table.init: i32 missing",
   556  			},
   557  			{
   558  				body:           []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0},
   559  				flag:           api.CoreFeatureBulkMemoryOperations,
   560  				tables:         []Table{{}},
   561  				elementSection: []ElementSegment{{}},
   562  				expectedErr:    "cannot pop the operand for table.init: i32 missing",
   563  			},
   564  			{
   565  				body:           []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0},
   566  				flag:           api.CoreFeatureBulkMemoryOperations,
   567  				tables:         []Table{{}},
   568  				elementSection: []ElementSegment{{}},
   569  				expectedErr:    "cannot pop the operand for table.init: i32 missing",
   570  			},
   571  			// elem.drop
   572  			{
   573  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop},
   574  				flag:        api.CoreFeaturesV1,
   575  				tables:      []Table{{}},
   576  				expectedErr: `elem.drop invalid as feature "bulk-memory-operations" is disabled`,
   577  			},
   578  			{
   579  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop},
   580  				flag:        api.CoreFeatureBulkMemoryOperations,
   581  				tables:      []Table{{}},
   582  				expectedErr: "failed to read element segment index for elem.drop: EOF",
   583  			},
   584  			{
   585  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop, 100 /* element section out of range */},
   586  				flag:           api.CoreFeatureBulkMemoryOperations,
   587  				tables:         []Table{{}},
   588  				elementSection: []ElementSegment{{}},
   589  				expectedErr:    "index 100 out of range of element section(len=1)",
   590  			},
   591  			// table.copy
   592  			{
   593  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy},
   594  				flag:        api.CoreFeaturesV1,
   595  				tables:      []Table{{}},
   596  				expectedErr: `table.copy invalid as feature "bulk-memory-operations" is disabled`,
   597  			},
   598  			{
   599  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy},
   600  				flag:        api.CoreFeatureBulkMemoryOperations,
   601  				tables:      []Table{{}},
   602  				expectedErr: `failed to read destination table index for table.copy: EOF`,
   603  			},
   604  			{
   605  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 10},
   606  				flag:        api.CoreFeatureBulkMemoryOperations,
   607  				tables:      []Table{{}},
   608  				expectedErr: "destination table index must be zero for table.copy as feature \"reference-types\" is disabled",
   609  			},
   610  			{
   611  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3},
   612  				flag:        api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
   613  				tables:      []Table{{}, {}},
   614  				expectedErr: "table of index 3 not found",
   615  			},
   616  			{
   617  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3},
   618  				flag:        api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
   619  				tables:      []Table{{}, {}, {}, {}},
   620  				expectedErr: "failed to read source table index for table.copy: EOF",
   621  			},
   622  			{
   623  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 3},
   624  				flag:        api.CoreFeatureBulkMemoryOperations, // Multiple tables require api.CoreFeatureReferenceTypes.
   625  				tables:      []Table{{}, {}, {}, {}},
   626  				expectedErr: "source table index must be zero for table.copy as feature \"reference-types\" is disabled",
   627  			},
   628  			{
   629  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3, 1},
   630  				flag:        api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
   631  				tables:      []Table{{}, {Type: RefTypeFuncref}, {}, {Type: RefTypeExternref}},
   632  				expectedErr: "table type mismatch for table.copy: funcref (src) != externref (dst)",
   633  			},
   634  			{
   635  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 0},
   636  				flag:        api.CoreFeatureBulkMemoryOperations,
   637  				tables:      []Table{{}},
   638  				expectedErr: "cannot pop the operand for table.copy: i32 missing",
   639  			},
   640  			{
   641  				body:        []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 0},
   642  				flag:        api.CoreFeatureBulkMemoryOperations,
   643  				tables:      []Table{{}},
   644  				expectedErr: "cannot pop the operand for table.copy: i32 missing",
   645  			},
   646  			{
   647  				body:        []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 0},
   648  				flag:        api.CoreFeatureBulkMemoryOperations,
   649  				tables:      []Table{{}},
   650  				expectedErr: "cannot pop the operand for table.copy: i32 missing",
   651  			},
   652  		}
   653  
   654  		for _, tt := range tests {
   655  			tc := tt
   656  			t.Run(tc.expectedErr, func(t *testing.T) {
   657  				m := &Module{
   658  					TypeSection:     []FunctionType{v_v},
   659  					FunctionSection: []Index{0},
   660  					CodeSection:     []Code{{Body: tc.body}},
   661  					ElementSection:  tc.elementSection,
   662  					DataSection:     tc.dataSection,
   663  				}
   664  				if !tc.dataCountSectionNil {
   665  					c := uint32(0)
   666  					m.DataCountSection = &c
   667  				}
   668  				err := m.validateFunction(&stacks{}, tc.flag, 0, []Index{0}, nil, tc.memory, tc.tables, nil, bytes.NewReader(nil))
   669  				require.EqualError(t, err, tc.expectedErr)
   670  			})
   671  		}
   672  	})
   673  }
   674  
   675  var (
   676  	f32, f64, i32, i64, v128, externref = ValueTypeF32, ValueTypeF64, ValueTypeI32, ValueTypeI64, ValueTypeV128, ValueTypeExternref
   677  	f32i32_v                            = initFt([]ValueType{f32, i32}, nil)
   678  	f64f32_i64                          = initFt([]ValueType{f64, f32}, []ValueType{i64})
   679  	f64i32_v128i64                      = initFt([]ValueType{f64, i32}, []ValueType{v128, i64})
   680  	i32_i32                             = initFt([]ValueType{i32}, []ValueType{i32})
   681  	i32f64_v                            = initFt([]ValueType{i32, f64}, nil)
   682  	i32i32_i32                          = initFt([]ValueType{i32, i32}, []ValueType{i32})
   683  	i32_v                               = initFt([]ValueType{i32}, nil)
   684  	v_v                                 = FunctionType{}
   685  	v_f32                               = initFt(nil, []ValueType{f32})
   686  	v_f32f32                            = initFt(nil, []ValueType{f32, f32})
   687  	v_f64i32                            = initFt(nil, []ValueType{f64, i32})
   688  	v_f64f64                            = initFt(nil, []ValueType{f64, f64})
   689  	v_i32                               = initFt(nil, []ValueType{i32})
   690  	v_i32i32                            = initFt(nil, []ValueType{i32, i32})
   691  	v_i32i64                            = initFt(nil, []ValueType{i32, i64})
   692  	v_i64i64                            = initFt(nil, []ValueType{i64, i64})
   693  )
   694  
   695  func initFt(params, results []ValueType) FunctionType {
   696  	ft := FunctionType{Params: params, Results: results}
   697  	ft.CacheNumInUint64()
   698  	return ft
   699  }
   700  
   701  // TestModule_ValidateFunction_MultiValue_TypeMismatch are "type mismatch" tests when "multi-value" was merged.
   702  //
   703  // See https://github.com/WebAssembly/spec/commit/484180ba3d9d7638ba1cb400b699ffede796927c
   704  func TestModule_ValidateFunction_MultiValue_TypeMismatch(t *testing.T) {
   705  	tests := []struct {
   706  		name            string
   707  		module          *Module
   708  		expectedErr     string
   709  		enabledFeatures api.CoreFeatures
   710  	}{
   711  		// test/core/func.wast
   712  
   713  		{
   714  			name: `func.wast - type-empty-f64-i32`,
   715  			module: &Module{
   716  				TypeSection:     []FunctionType{v_f64i32},
   717  				FunctionSection: []Index{0},
   718  				CodeSection:     []Code{{Body: []byte{OpcodeEnd}}},
   719  			},
   720  			expectedErr: `not enough results
   721  	have ()
   722  	want (f64, i32)`,
   723  		},
   724  		{
   725  			name: `func.wast - type-value-void-vs-nums`,
   726  			module: &Module{
   727  				TypeSection:     []FunctionType{v_i32i32},
   728  				FunctionSection: []Index{0},
   729  				CodeSection:     []Code{{Body: []byte{OpcodeNop, OpcodeEnd}}},
   730  			},
   731  			expectedErr: `not enough results
   732  	have ()
   733  	want (i32, i32)`,
   734  		},
   735  		{
   736  			name: `func.wast - type-value-nums-vs-void`,
   737  			module: &Module{
   738  				TypeSection:     []FunctionType{v_v},
   739  				FunctionSection: []Index{0},
   740  				CodeSection:     []Code{{Body: []byte{OpcodeI32Const, 0, OpcodeI64Const, 0, OpcodeEnd}}},
   741  			},
   742  			expectedErr: `too many results
   743  	have (i32, i64)
   744  	want ()`,
   745  		},
   746  		{
   747  			name: `func.wast - type-value-num-vs-nums - v_f32f32 -> f32`,
   748  			module: &Module{
   749  				TypeSection:     []FunctionType{v_f32f32},
   750  				FunctionSection: []Index{0},
   751  				CodeSection: []Code{{Body: []byte{
   752  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
   753  					OpcodeEnd, // func
   754  				}}},
   755  			},
   756  			expectedErr: `not enough results
   757  	have (f32)
   758  	want (f32, f32)`,
   759  		},
   760  		{
   761  			name: `func.wast - type-value-num-vs-nums - v_f32 -> f32f32`,
   762  			module: &Module{
   763  				TypeSection:     []FunctionType{v_f32},
   764  				FunctionSection: []Index{0},
   765  				CodeSection: []Code{{Body: []byte{
   766  					OpcodeF32Const, 0, 0, 0, 0, OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) (f32.const 0)
   767  					OpcodeEnd, // func
   768  				}}},
   769  			},
   770  			expectedErr: `too many results
   771  	have (f32, f32)
   772  	want (f32)`,
   773  		},
   774  		{
   775  			name: `func.wast - type-return-last-empty-vs-nums`,
   776  			module: &Module{
   777  				TypeSection:     []FunctionType{v_f32f32},
   778  				FunctionSection: []Index{0},
   779  				CodeSection:     []Code{{Body: []byte{OpcodeReturn, OpcodeEnd}}},
   780  			},
   781  			expectedErr: `not enough results
   782  	have ()
   783  	want (f32, f32)`,
   784  		},
   785  		{
   786  			name: `func.wast - type-return-last-void-vs-nums`,
   787  			module: &Module{
   788  				TypeSection:     []FunctionType{v_i32i64},
   789  				FunctionSection: []Index{0},
   790  				CodeSection:     []Code{{Body: []byte{OpcodeNop, OpcodeReturn, OpcodeEnd}}}, // (return (nop))
   791  			},
   792  			expectedErr: `not enough results
   793  	have ()
   794  	want (i32, i64)`,
   795  		},
   796  		{
   797  			name: `func.wast - type-return-last-num-vs-nums`,
   798  			module: &Module{
   799  				TypeSection:     []FunctionType{v_i64i64},
   800  				FunctionSection: []Index{0},
   801  				CodeSection: []Code{{Body: []byte{
   802  					OpcodeI64Const, 0, OpcodeReturn, // (return (i64.const 0))
   803  					OpcodeEnd, // func
   804  				}}},
   805  			},
   806  			expectedErr: `not enough results
   807  	have (i64)
   808  	want (i64, i64)`,
   809  		},
   810  		{
   811  			name: `func.wast - type-return-empty-vs-nums`,
   812  			// This should err because (return) precedes the values expected in the signature (i32i32):
   813  			//	(module (func $type-return-empty-vs-nums (result i32 i32)
   814  			//	  (return) (i32.const 1) (i32.const 2)
   815  			//	))
   816  			module: &Module{
   817  				TypeSection:     []FunctionType{v_i32i32},
   818  				FunctionSection: []Index{0},
   819  				CodeSection: []Code{{Body: []byte{
   820  					OpcodeReturn, OpcodeI32Const, 1, OpcodeI32Const, 2,
   821  					OpcodeEnd, // func
   822  				}}},
   823  			},
   824  			expectedErr: `not enough results
   825  	have ()
   826  	want (i32, i32)`,
   827  		},
   828  		{
   829  			name: `func.wast - type-return-partial-vs-nums`,
   830  			// This should err because (return) precedes one of the values expected in the signature (i32i32):
   831  			//	(module (func $type-return-partial-vs-nums (result i32 i32)
   832  			//	  (i32.const 1) (return) (i32.const 2)
   833  			//	))
   834  			module: &Module{
   835  				TypeSection:     []FunctionType{v_i32i32},
   836  				FunctionSection: []Index{0},
   837  				CodeSection: []Code{{Body: []byte{
   838  					OpcodeI32Const, 1, OpcodeReturn, OpcodeI32Const, 2,
   839  					OpcodeEnd, // func
   840  				}}},
   841  			},
   842  			expectedErr: `not enough results
   843  	have (i32)
   844  	want (i32, i32)`,
   845  		},
   846  		{
   847  			name: `func.wast - type-return-void-vs-nums`,
   848  			// This should err because (return) is empty due to nop, but the signature requires i32i32:
   849  			//	(module (func $type-return-void-vs-nums (result i32 i32)
   850  			//	  (return (nop)) (i32.const 1)
   851  			//	))
   852  			module: &Module{
   853  				TypeSection:     []FunctionType{v_i32i32},
   854  				FunctionSection: []Index{0},
   855  				CodeSection: []Code{{Body: []byte{
   856  					OpcodeNop, OpcodeReturn, // (return (nop))
   857  					OpcodeI32Const, 1, // (i32.const 1)
   858  					OpcodeEnd, // func
   859  				}}},
   860  			},
   861  			expectedErr: `not enough results
   862  	have ()
   863  	want (i32, i32)`,
   864  		},
   865  
   866  		{
   867  			name: `func.wast - type-return-num-vs-nums`,
   868  			module: &Module{
   869  				TypeSection:     []FunctionType{v_i32i32},
   870  				FunctionSection: []Index{0},
   871  				CodeSection: []Code{{Body: []byte{
   872  					OpcodeI64Const, 1, OpcodeReturn, // (return (i64.const 1))
   873  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2)
   874  					OpcodeEnd, // func
   875  				}}},
   876  			},
   877  			expectedErr: `not enough results
   878  	have (i64)
   879  	want (i32, i32)`,
   880  		},
   881  		{
   882  			name: `func.wast - type-return-first-num-vs-nums`,
   883  			// This should err because the return block doesn't return enough values.
   884  			//	(module (func $type-return-first-num-vs-nums (result i32 i32)
   885  			//	  (return (i32.const 1)) (return (i32.const 1) (i32.const 2))
   886  			//	))
   887  			module: &Module{
   888  				TypeSection:     []FunctionType{v_i32i32},
   889  				FunctionSection: []Index{0},
   890  				CodeSection: []Code{{Body: []byte{
   891  					OpcodeI64Const, 1, OpcodeReturn, // (return (i64.const 1))
   892  					OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeReturn, // (return (i32.const 1) (i32.const 2))
   893  					OpcodeEnd, // func
   894  				}}},
   895  			},
   896  			expectedErr: `not enough results
   897  	have (i64)
   898  	want (i32, i32)`,
   899  		},
   900  		{
   901  			name: `func.wast - type-break-last-num-vs-nums`,
   902  			module: &Module{
   903  				TypeSection:     []FunctionType{v_i32i32},
   904  				FunctionSection: []Index{0},
   905  				CodeSection: []Code{{Body: []byte{
   906  					OpcodeI32Const, 0, OpcodeBr, 0, // (br 0 (i32.const 0))
   907  					OpcodeEnd, // func
   908  				}}},
   909  			},
   910  			expectedErr: `not enough results in br block
   911  	have (i32)
   912  	want (i32, i32)`,
   913  		},
   914  		{
   915  			name: `func.wast - type-break-void-vs-nums`,
   916  			// This should err because (br 0) returns no values, but its enclosing function requires two:
   917  			//	(module (func $type-break-void-vs-nums (result i32 i32)
   918  			//	  (br 0) (i32.const 1) (i32.const 2)
   919  			//	))
   920  			module: &Module{
   921  				TypeSection:     []FunctionType{v_i32i32},
   922  				FunctionSection: []Index{0},
   923  				CodeSection: []Code{{Body: []byte{
   924  					OpcodeBr, 0, // (br 0)
   925  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2)
   926  					OpcodeEnd, // func
   927  				}}},
   928  			},
   929  			expectedErr: `not enough results in br block
   930  	have ()
   931  	want (i32, i32)`,
   932  		},
   933  		{
   934  			name: `func.wast - type-break-num-vs-nums`,
   935  			// This should err because (br 0) returns one value, but its enclosing function requires two:
   936  			//	(module (func $type-break-num-vs-nums (result i32 i32)
   937  			//	  (br 0 (i32.const 1)) (i32.const 1) (i32.const 2)
   938  			//	))
   939  			module: &Module{
   940  				TypeSection:     []FunctionType{v_i32i32},
   941  				FunctionSection: []Index{0},
   942  				CodeSection: []Code{{Body: []byte{
   943  					OpcodeI32Const, 1, OpcodeBr, 0, // (br 0 (i32.const 1))
   944  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2)
   945  					OpcodeEnd, // func
   946  				}}},
   947  			},
   948  			expectedErr: `not enough results in br block
   949  	have (i32)
   950  	want (i32, i32)`,
   951  		},
   952  		{
   953  			name: `func.wast - type-break-nested-empty-vs-nums`,
   954  			// This should err because (br 1) doesn't return values, but its enclosing function does:
   955  			//	(module (func $type-break-nested-empty-vs-nums (result i32 i32)
   956  			//	  (block (br 1)) (br 0 (i32.const 1) (i32.const 2))
   957  			//	))
   958  			module: &Module{
   959  				TypeSection:     []FunctionType{v_i32i32},
   960  				FunctionSection: []Index{0},
   961  				CodeSection: []Code{{Body: []byte{
   962  					OpcodeBlock, 0x40, OpcodeBr, 0x01, OpcodeEnd, // (block (br 1))
   963  					OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2))
   964  					OpcodeEnd, // func
   965  				}}},
   966  			},
   967  			expectedErr: `not enough results in br block
   968  	have ()
   969  	want (i32, i32)`,
   970  		},
   971  		{
   972  			name: `func.wast - type-break-nested-void-vs-nums`,
   973  			// This should err because nop returns the empty type, but the enclosing function returns i32i32:
   974  			//	(module (func $type-break-nested-void-vs-nums (result i32 i32)
   975  			//	  (block (br 1 (nop))) (br 0 (i32.const 1) (i32.const 2))
   976  			//	))
   977  			module: &Module{
   978  				TypeSection:     []FunctionType{v_i32i32},
   979  				FunctionSection: []Index{0},
   980  				CodeSection: []Code{{Body: []byte{
   981  					OpcodeBlock, 0x40, OpcodeNop, OpcodeBr, 0x01, OpcodeEnd, // (block (br 1 (nop)))
   982  					OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2))
   983  					OpcodeEnd, // func
   984  				}}},
   985  			},
   986  			expectedErr: `not enough results in br block
   987  	have ()
   988  	want (i32, i32)`,
   989  		},
   990  		{
   991  			name: `func.wast - type-break-nested-num-vs-nums`,
   992  			// This should err because the block signature is v_i32, but the enclosing function is v_i32i32:
   993  			//	(module (func $type-break-nested-num-vs-nums (result i32 i32)
   994  			//	  (block (result i32) (br 1 (i32.const 1))) (br 0 (i32.const 1) (i32.const 2))
   995  			//	))
   996  			module: &Module{
   997  				TypeSection:     []FunctionType{v_i32i32},
   998  				FunctionSection: []Index{0},
   999  				CodeSection: []Code{{Body: []byte{
  1000  					OpcodeBlock, 0x7f, OpcodeI32Const, 1, OpcodeBr, 1, OpcodeEnd, // (block (result i32) (br 1 (i32.const 1)))
  1001  					OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2))
  1002  					OpcodeEnd, // func
  1003  				}}},
  1004  			},
  1005  			expectedErr: `not enough results in br block
  1006  	have (i32)
  1007  	want (i32, i32)`,
  1008  		},
  1009  
  1010  		// test/core/if.wast
  1011  		{
  1012  			name: `if.wast - wrong signature for if type use`,
  1013  			// This should err because (br 0) returns no values, but its enclosing function requires two:
  1014  			//  (module
  1015  			//    (type $sig (func))
  1016  			//    (func (i32.const 1) (if (type $sig) (i32.const 0) (then)))
  1017  			//  )
  1018  			module: &Module{
  1019  				TypeSection:     []FunctionType{v_v},
  1020  				FunctionSection: []Index{0},
  1021  				CodeSection: []Code{{Body: []byte{
  1022  					OpcodeI32Const, 1, // (i32.const 1)
  1023  					OpcodeI32Const, 0, OpcodeIf, 0, // (if (type $sig) (i32.const 0)
  1024  					OpcodeEnd, // if
  1025  					OpcodeEnd, // func
  1026  				}}},
  1027  			},
  1028  			expectedErr: `too many results
  1029  	have (i32)
  1030  	want ()`,
  1031  		},
  1032  		{
  1033  			name: `if.wast - type-then-value-nums-vs-void`,
  1034  			// This should err because (if) without a type use returns no values, but its (then) returns two:
  1035  			//	(module (func $type-then-value-nums-vs-void
  1036  			//	  (if (i32.const 1) (then (i32.const 1) (i32.const 2)))
  1037  			//	))
  1038  			module: &Module{
  1039  				TypeSection:     []FunctionType{v_v},
  1040  				FunctionSection: []Index{0},
  1041  				CodeSection: []Code{{Body: []byte{
  1042  					OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1)
  1043  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (then (i32.const 1) (i32.const 2))
  1044  					OpcodeEnd, // if
  1045  					OpcodeEnd, // func
  1046  				}}},
  1047  			},
  1048  			expectedErr: `too many results in if block
  1049  	have (i32, i32)
  1050  	want ()`,
  1051  		},
  1052  		{
  1053  			name: `if.wast - type-then-value-nums-vs-void-else`,
  1054  			// This should err because (if) without a type use returns no values, but its (then) returns two:
  1055  			//	(module (func $type-then-value-nums-vs-void-else
  1056  			//	  (if (i32.const 1) (then (i32.const 1) (i32.const 2)) (else))
  1057  			//	))
  1058  			module: &Module{
  1059  				TypeSection:     []FunctionType{v_v},
  1060  				FunctionSection: []Index{0},
  1061  				CodeSection: []Code{{Body: []byte{
  1062  					OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1)
  1063  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (then (i32.const 1) (i32.const 2))
  1064  					OpcodeElse, // (else)
  1065  					OpcodeEnd,  // if
  1066  					OpcodeEnd,  // func
  1067  				}}},
  1068  			},
  1069  			expectedErr: `too many results in if block
  1070  	have (i32, i32)
  1071  	want ()`,
  1072  		},
  1073  		{
  1074  			name: `if.wast - type-else-value-nums-vs-void`,
  1075  			// This should err because (if) without a type use returns no values, but its (else) returns two:
  1076  			//	(module (func $type-else-value-nums-vs-void
  1077  			//	  (if (i32.const 1) (then) (else (i32.const 1) (i32.const 2)))
  1078  			//	))
  1079  			module: &Module{
  1080  				TypeSection:     []FunctionType{v_v},
  1081  				FunctionSection: []Index{0},
  1082  				CodeSection: []Code{{Body: []byte{
  1083  					OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1) (then)
  1084  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 2, // (else (i32.const 1) (i32.const 2))
  1085  					OpcodeEnd, // if
  1086  					OpcodeEnd, // func
  1087  				}}},
  1088  			},
  1089  			expectedErr: `too many results in else block
  1090  	have (i32, i32)
  1091  	want ()`,
  1092  		},
  1093  		{
  1094  			name: `if.wast - type-both-value-nums-vs-void`,
  1095  			// This should err because (if) without a type use returns no values, each branch returns two:
  1096  			//	(module (func $type-both-value-nums-vs-void
  1097  			//	  (if (i32.const 1) (then (i32.const 1) (i32.const 2)) (else (i32.const 2) (i32.const 1)))
  1098  			//	))
  1099  			module: &Module{
  1100  				TypeSection:     []FunctionType{v_v},
  1101  				FunctionSection: []Index{0},
  1102  				CodeSection: []Code{{Body: []byte{
  1103  					OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1)
  1104  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (then (i32.const 1) (i32.const 2))
  1105  					OpcodeElse, OpcodeI32Const, 2, OpcodeI32Const, 1, // (else (i32.const 2) (i32.const 1))
  1106  					OpcodeEnd, // if
  1107  					OpcodeEnd, // func
  1108  				}}},
  1109  			},
  1110  			expectedErr: `too many results in if block
  1111  	have (i32, i32)
  1112  	want ()`,
  1113  		},
  1114  		{
  1115  			name: `if.wast - type-then-value-empty-vs-nums`,
  1116  			// This should err because the if branch is empty, but its type use requires two i32s:
  1117  			//	(module (func $type-then-value-empty-vs-nums (result i32 i32)
  1118  			//	  (if (result i32 i32) (i32.const 1) (then) (else (i32.const 0) (i32.const 2)))
  1119  			//	))
  1120  			module: &Module{
  1121  				TypeSection:     []FunctionType{v_v, v_i32i32},
  1122  				FunctionSection: []Index{0},
  1123  				CodeSection: []Code{{Body: []byte{
  1124  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1) (then)
  1125  					OpcodeElse, OpcodeI32Const, 0, OpcodeI32Const, 2, // (else (i32.const 0) (i32.const 2)))
  1126  					OpcodeEnd, // if
  1127  					OpcodeEnd, // func
  1128  				}}},
  1129  			},
  1130  			expectedErr: `not enough results in if block
  1131  	have ()
  1132  	want (i32, i32)`,
  1133  		},
  1134  		{
  1135  			name: `if.wast - type-else-value-empty-vs-nums`,
  1136  			// This should err because the else branch is empty, but its type use requires two i32s:
  1137  			//	(module (func $type-else-value-empty-vs-nums (result i32 i32)
  1138  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 0) (i32.const 1)) (else))
  1139  			//	))
  1140  			module: &Module{
  1141  				TypeSection:     []FunctionType{v_v, v_i32i32},
  1142  				FunctionSection: []Index{0},
  1143  				CodeSection: []Code{{Body: []byte{
  1144  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1)
  1145  					OpcodeI32Const, 0, OpcodeI32Const, 2, // (then (i32.const 0) (i32.const 1))
  1146  					OpcodeElse, // (else)
  1147  					OpcodeEnd,  // if
  1148  					OpcodeEnd,  // func
  1149  				}}},
  1150  			},
  1151  			expectedErr: `not enough results in else block
  1152  	have ()
  1153  	want (i32, i32)`,
  1154  		},
  1155  		{
  1156  			name: `if.wast - type-both-value-empty-vs-nums`,
  1157  			// This should err because the both branches are empty, but the if type use requires two i32s:
  1158  			//	(module (func $type-both-value-empty-vs-nums (result i32 i32)
  1159  			//	  (if (result i32 i32) (i32.const 1) (then) (else))
  1160  			//	))
  1161  			module: &Module{
  1162  				TypeSection:     []FunctionType{v_v, v_i32i32},
  1163  				FunctionSection: []Index{0},
  1164  				CodeSection: []Code{{Body: []byte{
  1165  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1) (then)
  1166  					OpcodeElse, // (else)
  1167  					OpcodeEnd,  // if
  1168  					OpcodeEnd,  // func
  1169  				}}},
  1170  			},
  1171  			expectedErr: `not enough results in if block
  1172  	have ()
  1173  	want (i32, i32)`,
  1174  		},
  1175  		{
  1176  			name: `if.wast - type-no-else-vs-nums`,
  1177  			// This should err because the else branch is missing, but its type use requires two i32s:
  1178  			//	(module (func $type-no-else-vs-nums (result i32 i32)
  1179  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)))
  1180  			//	))
  1181  			module: &Module{
  1182  				TypeSection:     []FunctionType{v_v, v_i32i32},
  1183  				FunctionSection: []Index{0},
  1184  				CodeSection: []Code{{Body: []byte{
  1185  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1)
  1186  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1187  					OpcodeEnd, // if
  1188  					OpcodeEnd, // func
  1189  				}}},
  1190  			},
  1191  			expectedErr: `not enough results in else block
  1192  	have ()
  1193  	want (i32, i32)`,
  1194  		},
  1195  		{
  1196  			name: `if.wast - type-then-value-void-vs-nums`,
  1197  			// This should err because the then branch evaluates to empty, but its type use requires two i32s:
  1198  			//	(module (func $type-then-value-void-vs-nums (result i32 i32)
  1199  			//	  (if (result i32 i32) (i32.const 1) (then (nop)) (else (i32.const 0) (i32.const 0)))
  1200  			//	))
  1201  			module: &Module{
  1202  				TypeSection:     []FunctionType{v_v, v_i32i32},
  1203  				FunctionSection: []Index{0},
  1204  				CodeSection: []Code{{Body: []byte{
  1205  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1)
  1206  					OpcodeNop,                                        // (then (nop))
  1207  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1208  					OpcodeEnd, // if
  1209  					OpcodeEnd, // func
  1210  				}}},
  1211  			},
  1212  			expectedErr: `not enough results in if block
  1213  	have ()
  1214  	want (i32, i32)`,
  1215  		},
  1216  		{
  1217  			name: `if.wast - type-then-value-void-vs-nums`,
  1218  			// This should err because the else branch evaluates to empty, but its type use requires two i32s:
  1219  			//	(module (func $type-else-value-void-vs-nums (result i32 i32)
  1220  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 0) (i32.const 0)) (else (nop)))
  1221  			//	))
  1222  			module: &Module{
  1223  				TypeSection:     []FunctionType{v_i32i32},
  1224  				FunctionSection: []Index{0},
  1225  				CodeSection: []Code{{Body: []byte{
  1226  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1227  					OpcodeI32Const, 0, OpcodeI32Const, 0, // (then (i32.const 0) (i32.const 0))
  1228  					OpcodeElse, OpcodeNop, // (else (nop))
  1229  					OpcodeEnd, // if
  1230  					OpcodeEnd, // func
  1231  				}}},
  1232  			},
  1233  			expectedErr: `not enough results in else block
  1234  	have ()
  1235  	want (i32, i32)`,
  1236  		},
  1237  		{
  1238  			name: `if.wast - type-both-value-void-vs-nums`,
  1239  			// This should err because the if branch evaluates to empty, but its type use requires two i32s:
  1240  			//	(module (func $type-both-value-void-vs-nums (result i32 i32)
  1241  			//	  (if (result i32 i32) (i32.const 1) (then (nop)) (else (nop)))
  1242  			//	))
  1243  			module: &Module{
  1244  				TypeSection:     []FunctionType{v_i32i32},
  1245  				FunctionSection: []Index{0},
  1246  				CodeSection: []Code{{Body: []byte{
  1247  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1248  					OpcodeNop,             // (then (nop))
  1249  					OpcodeElse, OpcodeNop, // (else (nop))
  1250  					OpcodeEnd, // if
  1251  					OpcodeEnd, // func
  1252  				}}},
  1253  			},
  1254  			expectedErr: `not enough results in if block
  1255  	have ()
  1256  	want (i32, i32)`,
  1257  		},
  1258  		{
  1259  			name: `if.wast - type-then-value-num-vs-nums`,
  1260  			// This should err because the if branch returns one value, but its type use requires two:
  1261  			//	(module (func $type-then-value-num-vs-nums (result i32 i32)
  1262  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1)))
  1263  			//	))
  1264  			module: &Module{
  1265  				TypeSection:     []FunctionType{v_i32i32},
  1266  				FunctionSection: []Index{0},
  1267  				CodeSection: []Code{{Body: []byte{
  1268  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1269  					OpcodeI32Const, 1, // (then (i32.const 1))
  1270  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)))
  1271  					OpcodeEnd, // if
  1272  					OpcodeEnd, // func
  1273  				}}},
  1274  			},
  1275  			expectedErr: `not enough results in if block
  1276  	have (i32)
  1277  	want (i32, i32)`,
  1278  		},
  1279  		{
  1280  			name: `if.wast - type-else-value-num-vs-nums`,
  1281  			// This should err because the else branch returns one value, but its type use requires two:
  1282  			//	(module (func $type-else-value-num-vs-nums (result i32 i32)
  1283  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1)))
  1284  			//	))
  1285  			module: &Module{
  1286  				TypeSection:     []FunctionType{v_i32i32},
  1287  				FunctionSection: []Index{0},
  1288  				CodeSection: []Code{{Body: []byte{
  1289  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1290  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1291  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)))
  1292  					OpcodeEnd, // if
  1293  					OpcodeEnd, // func
  1294  				}}},
  1295  			},
  1296  			expectedErr: `not enough results in else block
  1297  	have (i32)
  1298  	want (i32, i32)`,
  1299  		},
  1300  		{
  1301  			name: `if.wast - type-both-value-num-vs-nums`,
  1302  			// This should err because the if branch returns one value, but its type use requires two:
  1303  			//	(module (func $type-both-value-num-vs-nums (result i32 i32)
  1304  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1)))
  1305  			//	))
  1306  			module: &Module{
  1307  				TypeSection:     []FunctionType{v_i32i32},
  1308  				FunctionSection: []Index{0},
  1309  				CodeSection: []Code{{Body: []byte{
  1310  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1311  					OpcodeI32Const, 1, // (then (i32.const 1))
  1312  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)))
  1313  					OpcodeEnd, // if
  1314  					OpcodeEnd, // func
  1315  				}}},
  1316  			},
  1317  			expectedErr: `not enough results in if block
  1318  	have (i32)
  1319  	want (i32, i32)`,
  1320  		},
  1321  		{
  1322  			name: `if.wast - type-then-value-partial-vs-nums`,
  1323  			// This should err because the if branch returns one value, but its type use requires two:
  1324  			//	(module (func $type-then-value-partial-vs-nums (result i32 i32)
  1325  			//	  (i32.const 0)
  1326  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1)))
  1327  			//	))
  1328  			module: &Module{
  1329  				TypeSection:     []FunctionType{v_i32i32},
  1330  				FunctionSection: []Index{0},
  1331  				CodeSection: []Code{{Body: []byte{
  1332  					OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if)
  1333  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1334  					OpcodeI32Const, 1, // (then (i32.const 1))
  1335  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1336  					OpcodeEnd, // if
  1337  					OpcodeEnd, // func
  1338  				}}},
  1339  			},
  1340  			expectedErr: `not enough results in if block
  1341  	have (i32)
  1342  	want (i32, i32)`,
  1343  		},
  1344  		{
  1345  			name: `if.wast - type-else-value-partial-vs-nums`,
  1346  			// This should err because the else branch returns one value, but its type use requires two:
  1347  			//	(module (func $type-else-value-partial-vs-nums (result i32 i32)
  1348  			//	  (i32.const 0)
  1349  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1)))
  1350  			//	))
  1351  			module: &Module{
  1352  				TypeSection:     []FunctionType{v_i32i32},
  1353  				FunctionSection: []Index{0},
  1354  				CodeSection: []Code{{Body: []byte{
  1355  					OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if)
  1356  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1357  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1358  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))
  1359  					OpcodeEnd, // if
  1360  					OpcodeEnd, // func
  1361  				}}},
  1362  			},
  1363  			expectedErr: `not enough results in else block
  1364  	have (i32)
  1365  	want (i32, i32)`,
  1366  		},
  1367  		{
  1368  			name: `if.wast - type-both-value-partial-vs-nums`,
  1369  			// This should err because the if branch returns one value, but its type use requires two:
  1370  			//  (module (func $type-both-value-partial-vs-nums (result i32 i32)
  1371  			//    (i32.const 0)
  1372  			//    (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1)))
  1373  			//  ))
  1374  			module: &Module{
  1375  				TypeSection:     []FunctionType{v_i32i32},
  1376  				FunctionSection: []Index{0},
  1377  				CodeSection: []Code{{Body: []byte{
  1378  					OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if)
  1379  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1380  					OpcodeI32Const, 1, // (then (i32.const 1))
  1381  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))
  1382  					OpcodeEnd, // if
  1383  					OpcodeEnd, // func
  1384  				}}},
  1385  			},
  1386  			expectedErr: `not enough results in if block
  1387  	have (i32)
  1388  	want (i32, i32)`,
  1389  		},
  1390  		{
  1391  			name: `if.wast - type-then-value-nums-vs-num`,
  1392  			// This should err because the if branch returns two values, but its type use requires one:
  1393  			//	(module (func $type-then-value-nums-vs-num (result i32)
  1394  			//	  (if (result i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1)))
  1395  			//	))
  1396  			module: &Module{
  1397  				TypeSection:     []FunctionType{v_i32},
  1398  				FunctionSection: []Index{0},
  1399  				CodeSection: []Code{{Body: []byte{
  1400  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1)
  1401  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1402  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))
  1403  					OpcodeEnd, // if
  1404  					OpcodeEnd, // func
  1405  				}}},
  1406  			},
  1407  			expectedErr: `too many results in if block
  1408  	have (i32, i32)
  1409  	want (i32)`,
  1410  		},
  1411  		{
  1412  			name: `if.wast - type-else-value-nums-vs-num`,
  1413  			// This should err because the else branch returns two values, but its type use requires one:
  1414  			//	(module (func $type-else-value-nums-vs-num (result i32)
  1415  			//	  (if (result i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1)))
  1416  			//	))
  1417  			module: &Module{
  1418  				TypeSection:     []FunctionType{v_i32},
  1419  				FunctionSection: []Index{0},
  1420  				CodeSection: []Code{{Body: []byte{
  1421  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1)
  1422  					OpcodeI32Const, 1, // (then (i32.const 1))
  1423  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1424  					OpcodeEnd, // if
  1425  					OpcodeEnd, // func
  1426  				}}},
  1427  			},
  1428  			expectedErr: `too many results in else block
  1429  	have (i32, i32)
  1430  	want (i32)`,
  1431  		},
  1432  		{
  1433  			name: `if.wast - type-both-value-nums-vs-num`,
  1434  			// This should err because the if branch returns two values, but its type use requires one:
  1435  			//	(module (func $type-both-value-nums-vs-num (result i32)
  1436  			//	  (if (result i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1) (i32.const 1)))
  1437  			//	))
  1438  			module: &Module{
  1439  				TypeSection:     []FunctionType{v_i32},
  1440  				FunctionSection: []Index{0},
  1441  				CodeSection: []Code{{Body: []byte{
  1442  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1)
  1443  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1444  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1445  					OpcodeEnd, // if
  1446  					OpcodeEnd, // func
  1447  				}}},
  1448  			},
  1449  			expectedErr: `too many results in if block
  1450  	have (i32, i32)
  1451  	want (i32)`,
  1452  		},
  1453  		{
  1454  			name: `if.wast - type-both-different-value-nums-vs-nums`,
  1455  			// This should err because the if branch returns three values, but its type use requires two:
  1456  			//	(module (func $type-both-different-value-nums-vs-nums (result i32 i32)
  1457  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1) (i32.const 1)) (else (i32.const 1)))
  1458  			//	))
  1459  			module: &Module{
  1460  				TypeSection:     []FunctionType{v_i32i32},
  1461  				FunctionSection: []Index{0},
  1462  				CodeSection: []Code{{Body: []byte{
  1463  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1464  					OpcodeI32Const, 1, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1) (i32.const 1))
  1465  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))
  1466  					OpcodeEnd, // if
  1467  					OpcodeEnd, // func
  1468  				}}},
  1469  			},
  1470  			expectedErr: `too many results in if block
  1471  	have (i32, i32, i32)
  1472  	want (i32, i32)`,
  1473  		},
  1474  		{
  1475  			name: `if.wast - type-then-break-last-void-vs-nums`,
  1476  			// This should err because the branch in the if returns no values, but its type use requires two:
  1477  			//	(module (func $type-then-break-last-void-vs-nums (result i32 i32)
  1478  			//	  (if (result i32 i32) (i32.const 1) (then (br 0)) (else (i32.const 1) (i32.const 1)))
  1479  			//	))
  1480  			module: &Module{
  1481  				TypeSection:     []FunctionType{v_i32i32},
  1482  				FunctionSection: []Index{0},
  1483  				CodeSection: []Code{{Body: []byte{
  1484  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1485  					OpcodeBr, 0, // (then (br 0))
  1486  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)))
  1487  					OpcodeEnd, // if
  1488  					OpcodeEnd, // func
  1489  				}}},
  1490  			},
  1491  			expectedErr: `not enough results in br block
  1492  	have ()
  1493  	want (i32, i32)`,
  1494  		},
  1495  		{
  1496  			name: `if.wast - type-else-break-last-void-vs-nums`,
  1497  			// This should err because the branch in the else returns no values, but its type use requires two:
  1498  			//	(module (func $type-else-break-last-void-vs-nums (result i32 i32)
  1499  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (br 0)))
  1500  			//	))
  1501  			module: &Module{
  1502  				TypeSection:     []FunctionType{v_i32i32},
  1503  				FunctionSection: []Index{0},
  1504  				CodeSection: []Code{{Body: []byte{
  1505  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1506  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1507  					OpcodeElse, OpcodeBr, 0, // (else (br 0))
  1508  					OpcodeEnd, // if
  1509  					OpcodeEnd, // func
  1510  				}}},
  1511  			},
  1512  			expectedErr: `not enough results in br block
  1513  	have ()
  1514  	want (i32, i32)`,
  1515  		},
  1516  		{
  1517  			name: `if.wast - type-then-break-empty-vs-nums`,
  1518  			// This should err because the branch in the if returns no values, but its type use requires two:
  1519  			//	(module (func $type-then-break-empty-vs-nums (result i32 i32)
  1520  			//	  (if (result i32 i32) (i32.const 1)
  1521  			//	    (then (br 0) (i32.const 1) (i32.const 1))
  1522  			//	    (else (i32.const 1) (i32.const 1))
  1523  			//	  )
  1524  			//	))
  1525  			module: &Module{
  1526  				TypeSection:     []FunctionType{v_i32i32},
  1527  				FunctionSection: []Index{0},
  1528  				CodeSection: []Code{{Body: []byte{
  1529  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1530  					OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0) (i32.const 1) (i32.const 1))
  1531  					// ^^ NOTE: consts are outside the br block
  1532  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1533  					OpcodeEnd, // if
  1534  					OpcodeEnd, // func
  1535  				}}},
  1536  			},
  1537  			expectedErr: `not enough results in br block
  1538  	have ()
  1539  	want (i32, i32)`,
  1540  		},
  1541  		{
  1542  			name: `if.wast - type-else-break-empty-vs-nums`,
  1543  			// This should err because the branch in the else returns no values, but its type use requires two:
  1544  			//	(module (func $type-else-break-empty-vs-nums (result i32 i32)
  1545  			//	  (if (result i32 i32) (i32.const 1)
  1546  			//	    (then (i32.const 1) (i32.const 1))
  1547  			//	    (else (br 0) (i32.const 1) (i32.const 1))
  1548  			//	  )
  1549  			//	))
  1550  			module: &Module{
  1551  				TypeSection:     []FunctionType{v_i32i32},
  1552  				FunctionSection: []Index{0},
  1553  				CodeSection: []Code{{Body: []byte{
  1554  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1555  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1556  					OpcodeElse, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0) (i32.const 1) (i32.const 1))
  1557  					// ^^ NOTE: consts are outside the br block
  1558  					OpcodeEnd, // if
  1559  					OpcodeEnd, // func
  1560  				}}},
  1561  			},
  1562  			expectedErr: `not enough results in br block
  1563  	have ()
  1564  	want (i32, i32)`,
  1565  		},
  1566  		{
  1567  			name: `if.wast - type-then-break-void-vs-nums`,
  1568  			// This should err because the branch in the if evaluates to no values, but its type use requires two:
  1569  			//	(module (func $type-then-break-void-vs-nums (result i32 i32)
  1570  			//	  (if (result i32 i32) (i32.const 1)
  1571  			//	    (then (br 0 (nop)) (i32.const 1) (i32.const 1))
  1572  			//	    (else (i32.const 1) (i32.const 1))
  1573  			//	  )
  1574  			//	))
  1575  			module: &Module{
  1576  				TypeSection:     []FunctionType{v_i32i32},
  1577  				FunctionSection: []Index{0},
  1578  				CodeSection: []Code{{Body: []byte{
  1579  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1580  					OpcodeNop, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0 (nop)) (i32.const 1) (i32.const 1))
  1581  					// ^^ NOTE: consts are outside the br block
  1582  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1583  					OpcodeEnd, // if
  1584  					OpcodeEnd, // func
  1585  				}}},
  1586  			},
  1587  			expectedErr: `not enough results in br block
  1588  	have ()
  1589  	want (i32, i32)`,
  1590  		},
  1591  		{
  1592  			name: `if.wast - type-else-break-void-vs-nums`,
  1593  			// This should err because the branch in the else evaluates to no values, but its type use requires two:
  1594  			//	(module (func $type-else-break-void-vs-nums (result i32 i32)
  1595  			//	  (if (result i32 i32) (i32.const 1)
  1596  			//	    (then (i32.const 1) (i32.const 1))
  1597  			//	    (else (br 0 (nop)) (i32.const 1) (i32.const 1))
  1598  			//	  )
  1599  			//	))
  1600  			module: &Module{
  1601  				TypeSection:     []FunctionType{v_i32i32},
  1602  				FunctionSection: []Index{0},
  1603  				CodeSection: []Code{{Body: []byte{
  1604  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1605  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1606  					OpcodeElse, OpcodeNop, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0 (nop)) (i32.const 1) (i32.const 1))
  1607  					// ^^ NOTE: consts are outside the br block
  1608  					OpcodeEnd, // if
  1609  					OpcodeEnd, // func
  1610  				}}},
  1611  			},
  1612  			expectedErr: `not enough results in br block
  1613  	have ()
  1614  	want (i32, i32)`,
  1615  		},
  1616  		{
  1617  			name: `if.wast - type-then-break-num-vs-nums`,
  1618  			// This should err because the branch in the if evaluates to one value, but its type use requires two:
  1619  			//	(module (func $type-then-break-num-vs-nums (result i32 i32)
  1620  			//	  (if (result i32 i32) (i32.const 1)
  1621  			//	    (then (br 0 (i64.const 1)) (i32.const 1) (i32.const 1))
  1622  			//	    (else (i32.const 1) (i32.const 1))
  1623  			//	  )
  1624  			//	))
  1625  			module: &Module{
  1626  				TypeSection:     []FunctionType{v_i32i32},
  1627  				FunctionSection: []Index{0},
  1628  				CodeSection: []Code{{Body: []byte{
  1629  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1630  					OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0 (i64.const 1)) (i32.const 1) (i32.const 1))
  1631  					// ^^ NOTE: only one (incorrect) const is inside the br block
  1632  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1633  					OpcodeEnd, // if
  1634  					OpcodeEnd, // func
  1635  				}}},
  1636  			},
  1637  			expectedErr: `not enough results in br block
  1638  	have (i64)
  1639  	want (i32, i32)`,
  1640  		},
  1641  		{
  1642  			name: `if.wast - type-else-break-num-vs-nums`,
  1643  			// This should err because the branch in the else evaluates to one value, but its type use requires two:
  1644  			//	(module (func $type-else-break-num-vs-nums (result i32 i32)
  1645  			//	  (if (result i32 i32) (i32.const 1)
  1646  			//	    (then (i32.const 1) (i32.const 1))
  1647  			//	    (else (br 0 (i64.const 1)) (i32.const 1) (i32.const 1))
  1648  			//	  )
  1649  			//	))
  1650  			module: &Module{
  1651  				TypeSection:     []FunctionType{v_i32i32},
  1652  				FunctionSection: []Index{0},
  1653  				CodeSection: []Code{{Body: []byte{
  1654  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1655  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1656  					OpcodeElse, OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0 (i64.const 1)) (i32.const 1) (i32.const 1))
  1657  					// ^^ NOTE: only one (incorrect) const is inside the br block
  1658  					OpcodeEnd, // if
  1659  					OpcodeEnd, // func
  1660  				}}},
  1661  			},
  1662  			expectedErr: `not enough results in br block
  1663  	have (i64)
  1664  	want (i32, i32)`,
  1665  		},
  1666  		{
  1667  			name: `if.wast - type-then-break-partial-vs-nums`,
  1668  			// This should err because the branch in the if evaluates to one value, but its type use requires two:
  1669  			//	(module (func $type-then-break-partial-vs-nums (result i32 i32)
  1670  			//	  (i32.const 1)
  1671  			//	  (if (result i32 i32) (i32.const 1)
  1672  			//	    (then (br 0 (i64.const 1)) (i32.const 1))
  1673  			//	    (else (i32.const 1))
  1674  			//	  )
  1675  			//	))
  1676  			module: &Module{
  1677  				TypeSection:     []FunctionType{v_i32i32},
  1678  				FunctionSection: []Index{0},
  1679  				CodeSection: []Code{{Body: []byte{
  1680  					OpcodeI32Const, 1, // (i32.const 1)
  1681  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1682  					OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, // (then (br 0 (i64.const 1)) (i32.const 1))
  1683  					// ^^ NOTE: only one (incorrect) const is inside the br block
  1684  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))
  1685  					OpcodeEnd, // if
  1686  					OpcodeEnd, // func
  1687  				}}},
  1688  			},
  1689  			expectedErr: `not enough results in br block
  1690  	have (i64)
  1691  	want (i32, i32)`,
  1692  		},
  1693  		{
  1694  			name: `if.wast - type-else-break-partial-vs-nums`,
  1695  			// This should err because the branch in the if evaluates to one value, but its type use requires two:
  1696  			//	(module (func $type-else-break-partial-vs-nums (result i32 i32)
  1697  			//	  (i32.const 1)
  1698  			//	  (if (result i32 i32) (i32.const 1)
  1699  			//	    (then (i32.const 1))
  1700  			//	    (else (br 0 (i64.const 1)) (i32.const 1))
  1701  			//	  )
  1702  			//	))
  1703  			module: &Module{
  1704  				TypeSection:     []FunctionType{v_i32i32},
  1705  				FunctionSection: []Index{0},
  1706  				CodeSection: []Code{{Body: []byte{
  1707  					OpcodeI32Const, 1, // (i32.const 1)
  1708  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1709  					OpcodeI32Const, 1, // (then (i32.const 1))
  1710  					OpcodeElse, OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, // (else (br 0 (i64.const 1)) (i32.const 1))
  1711  					// ^^ NOTE: only one (incorrect) const is inside the br block
  1712  					OpcodeEnd, // if
  1713  					OpcodeEnd, // func
  1714  				}}},
  1715  			},
  1716  			expectedErr: `not enough results in if block
  1717  	have (i32)
  1718  	want (i32, i32)`,
  1719  		},
  1720  		{
  1721  			name: `if.wast - type-param-void-vs-num`,
  1722  			// This should err because the stack has no values, but the if type use requires two:
  1723  			//	(module (func $type-param-void-vs-num
  1724  			//	  (if (param i32) (i32.const 1) (then (drop)))
  1725  			//	))
  1726  			module: &Module{
  1727  				TypeSection:     []FunctionType{v_v, i32_v},
  1728  				FunctionSection: []Index{0},
  1729  				CodeSection: []Code{{Body: []byte{
  1730  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1)
  1731  					OpcodeDrop, // (then (drop)))
  1732  					OpcodeEnd,  // if
  1733  					OpcodeEnd,  // func
  1734  				}}},
  1735  			},
  1736  			expectedErr: `not enough params for if block
  1737  	have ()
  1738  	want (i32)`,
  1739  		},
  1740  		{
  1741  			name: `if.wast - type-param-void-vs-nums`,
  1742  			// This should err because the stack has no values, but the if type use requires two:
  1743  			//	(module (func $type-param-void-vs-nums
  1744  			//	  (if (param i32 f64) (i32.const 1) (then (drop) (drop)))
  1745  			//	))
  1746  			module: &Module{
  1747  				TypeSection:     []FunctionType{v_v, i32f64_v},
  1748  				FunctionSection: []Index{0},
  1749  				CodeSection: []Code{{Body: []byte{
  1750  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32 f64) (i32.const 1)
  1751  					OpcodeI32Const, 1, OpcodeDrop, // (then (drop) (drop))
  1752  					OpcodeEnd, // if
  1753  					OpcodeEnd, // func
  1754  				}}},
  1755  			},
  1756  			expectedErr: `not enough params for if block
  1757  	have ()
  1758  	want (i32, f64)`,
  1759  		},
  1760  		{
  1761  			name: `if.wast - type-param-num-vs-num`,
  1762  			// This should err because the stack has a different value that what the if type use requires:
  1763  			//	(module (func $type-param-num-vs-num
  1764  			//	  (f32.const 0) (if (param i32) (i32.const 1) (then (drop)))
  1765  			//	))
  1766  			module: &Module{
  1767  				TypeSection:     []FunctionType{v_v, i32_v},
  1768  				FunctionSection: []Index{0},
  1769  				CodeSection: []Code{{Body: []byte{
  1770  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  1771  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1)
  1772  					OpcodeDrop, // (then (drop))
  1773  					OpcodeEnd,  // if
  1774  					OpcodeEnd,  // func
  1775  				}}},
  1776  			},
  1777  			expectedErr: "cannot use f32 in if block as param[0] type i32",
  1778  		},
  1779  		{
  1780  			name: `if.wast - type-param-num-vs-nums`,
  1781  			// This should err because the stack has one value, but the if type use requires two:
  1782  			//	(module (func $type-param-num-vs-nums
  1783  			//	  (f32.const 0) (if (param f32 i32) (i32.const 1) (then (drop) (drop)))
  1784  			//	))
  1785  			module: &Module{
  1786  				TypeSection:     []FunctionType{v_v, f32i32_v},
  1787  				FunctionSection: []Index{0},
  1788  				CodeSection: []Code{{Body: []byte{
  1789  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  1790  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param f32 i32) (i32.const 1)
  1791  					OpcodeDrop, OpcodeDrop, // (then (drop) (drop))
  1792  					OpcodeEnd, // if
  1793  					OpcodeEnd, // func
  1794  				}}},
  1795  			},
  1796  			expectedErr: `not enough params for if block
  1797  	have (f32)
  1798  	want (f32, i32)`,
  1799  		},
  1800  		{
  1801  			name: `if.wast - type-param-nested-void-vs-num`,
  1802  			// This should err because the stack has no values, but the if type use requires one:
  1803  			//	(module (func $type-param-nested-void-vs-num
  1804  			//	  (block (if (param i32) (i32.const 1) (then (drop))))
  1805  			//	))
  1806  			module: &Module{
  1807  				TypeSection:     []FunctionType{v_v, i32_v},
  1808  				FunctionSection: []Index{0},
  1809  				CodeSection: []Code{{Body: []byte{
  1810  					OpcodeBlock, 0x40, // (block
  1811  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1)
  1812  					OpcodeDrop, // (then (drop))
  1813  					OpcodeEnd,  // block
  1814  					OpcodeEnd,  // if
  1815  					OpcodeEnd,  // func
  1816  				}}},
  1817  			},
  1818  			expectedErr: `not enough params for if block
  1819  	have ()
  1820  	want (i32)`,
  1821  		},
  1822  		{
  1823  			name: `if.wast - type-param-void-vs-nums`,
  1824  			// This should err because the stack has no values, but the if type use requires two:
  1825  			//	(module (func $type-param-void-vs-nums
  1826  			//	  (block (if (param i32 f64) (i32.const 1) (then (drop) (drop))))
  1827  			//	))
  1828  			module: &Module{
  1829  				TypeSection:     []FunctionType{v_v, i32f64_v},
  1830  				FunctionSection: []Index{0},
  1831  				CodeSection: []Code{{Body: []byte{
  1832  					OpcodeBlock, 0x40, // (block
  1833  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32 f64) (i32.const 1)
  1834  					OpcodeDrop, // (then (drop) (drop))
  1835  					OpcodeEnd,  // block
  1836  					OpcodeEnd,  // if
  1837  					OpcodeEnd,  // func
  1838  				}}},
  1839  			},
  1840  			expectedErr: `not enough params for if block
  1841  	have ()
  1842  	want (i32, f64)`,
  1843  		},
  1844  		{
  1845  			name: `if.wast - type-param-num-vs-num`,
  1846  			// This should err because the stack has a different values than required by the if type use:
  1847  			//	(module (func $type-param-num-vs-num
  1848  			//	  (block (f32.const 0) (if (param i32) (i32.const 1) (then (drop))))
  1849  			//	))
  1850  			module: &Module{
  1851  				TypeSection:     []FunctionType{v_v, i32_v},
  1852  				FunctionSection: []Index{0},
  1853  				CodeSection: []Code{{Body: []byte{
  1854  					OpcodeBlock, 0x40, // (block
  1855  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  1856  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1)
  1857  					OpcodeDrop, // (then (drop))
  1858  					OpcodeEnd,  // block
  1859  					OpcodeEnd,  // if
  1860  					OpcodeEnd,  // func
  1861  				}}},
  1862  			},
  1863  			expectedErr: "cannot use f32 in if block as param[0] type i32",
  1864  		},
  1865  		{
  1866  			name: `if.wast - type-param-num-vs-nums`,
  1867  			// This should err because the stack has one value, but the if type use requires two:
  1868  			//	(module (func $type-param-num-vs-nums
  1869  			//	  (block (f32.const 0) (if (param f32 i32) (i32.const 1) (then (drop) (drop))))
  1870  			//	))
  1871  			module: &Module{
  1872  				TypeSection:     []FunctionType{v_v, f32i32_v},
  1873  				FunctionSection: []Index{0},
  1874  				CodeSection: []Code{{Body: []byte{
  1875  					OpcodeBlock, 0x40, // (block
  1876  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  1877  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param f32 i32) (i32.const 1)
  1878  					OpcodeDrop, // (then (drop) (drop))
  1879  					OpcodeEnd,  // block
  1880  					OpcodeEnd,  // if
  1881  					OpcodeEnd,  // func
  1882  				}}},
  1883  			},
  1884  			expectedErr: `not enough params for if block
  1885  	have (f32)
  1886  	want (f32, i32)`,
  1887  		},
  1888  
  1889  		// test/core/loop.wast
  1890  		{
  1891  			name: `loop.wast - wrong signature for loop type use`,
  1892  			// This should err because the loop type use returns no values, but its block returns one:
  1893  			//  (module
  1894  			//    (type $sig (func))
  1895  			//    (func (loop (type $sig) (i32.const 0)))
  1896  			//  )
  1897  			module: &Module{
  1898  				TypeSection:     []FunctionType{v_v},
  1899  				FunctionSection: []Index{0},
  1900  				CodeSection: []Code{{Body: []byte{
  1901  					OpcodeLoop, 0, OpcodeI32Const, 0, // (loop (type $sig) (i32.const 0))
  1902  					OpcodeEnd, // loop
  1903  					OpcodeEnd, // func
  1904  				}}},
  1905  			},
  1906  			expectedErr: `too many results in loop block
  1907  	have (i32)
  1908  	want ()`,
  1909  		},
  1910  		{
  1911  			name: `loop.wast - type-value-nums-vs-void`,
  1912  			// This should err because the empty block type requires no values, but the loop returns two:
  1913  			//  (module (func $type-value-nums-vs-void
  1914  			//    (loop (i32.const 1) (i32.const 2))
  1915  			//  ))
  1916  			module: &Module{
  1917  				TypeSection:     []FunctionType{v_v},
  1918  				FunctionSection: []Index{0},
  1919  				CodeSection: []Code{{Body: []byte{
  1920  					OpcodeLoop, 0x40, OpcodeI32Const, 1, OpcodeI32Const, 2, // (loop (i32.const 1) (i32.const 2))
  1921  					OpcodeEnd, // loop
  1922  					OpcodeEnd, // func
  1923  				}}},
  1924  			},
  1925  			expectedErr: `too many results in loop block
  1926  	have (i32, i32)
  1927  	want ()`,
  1928  		},
  1929  		{
  1930  			name: `loop.wast - type-value-empty-vs-nums`,
  1931  			// This should err because the loop type use returns two values, but the block returns none:
  1932  			//	(module (func $type-value-empty-vs-nums (result i32 i32)
  1933  			//	  (loop (result i32 i32))
  1934  			//	))
  1935  			module: &Module{
  1936  				TypeSection:     []FunctionType{v_i32i32},
  1937  				FunctionSection: []Index{0},
  1938  				CodeSection: []Code{{Body: []byte{
  1939  					OpcodeLoop, 0x0, // (loop (result i32 i32)) - matches existing func type
  1940  					OpcodeEnd, // loop
  1941  					OpcodeEnd, // func
  1942  				}}},
  1943  			},
  1944  			expectedErr: `not enough results in loop block
  1945  	have ()
  1946  	want (i32, i32)`,
  1947  		},
  1948  		{
  1949  			name: `loop.wast - type-value-void-vs-nums`,
  1950  			// This should err because the loop type use returns two values, but the block returns none:
  1951  			//	(module (func $type-value-void-vs-nums (result i32 i32)
  1952  			//	  (loop (result i32 i32) (nop))
  1953  			//	))
  1954  			module: &Module{
  1955  				TypeSection:     []FunctionType{v_i32i32},
  1956  				FunctionSection: []Index{0},
  1957  				CodeSection: []Code{{Body: []byte{
  1958  					OpcodeLoop, 0x0, // (loop (result i32 i32) - matches existing func type
  1959  					OpcodeNop, // (nop)
  1960  					OpcodeEnd, // loop
  1961  					OpcodeEnd, // func
  1962  				}}},
  1963  			},
  1964  			expectedErr: `not enough results in loop block
  1965  	have ()
  1966  	want (i32, i32)`,
  1967  		},
  1968  		{
  1969  			name: `loop.wast - type-value-num-vs-nums`,
  1970  			// This should err because the loop type use returns two values, but the block returns one:
  1971  			//	(module (func $type-value-num-vs-nums (result i32 i32)
  1972  			//	  (loop (result i32 i32) (i32.const 0))
  1973  			//	))
  1974  			module: &Module{
  1975  				TypeSection:     []FunctionType{v_i32i32},
  1976  				FunctionSection: []Index{0},
  1977  				CodeSection: []Code{{Body: []byte{
  1978  					OpcodeLoop, 0x0, // (loop (result i32 i32) - matches existing func type
  1979  					OpcodeI32Const, 0, // (i32.const 0)
  1980  					OpcodeEnd, // loop
  1981  					OpcodeEnd, // func
  1982  				}}},
  1983  			},
  1984  			expectedErr: `not enough results in loop block
  1985  	have (i32)
  1986  	want (i32, i32)`,
  1987  		},
  1988  		{
  1989  			name: `loop.wast - type-value-partial-vs-nums`,
  1990  			// This should err because the loop type use returns two values, but the block returns one:
  1991  			//	(module (func $type-value-partial-vs-nums (result i32 i32)
  1992  			//	  (i32.const 1) (loop (result i32 i32) (i32.const 2))
  1993  			//	))
  1994  			module: &Module{
  1995  				TypeSection:     []FunctionType{v_i32i32},
  1996  				FunctionSection: []Index{0},
  1997  				CodeSection: []Code{{Body: []byte{
  1998  					OpcodeI32Const, 1, // (i32.const 1) - NOTE: outside the loop!
  1999  					OpcodeLoop, 0x0, // (loop (result i32 i32) - matches existing func type
  2000  					OpcodeI32Const, 2, // (i32.const 2)
  2001  					OpcodeEnd, // loop
  2002  					OpcodeEnd, // func
  2003  				}}},
  2004  			},
  2005  			expectedErr: `not enough results in loop block
  2006  	have (i32)
  2007  	want (i32, i32)`,
  2008  		},
  2009  		{
  2010  			name: `loop.wast - type-value-nums-vs-num`,
  2011  			// This should err because the loop type use returns one value, but the block returns two:
  2012  			//	(module (func $type-value-nums-vs-num (result i32)
  2013  			//	  (loop (result i32) (i32.const 1) (i32.const 2))
  2014  			//	))
  2015  			module: &Module{
  2016  				TypeSection:     []FunctionType{v_i32},
  2017  				FunctionSection: []Index{0},
  2018  				CodeSection: []Code{{Body: []byte{
  2019  					OpcodeLoop, 0x0, // (loop (result i32) - matches existing func type
  2020  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2))
  2021  					OpcodeEnd, // loop
  2022  					OpcodeEnd, // func
  2023  				}}},
  2024  			},
  2025  			expectedErr: `too many results in loop block
  2026  	have (i32, i32)
  2027  	want (i32)`,
  2028  		},
  2029  		{
  2030  			name: `loop.wast - type-param-void-vs-num`,
  2031  			// This should err because the loop type use requires one param, but the stack has none:
  2032  			//	(module (func $type-param-void-vs-num
  2033  			//	  (loop (param i32) (drop))
  2034  			//	))
  2035  			module: &Module{
  2036  				TypeSection:     []FunctionType{v_v, i32_v},
  2037  				FunctionSection: []Index{0},
  2038  				CodeSection: []Code{{Body: []byte{
  2039  					OpcodeLoop, 0x1, // (loop (param i32)
  2040  					OpcodeDrop, // (drop)
  2041  					OpcodeEnd,  // loop
  2042  					OpcodeEnd,  // func
  2043  				}}},
  2044  			},
  2045  			expectedErr: `not enough params for loop block
  2046  	have ()
  2047  	want (i32)`,
  2048  		},
  2049  		{
  2050  			name: `loop.wast - type-param-void-vs-nums`,
  2051  			// This should err because the loop type use requires two params, but the stack has none:
  2052  			//	(module (func $type-param-void-vs-nums
  2053  			//	  (loop (param i32 f64) (drop) (drop))
  2054  			//	))
  2055  			module: &Module{
  2056  				TypeSection:     []FunctionType{v_v, i32f64_v},
  2057  				FunctionSection: []Index{0},
  2058  				CodeSection: []Code{{Body: []byte{
  2059  					OpcodeLoop, 0x1, // (loop (param i32 f64)
  2060  					OpcodeDrop, // (drop)
  2061  					OpcodeDrop, // (drop)
  2062  					OpcodeEnd,  // loop
  2063  					OpcodeEnd,  // func
  2064  				}}},
  2065  			},
  2066  			expectedErr: `not enough params for loop block
  2067  	have ()
  2068  	want (i32, f64)`,
  2069  		},
  2070  		{
  2071  			name: `loop.wast - type-param-num-vs-num`,
  2072  			// This should err because the loop type use requires a different param type than what's on the stack:
  2073  			//	(module (func $type-param-num-vs-num
  2074  			//	  (f32.const 0) (loop (param i32) (drop))
  2075  			//	))
  2076  			module: &Module{
  2077  				TypeSection:     []FunctionType{v_v, i32_v},
  2078  				FunctionSection: []Index{0},
  2079  				CodeSection: []Code{{Body: []byte{
  2080  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  2081  					OpcodeLoop, 0x1, // (loop (param i32)
  2082  					OpcodeDrop, // (drop)
  2083  					OpcodeEnd,  // loop
  2084  					OpcodeEnd,  // func
  2085  				}}},
  2086  			},
  2087  			expectedErr: "cannot use f32 in loop block as param[0] type i32",
  2088  		},
  2089  		{
  2090  			name: `loop.wast - type-param-num-vs-num`,
  2091  			// This should err because the loop type use requires a more parameters than what's on the stack:
  2092  			//	(module (func $type-param-num-vs-nums
  2093  			//	  (f32.const 0) (loop (param f32 i32) (drop) (drop))
  2094  			//	))
  2095  			module: &Module{
  2096  				TypeSection:     []FunctionType{v_v, f32i32_v},
  2097  				FunctionSection: []Index{0},
  2098  				CodeSection: []Code{{Body: []byte{
  2099  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  2100  					OpcodeLoop, 0x1, // (loop (param f32 i32)
  2101  					OpcodeDrop, OpcodeDrop, // (drop) (drop)
  2102  					OpcodeEnd, // loop
  2103  					OpcodeEnd, // func
  2104  				}}},
  2105  			},
  2106  			expectedErr: `not enough params for loop block
  2107  	have (f32)
  2108  	want (f32, i32)`,
  2109  		},
  2110  		{
  2111  			name: `loop.wast - type-param-nested-void-vs-num`,
  2112  			// This should err because the loop type use requires a more parameters than what's on the stack:
  2113  			//	(module (func $type-param-nested-void-vs-num
  2114  			//	  (block (loop (param i32) (drop)))
  2115  			//	))
  2116  			module: &Module{
  2117  				TypeSection:     []FunctionType{v_v, i32_v},
  2118  				FunctionSection: []Index{0},
  2119  				CodeSection: []Code{{Body: []byte{
  2120  					OpcodeBlock, 0x40, // (block
  2121  					OpcodeLoop, 0x1, // (loop (param i32)
  2122  					OpcodeDrop, // (drop)
  2123  					OpcodeEnd,  // loop
  2124  					OpcodeEnd,  // block
  2125  					OpcodeEnd,  // func
  2126  				}}},
  2127  			},
  2128  			expectedErr: `not enough params for loop block
  2129  	have ()
  2130  	want (i32)`,
  2131  		},
  2132  		{
  2133  			name: `loop.wast - type-param-void-vs-nums`,
  2134  			// This should err because the loop type use requires a more parameters than what's on the stack:
  2135  			//	(module (func $type-param-void-vs-nums
  2136  			//	  (block (loop (param i32 f64) (drop) (drop)))
  2137  			//	))
  2138  			module: &Module{
  2139  				TypeSection:     []FunctionType{v_v, i32f64_v},
  2140  				FunctionSection: []Index{0},
  2141  				CodeSection: []Code{{Body: []byte{
  2142  					OpcodeBlock, 0x40, // (block
  2143  					OpcodeLoop, 0x1, // (loop (param i32 f64)
  2144  					OpcodeDrop, OpcodeDrop, // (drop) (drop)
  2145  					OpcodeEnd, // loop
  2146  					OpcodeEnd, // block
  2147  					OpcodeEnd, // func
  2148  				}}},
  2149  			},
  2150  			expectedErr: `not enough params for loop block
  2151  	have ()
  2152  	want (i32, f64)`,
  2153  		},
  2154  		{
  2155  			name: `loop.wast - type-param-void-vs-nums`,
  2156  			// This should err because the loop type use requires a different param type than what's on the stack:
  2157  			//	(module (func $type-param-num-vs-num
  2158  			//	  (block (f32.const 0) (loop (param i32) (drop)))
  2159  			//	))
  2160  			module: &Module{
  2161  				TypeSection:     []FunctionType{v_v, i32_v},
  2162  				FunctionSection: []Index{0},
  2163  				CodeSection: []Code{{Body: []byte{
  2164  					OpcodeBlock, 0x40, // (block
  2165  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  2166  					OpcodeLoop, 0x1, // (loop (param i32)
  2167  					OpcodeDrop, // (drop)
  2168  					OpcodeEnd,  // loop
  2169  					OpcodeEnd,  // block
  2170  					OpcodeEnd,  // func
  2171  				}}},
  2172  			},
  2173  			expectedErr: "cannot use f32 in loop block as param[0] type i32",
  2174  		},
  2175  		{
  2176  			name: `loop.wast - type-param-void-vs-nums`,
  2177  			// This should err because the loop type use requires a more parameters than what's on the stack:
  2178  			//	(module (func $type-param-num-vs-nums
  2179  			//	  (block (f32.const 0) (loop (param f32 i32) (drop) (drop)))
  2180  			//	))
  2181  			module: &Module{
  2182  				TypeSection:     []FunctionType{v_v, f32i32_v},
  2183  				FunctionSection: []Index{0},
  2184  				CodeSection: []Code{{Body: []byte{
  2185  					OpcodeBlock, 0x40, // (block
  2186  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  2187  					OpcodeLoop, 0x1, // (loop (param f32 i32)
  2188  					OpcodeDrop, OpcodeDrop, // (drop) (drop)
  2189  					OpcodeEnd, // loop
  2190  					OpcodeEnd, // block
  2191  					OpcodeEnd, // func
  2192  				}}},
  2193  			},
  2194  			expectedErr: `not enough params for loop block
  2195  	have (f32)
  2196  	want (f32, i32)`,
  2197  		},
  2198  	}
  2199  
  2200  	for _, tt := range tests {
  2201  		tc := tt
  2202  
  2203  		t.Run(tc.name, func(t *testing.T) {
  2204  			err := tc.module.validateFunction(&stacks{}, api.CoreFeatureMultiValue,
  2205  				0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
  2206  			require.EqualError(t, err, tc.expectedErr)
  2207  		})
  2208  	}
  2209  }
  2210  
  2211  func TestModule_funcValidation_CallIndirect(t *testing.T) {
  2212  	t.Run("ok", func(t *testing.T) {
  2213  		m := &Module{
  2214  			TypeSection:     []FunctionType{v_v},
  2215  			FunctionSection: []Index{0},
  2216  			CodeSection: []Code{{Body: []byte{
  2217  				OpcodeI32Const, 1,
  2218  				OpcodeCallIndirect, 0, 0,
  2219  				OpcodeEnd,
  2220  			}}},
  2221  		}
  2222  		err := m.validateFunction(&stacks{}, api.CoreFeatureReferenceTypes,
  2223  			0, []Index{0}, nil, &Memory{}, []Table{{Type: RefTypeFuncref}}, nil, bytes.NewReader(nil))
  2224  		require.NoError(t, err)
  2225  	})
  2226  	t.Run("non zero table index", func(t *testing.T) {
  2227  		m := &Module{
  2228  			TypeSection:     []FunctionType{v_v},
  2229  			FunctionSection: []Index{0},
  2230  			CodeSection: []Code{{Body: []byte{
  2231  				OpcodeI32Const, 1,
  2232  				OpcodeCallIndirect, 0, 100,
  2233  				OpcodeEnd,
  2234  			}}},
  2235  		}
  2236  		t.Run("disabled", func(t *testing.T) {
  2237  			err := m.validateFunction(&stacks{}, api.CoreFeaturesV1,
  2238  				0, []Index{0}, nil, &Memory{}, []Table{{}, {}}, nil, bytes.NewReader(nil))
  2239  			require.EqualError(t, err, "table index must be zero but was 100: feature \"reference-types\" is disabled")
  2240  		})
  2241  		t.Run("enabled but out of range", func(t *testing.T) {
  2242  			err := m.validateFunction(&stacks{}, api.CoreFeatureReferenceTypes,
  2243  				0, []Index{0}, nil, &Memory{}, []Table{{}, {}}, nil, bytes.NewReader(nil))
  2244  			require.EqualError(t, err, "unknown table index: 100")
  2245  		})
  2246  	})
  2247  	t.Run("non funcref table", func(t *testing.T) {
  2248  		m := &Module{
  2249  			TypeSection:     []FunctionType{v_v},
  2250  			FunctionSection: []Index{0},
  2251  			CodeSection: []Code{{Body: []byte{
  2252  				OpcodeI32Const, 1,
  2253  				OpcodeCallIndirect, 0, 0,
  2254  				OpcodeEnd,
  2255  			}}},
  2256  		}
  2257  		err := m.validateFunction(&stacks{}, api.CoreFeatureReferenceTypes,
  2258  			0, []Index{0}, nil, &Memory{}, []Table{{Type: RefTypeExternref}}, nil, bytes.NewReader(nil))
  2259  		require.EqualError(t, err, "table is not funcref type but was externref for call_indirect")
  2260  	})
  2261  }
  2262  
  2263  func TestModule_funcValidation_RefTypes(t *testing.T) {
  2264  	tests := []struct {
  2265  		name                    string
  2266  		body                    []byte
  2267  		flag                    api.CoreFeatures
  2268  		declaredFunctionIndexes map[Index]struct{}
  2269  		expectedErr             string
  2270  	}{
  2271  		{
  2272  			name: "ref.null (funcref)",
  2273  			flag: api.CoreFeatureReferenceTypes,
  2274  			body: []byte{
  2275  				OpcodeRefNull, ValueTypeFuncref,
  2276  				OpcodeDrop, OpcodeEnd,
  2277  			},
  2278  		},
  2279  		{
  2280  			name: "ref.null (externref)",
  2281  			flag: api.CoreFeatureReferenceTypes,
  2282  			body: []byte{
  2283  				OpcodeRefNull, ValueTypeExternref,
  2284  				OpcodeDrop, OpcodeEnd,
  2285  			},
  2286  		},
  2287  		{
  2288  			name: "ref.null - disabled",
  2289  			flag: api.CoreFeaturesV1,
  2290  			body: []byte{
  2291  				OpcodeRefNull, ValueTypeFuncref,
  2292  				OpcodeDrop, OpcodeEnd,
  2293  			},
  2294  			expectedErr: "ref.null invalid as feature \"reference-types\" is disabled",
  2295  		},
  2296  		{
  2297  			name: "ref.is_null",
  2298  			flag: api.CoreFeatureReferenceTypes,
  2299  			body: []byte{
  2300  				OpcodeRefNull, ValueTypeFuncref,
  2301  				OpcodeRefIsNull,
  2302  				OpcodeDrop, OpcodeEnd,
  2303  			},
  2304  		},
  2305  		{
  2306  			name: "ref.is_null - disabled",
  2307  			flag: api.CoreFeaturesV1,
  2308  			body: []byte{
  2309  				OpcodeRefIsNull,
  2310  				OpcodeDrop, OpcodeEnd,
  2311  			},
  2312  			expectedErr: `ref.is_null invalid as feature "reference-types" is disabled`,
  2313  		},
  2314  		{
  2315  			name:                    "ref.func",
  2316  			flag:                    api.CoreFeatureReferenceTypes,
  2317  			declaredFunctionIndexes: map[uint32]struct{}{0: {}},
  2318  			body: []byte{
  2319  				OpcodeRefFunc, 0,
  2320  				OpcodeDrop, OpcodeEnd,
  2321  			},
  2322  		},
  2323  		{
  2324  			name:                    "ref.func - undeclared function index",
  2325  			flag:                    api.CoreFeatureReferenceTypes,
  2326  			declaredFunctionIndexes: map[uint32]struct{}{0: {}},
  2327  			body: []byte{
  2328  				OpcodeRefFunc, 100,
  2329  				OpcodeDrop, OpcodeEnd,
  2330  			},
  2331  			expectedErr: `undeclared function index 100 for ref.func`,
  2332  		},
  2333  		{
  2334  			name:                    "ref.func",
  2335  			flag:                    api.CoreFeaturesV1,
  2336  			declaredFunctionIndexes: map[uint32]struct{}{0: {}},
  2337  			body: []byte{
  2338  				OpcodeRefFunc, 0,
  2339  				OpcodeDrop, OpcodeEnd,
  2340  			},
  2341  			expectedErr: "ref.func invalid as feature \"reference-types\" is disabled",
  2342  		},
  2343  	}
  2344  
  2345  	for _, tt := range tests {
  2346  		tc := tt
  2347  		t.Run(tc.name, func(t *testing.T) {
  2348  			m := &Module{
  2349  				TypeSection:     []FunctionType{v_v},
  2350  				FunctionSection: []Index{0},
  2351  				CodeSection:     []Code{{Body: tc.body}},
  2352  			}
  2353  			err := m.validateFunction(&stacks{}, tc.flag,
  2354  				0, []Index{0}, nil, nil, nil, tc.declaredFunctionIndexes, bytes.NewReader(nil))
  2355  			if tc.expectedErr != "" {
  2356  				require.EqualError(t, err, tc.expectedErr)
  2357  			} else {
  2358  				require.NoError(t, err)
  2359  			}
  2360  		})
  2361  	}
  2362  }
  2363  
  2364  func TestModule_funcValidation_TableGrowSizeFill(t *testing.T) {
  2365  	tables := []Table{{Type: RefTypeFuncref}, {Type: RefTypeExternref}}
  2366  	tests := []struct {
  2367  		name        string
  2368  		body        []byte
  2369  		flag        api.CoreFeatures
  2370  		expectedErr string
  2371  	}{
  2372  		{
  2373  			name: "table.grow (funcref)",
  2374  			body: []byte{
  2375  				OpcodeRefNull, RefTypeFuncref,
  2376  				OpcodeI32Const, 1, // number of elements
  2377  				OpcodeMiscPrefix, OpcodeMiscTableGrow,
  2378  				0, // Table Index.
  2379  				OpcodeDrop,
  2380  				OpcodeEnd,
  2381  			},
  2382  			flag: api.CoreFeatureReferenceTypes,
  2383  		},
  2384  		{
  2385  			name: "table.grow (funcref) - type mismatch",
  2386  			body: []byte{
  2387  				OpcodeRefNull, RefTypeFuncref,
  2388  				OpcodeI32Const, 1, // number of elements
  2389  				OpcodeMiscPrefix, OpcodeMiscTableGrow,
  2390  				1, // Table of externref type -> mismatch.
  2391  				OpcodeEnd,
  2392  			},
  2393  			flag:        api.CoreFeatureReferenceTypes,
  2394  			expectedErr: `cannot pop the operand for table.grow: type mismatch: expected externref, but was funcref`,
  2395  		},
  2396  		{
  2397  			name: "table.grow (externref)",
  2398  			body: []byte{
  2399  				OpcodeRefNull, RefTypeExternref,
  2400  				OpcodeI32Const, 1, // number of elements
  2401  				OpcodeMiscPrefix, OpcodeMiscTableGrow,
  2402  				1, // Table Index.
  2403  				OpcodeDrop,
  2404  				OpcodeEnd,
  2405  			},
  2406  			flag: api.CoreFeatureReferenceTypes,
  2407  		},
  2408  		{
  2409  			name: "table.grow (externref) type mismatch",
  2410  			body: []byte{
  2411  				OpcodeRefNull, RefTypeExternref,
  2412  				OpcodeI32Const, 1, // number of elements
  2413  				OpcodeMiscPrefix, OpcodeMiscTableGrow,
  2414  				0, // Table of funcref type -> mismatch.
  2415  				OpcodeEnd,
  2416  			},
  2417  			flag:        api.CoreFeatureReferenceTypes,
  2418  			expectedErr: `cannot pop the operand for table.grow: type mismatch: expected funcref, but was externref`,
  2419  		},
  2420  		{
  2421  			name: "table.grow - table not found",
  2422  			body: []byte{
  2423  				OpcodeRefNull, RefTypeFuncref,
  2424  				OpcodeI32Const, 1, // number of elements
  2425  				OpcodeMiscPrefix, OpcodeMiscTableGrow,
  2426  				10, // Table Index.
  2427  				OpcodeEnd,
  2428  			},
  2429  			flag:        api.CoreFeatureReferenceTypes,
  2430  			expectedErr: `table of index 10 not found`,
  2431  		},
  2432  		{
  2433  			name: "table.size - table not found",
  2434  			body: []byte{
  2435  				OpcodeMiscPrefix, OpcodeMiscTableSize,
  2436  				10, // Table Index.
  2437  				OpcodeEnd,
  2438  			},
  2439  			flag:        api.CoreFeatureReferenceTypes,
  2440  			expectedErr: `table of index 10 not found`,
  2441  		},
  2442  		{
  2443  			name: "table.size",
  2444  			body: []byte{
  2445  				OpcodeMiscPrefix, OpcodeMiscTableSize,
  2446  				1, // Table Index.
  2447  				OpcodeDrop,
  2448  				OpcodeEnd,
  2449  			},
  2450  			flag: api.CoreFeatureReferenceTypes,
  2451  		},
  2452  		{
  2453  			name: "table.fill (funcref)",
  2454  			body: []byte{
  2455  				OpcodeI32Const, 1, // offset
  2456  				OpcodeRefNull, RefTypeFuncref,
  2457  				OpcodeI32Const, 1, // number of elements
  2458  				OpcodeMiscPrefix, OpcodeMiscTableFill,
  2459  				0, // Table Index.
  2460  				OpcodeEnd,
  2461  			},
  2462  			flag: api.CoreFeatureReferenceTypes,
  2463  		},
  2464  		{
  2465  			name: "table.fill (funcref) - type mismatch",
  2466  			body: []byte{
  2467  				OpcodeI32Const, 1, // offset
  2468  				OpcodeRefNull, RefTypeFuncref,
  2469  				OpcodeI32Const, 1, // number of elements
  2470  				OpcodeMiscPrefix, OpcodeMiscTableFill,
  2471  				1, // Table of externref type -> mismatch.
  2472  				OpcodeEnd,
  2473  			},
  2474  			flag:        api.CoreFeatureReferenceTypes,
  2475  			expectedErr: `cannot pop the operand for table.fill: type mismatch: expected externref, but was funcref`,
  2476  		},
  2477  		{
  2478  			name: "table.fill (externref)",
  2479  			body: []byte{
  2480  				OpcodeI32Const, 1, // offset
  2481  				OpcodeRefNull, RefTypeExternref,
  2482  				OpcodeI32Const, 1, // number of elements
  2483  				OpcodeMiscPrefix, OpcodeMiscTableFill,
  2484  				1, // Table Index.
  2485  				OpcodeEnd,
  2486  			},
  2487  			flag: api.CoreFeatureReferenceTypes,
  2488  		},
  2489  		{
  2490  			name: "table.fill (externref) - type mismatch",
  2491  			body: []byte{
  2492  				OpcodeI32Const, 1, // offset
  2493  				OpcodeRefNull, RefTypeExternref,
  2494  				OpcodeI32Const, 1, // number of elements
  2495  				OpcodeMiscPrefix, OpcodeMiscTableFill,
  2496  				0, // Table of funcref type -> mismatch.
  2497  				OpcodeEnd,
  2498  			},
  2499  			flag:        api.CoreFeatureReferenceTypes,
  2500  			expectedErr: `cannot pop the operand for table.fill: type mismatch: expected funcref, but was externref`,
  2501  		},
  2502  		{
  2503  			name: "table.fill - table not found",
  2504  			body: []byte{
  2505  				OpcodeMiscPrefix, OpcodeMiscTableFill,
  2506  				10, // Table Index.
  2507  				OpcodeEnd,
  2508  			},
  2509  			flag:        api.CoreFeatureReferenceTypes,
  2510  			expectedErr: `table of index 10 not found`,
  2511  		},
  2512  	}
  2513  
  2514  	for _, tt := range tests {
  2515  		tc := tt
  2516  		t.Run(tc.name, func(t *testing.T) {
  2517  			m := &Module{
  2518  				TypeSection:     []FunctionType{v_v},
  2519  				FunctionSection: []Index{0},
  2520  				CodeSection:     []Code{{Body: tc.body}},
  2521  			}
  2522  			err := m.validateFunction(&stacks{}, tc.flag,
  2523  				0, []Index{0}, nil, nil, tables, nil, bytes.NewReader(nil))
  2524  			if tc.expectedErr != "" {
  2525  				require.EqualError(t, err, tc.expectedErr)
  2526  			} else {
  2527  				require.NoError(t, err)
  2528  			}
  2529  		})
  2530  	}
  2531  }
  2532  
  2533  func TestModule_funcValidation_TableGetSet(t *testing.T) {
  2534  	tables := []Table{{Type: RefTypeFuncref}, {Type: RefTypeExternref}}
  2535  	tests := []struct {
  2536  		name        string
  2537  		body        []byte
  2538  		flag        api.CoreFeatures
  2539  		expectedErr string
  2540  	}{
  2541  		{
  2542  			name: "table.get (funcref)",
  2543  			body: []byte{
  2544  				OpcodeI32Const, 0,
  2545  				OpcodeTableGet, 0,
  2546  				OpcodeRefIsNull,
  2547  				OpcodeDrop,
  2548  				OpcodeEnd,
  2549  			},
  2550  			flag: api.CoreFeatureReferenceTypes,
  2551  		},
  2552  		{
  2553  			name: "table.get (externref)",
  2554  			body: []byte{
  2555  				OpcodeI32Const, 0,
  2556  				OpcodeTableGet, 1,
  2557  				OpcodeRefIsNull,
  2558  				OpcodeDrop,
  2559  				OpcodeEnd,
  2560  			},
  2561  			flag: api.CoreFeatureReferenceTypes,
  2562  		},
  2563  		{
  2564  			name: "table.get (disabled)",
  2565  			body: []byte{
  2566  				OpcodeI32Const, 0,
  2567  				OpcodeTableGet, 0,
  2568  				OpcodeDrop,
  2569  				OpcodeEnd,
  2570  			},
  2571  			flag:        api.CoreFeaturesV1,
  2572  			expectedErr: `table.get is invalid as feature "reference-types" is disabled`,
  2573  		},
  2574  		{
  2575  			name: "table.set (funcref)",
  2576  			body: []byte{
  2577  				OpcodeI32Const, 0,
  2578  				OpcodeRefNull, ValueTypeFuncref,
  2579  				OpcodeTableSet, 0,
  2580  				OpcodeEnd,
  2581  			},
  2582  			flag: api.CoreFeatureReferenceTypes,
  2583  		},
  2584  		{
  2585  			name: "table.set type mismatch (src=funcref, dst=externref)",
  2586  			body: []byte{
  2587  				OpcodeI32Const, 0,
  2588  				OpcodeRefNull, ValueTypeFuncref,
  2589  				OpcodeTableSet, 1,
  2590  				OpcodeEnd,
  2591  			},
  2592  			flag:        api.CoreFeatureReferenceTypes,
  2593  			expectedErr: `cannot pop the operand for table.set: type mismatch: expected externref, but was funcref`,
  2594  		},
  2595  		{
  2596  			name: "table.set (externref)",
  2597  			body: []byte{
  2598  				OpcodeI32Const, 0,
  2599  				OpcodeRefNull, ValueTypeExternref,
  2600  				OpcodeTableSet, 1,
  2601  				OpcodeEnd,
  2602  			},
  2603  			flag: api.CoreFeatureReferenceTypes,
  2604  		},
  2605  		{
  2606  			name: "table.set type mismatch (src=externref, dst=funcref)",
  2607  			body: []byte{
  2608  				OpcodeI32Const, 0,
  2609  				OpcodeRefNull, ValueTypeExternref,
  2610  				OpcodeTableSet, 0,
  2611  				OpcodeEnd,
  2612  			},
  2613  			flag:        api.CoreFeatureReferenceTypes,
  2614  			expectedErr: `cannot pop the operand for table.set: type mismatch: expected funcref, but was externref`,
  2615  		},
  2616  		{
  2617  			name: "table.set (disabled)",
  2618  			body: []byte{
  2619  				OpcodeTableSet, 1,
  2620  				OpcodeEnd,
  2621  			},
  2622  			flag:        api.CoreFeaturesV1,
  2623  			expectedErr: `table.set is invalid as feature "reference-types" is disabled`,
  2624  		},
  2625  	}
  2626  
  2627  	for _, tt := range tests {
  2628  		tc := tt
  2629  		t.Run(tc.name, func(t *testing.T) {
  2630  			m := &Module{
  2631  				TypeSection:     []FunctionType{v_v},
  2632  				FunctionSection: []Index{0},
  2633  				CodeSection:     []Code{{Body: tc.body}},
  2634  			}
  2635  			err := m.validateFunction(&stacks{}, tc.flag,
  2636  				0, []Index{0}, nil, nil, tables, nil, bytes.NewReader(nil))
  2637  			if tc.expectedErr != "" {
  2638  				require.EqualError(t, err, tc.expectedErr)
  2639  			} else {
  2640  				require.NoError(t, err)
  2641  			}
  2642  		})
  2643  	}
  2644  }
  2645  
  2646  func TestModule_funcValidation_Select_error(t *testing.T) {
  2647  	tests := []struct {
  2648  		name        string
  2649  		body        []byte
  2650  		flag        api.CoreFeatures
  2651  		expectedErr string
  2652  	}{
  2653  		{
  2654  			name: "typed_select (disabled)",
  2655  			body: []byte{
  2656  				OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0,
  2657  				OpcodeTypedSelect, 1, ValueTypeI32, // immediate vector's size must be one
  2658  				OpcodeDrop,
  2659  				OpcodeEnd,
  2660  			},
  2661  			flag:        api.CoreFeaturesV1,
  2662  			expectedErr: "typed_select is invalid as feature \"reference-types\" is disabled",
  2663  		},
  2664  		{
  2665  			name: "typed_select (too many immediate types)",
  2666  			body: []byte{
  2667  				OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0,
  2668  				OpcodeTypedSelect, 2, // immediate vector's size must be one
  2669  			},
  2670  			flag:        api.CoreFeatureReferenceTypes,
  2671  			expectedErr: `too many type immediates for typed_select`,
  2672  		},
  2673  		{
  2674  			name: "typed_select (immediate type not found)",
  2675  			body: []byte{
  2676  				OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0,
  2677  				OpcodeTypedSelect, 1, 0,
  2678  				OpcodeEnd,
  2679  			},
  2680  			flag:        api.CoreFeatureReferenceTypes,
  2681  			expectedErr: `invalid type unknown for typed_select`,
  2682  		},
  2683  	}
  2684  
  2685  	for _, tt := range tests {
  2686  		tc := tt
  2687  		t.Run(tc.name, func(t *testing.T) {
  2688  			m := &Module{
  2689  				TypeSection:     []FunctionType{v_v},
  2690  				FunctionSection: []Index{0},
  2691  				CodeSection:     []Code{{Body: tc.body}},
  2692  			}
  2693  			err := m.validateFunction(&stacks{}, tc.flag,
  2694  				0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
  2695  			require.EqualError(t, err, tc.expectedErr)
  2696  		})
  2697  	}
  2698  }
  2699  
  2700  func TestModule_funcValidation_SIMD(t *testing.T) {
  2701  	addV128Const := func(in []byte) []byte {
  2702  		return append(in, OpcodeVecPrefix,
  2703  			OpcodeVecV128Const,
  2704  			1, 1, 1, 1, 1, 1, 1, 1,
  2705  			1, 1, 1, 1, 1, 1, 1, 1)
  2706  	}
  2707  	vv2v := func(vec OpcodeVec) (ret []byte) {
  2708  		ret = addV128Const(ret)
  2709  		ret = addV128Const(ret)
  2710  		return append(ret,
  2711  			OpcodeVecPrefix,
  2712  			vec,
  2713  			OpcodeDrop,
  2714  			OpcodeEnd,
  2715  		)
  2716  	}
  2717  	vvv2v := func(vec OpcodeVec) (ret []byte) {
  2718  		ret = addV128Const(ret)
  2719  		ret = addV128Const(ret)
  2720  		ret = addV128Const(ret)
  2721  		return append(ret,
  2722  			OpcodeVecPrefix,
  2723  			vec,
  2724  			OpcodeDrop,
  2725  			OpcodeEnd,
  2726  		)
  2727  	}
  2728  
  2729  	v2v := func(vec OpcodeVec) (ret []byte) {
  2730  		ret = addV128Const(ret)
  2731  		return append(ret,
  2732  			OpcodeVecPrefix,
  2733  			vec,
  2734  			OpcodeDrop,
  2735  			OpcodeEnd,
  2736  		)
  2737  	}
  2738  
  2739  	vi2v := func(vec OpcodeVec) (ret []byte) {
  2740  		ret = addV128Const(ret)
  2741  		return append(ret,
  2742  			OpcodeI32Const, 1,
  2743  			OpcodeVecPrefix,
  2744  			vec,
  2745  			OpcodeDrop,
  2746  			OpcodeEnd,
  2747  		)
  2748  	}
  2749  
  2750  	load := func(vec OpcodeVec, offset, align uint32) (ret []byte) {
  2751  		ret = []byte{
  2752  			OpcodeI32Const, 1,
  2753  			OpcodeVecPrefix,
  2754  			vec,
  2755  		}
  2756  
  2757  		ret = append(ret, leb128.EncodeUint32(align)...)
  2758  		ret = append(ret, leb128.EncodeUint32(offset)...)
  2759  		ret = append(ret,
  2760  			OpcodeDrop,
  2761  			OpcodeEnd,
  2762  		)
  2763  		return
  2764  	}
  2765  
  2766  	loadLane := func(vec OpcodeVec, offset, align uint32, lane byte) (ret []byte) {
  2767  		ret = addV128Const([]byte{OpcodeI32Const, 1})
  2768  		ret = append(ret,
  2769  			OpcodeVecPrefix,
  2770  			vec,
  2771  		)
  2772  
  2773  		ret = append(ret, leb128.EncodeUint32(align)...)
  2774  		ret = append(ret, leb128.EncodeUint32(offset)...)
  2775  		ret = append(ret,
  2776  			lane,
  2777  			OpcodeDrop,
  2778  			OpcodeEnd,
  2779  		)
  2780  		return
  2781  	}
  2782  
  2783  	storeLane := func(vec OpcodeVec, offset, align uint32, lane byte) (ret []byte) {
  2784  		ret = addV128Const([]byte{OpcodeI32Const, 1})
  2785  		ret = append(ret,
  2786  			OpcodeVecPrefix,
  2787  			vec,
  2788  		)
  2789  		ret = append(ret, leb128.EncodeUint32(align)...)
  2790  		ret = append(ret, leb128.EncodeUint32(offset)...)
  2791  		ret = append(ret,
  2792  			lane,
  2793  			OpcodeEnd,
  2794  		)
  2795  		return
  2796  	}
  2797  
  2798  	extractLane := func(vec OpcodeVec, lane byte) (ret []byte) {
  2799  		ret = addV128Const(ret)
  2800  		ret = append(ret,
  2801  			OpcodeVecPrefix,
  2802  			vec,
  2803  			lane,
  2804  			OpcodeDrop,
  2805  			OpcodeEnd,
  2806  		)
  2807  		return
  2808  	}
  2809  
  2810  	replaceLane := func(vec OpcodeVec, lane byte) (ret []byte) {
  2811  		ret = addV128Const(ret)
  2812  
  2813  		switch vec {
  2814  		case OpcodeVecI8x16ReplaceLane, OpcodeVecI16x8ReplaceLane, OpcodeVecI32x4ReplaceLane:
  2815  			ret = append(ret, OpcodeI32Const, 0)
  2816  		case OpcodeVecI64x2ReplaceLane:
  2817  			ret = append(ret, OpcodeI64Const, 0)
  2818  		case OpcodeVecF32x4ReplaceLane:
  2819  			ret = append(ret, OpcodeF32Const, 0, 0, 0, 0)
  2820  		case OpcodeVecF64x2ReplaceLane:
  2821  			ret = append(ret, OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0)
  2822  		}
  2823  
  2824  		ret = append(ret,
  2825  			OpcodeVecPrefix,
  2826  			vec,
  2827  			lane,
  2828  			OpcodeDrop,
  2829  			OpcodeEnd,
  2830  		)
  2831  		return
  2832  	}
  2833  
  2834  	splat := func(vec OpcodeVec) (ret []byte) {
  2835  		switch vec {
  2836  		case OpcodeVecI8x16Splat, OpcodeVecI16x8Splat, OpcodeVecI32x4Splat:
  2837  			ret = append(ret, OpcodeI32Const, 0, 0, 0, 0)
  2838  		case OpcodeVecI64x2Splat:
  2839  			ret = append(ret, OpcodeI64Const, 0, 0, 0, 0, 0, 0, 0, 0)
  2840  		case OpcodeVecF32x4Splat:
  2841  			ret = append(ret, OpcodeF32Const, 0, 0, 0, 0)
  2842  		case OpcodeVecF64x2Splat:
  2843  			ret = append(ret, OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0)
  2844  		}
  2845  
  2846  		ret = append(ret,
  2847  			OpcodeVecPrefix,
  2848  			vec,
  2849  			OpcodeDrop,
  2850  			OpcodeEnd,
  2851  		)
  2852  		return
  2853  	}
  2854  
  2855  	tests := []struct {
  2856  		name        string
  2857  		body        []byte
  2858  		expectedErr string
  2859  	}{
  2860  		{
  2861  			name: "v128.const",
  2862  			body: []byte{
  2863  				OpcodeVecPrefix,
  2864  				OpcodeVecV128Const,
  2865  				1, 1, 1, 1, 1, 1, 1, 1,
  2866  				1, 1, 1, 1, 1, 1, 1, 1,
  2867  				OpcodeDrop,
  2868  				OpcodeEnd,
  2869  			},
  2870  		},
  2871  		{name: OpcodeVecI8x16AddName, body: vv2v(OpcodeVecI8x16Add)},
  2872  		{name: OpcodeVecI16x8AddName, body: vv2v(OpcodeVecI16x8Add)},
  2873  		{name: OpcodeVecI32x4AddName, body: vv2v(OpcodeVecI32x4Add)},
  2874  		{name: OpcodeVecI64x2AddName, body: vv2v(OpcodeVecI64x2Add)},
  2875  		{name: OpcodeVecI8x16SubName, body: vv2v(OpcodeVecI8x16Sub)},
  2876  		{name: OpcodeVecI16x8SubName, body: vv2v(OpcodeVecI16x8Sub)},
  2877  		{name: OpcodeVecI32x4SubName, body: vv2v(OpcodeVecI32x4Sub)},
  2878  		{name: OpcodeVecI64x2SubName, body: vv2v(OpcodeVecI64x2Sub)},
  2879  		{name: OpcodeVecV128AnyTrueName, body: v2v(OpcodeVecV128AnyTrue)},
  2880  		{name: OpcodeVecI8x16AllTrueName, body: v2v(OpcodeVecI8x16AllTrue)},
  2881  		{name: OpcodeVecI16x8AllTrueName, body: v2v(OpcodeVecI16x8AllTrue)},
  2882  		{name: OpcodeVecI32x4AllTrueName, body: v2v(OpcodeVecI32x4AllTrue)},
  2883  		{name: OpcodeVecI64x2AllTrueName, body: v2v(OpcodeVecI64x2AllTrue)},
  2884  		{name: OpcodeVecI8x16BitMaskName, body: v2v(OpcodeVecI8x16BitMask)},
  2885  		{name: OpcodeVecI16x8BitMaskName, body: v2v(OpcodeVecI16x8BitMask)},
  2886  		{name: OpcodeVecI32x4BitMaskName, body: v2v(OpcodeVecI32x4BitMask)},
  2887  		{name: OpcodeVecI64x2BitMaskName, body: v2v(OpcodeVecI64x2BitMask)},
  2888  		{name: OpcodeVecV128LoadName, body: load(OpcodeVecV128Load, 0, 0)},
  2889  		{name: OpcodeVecV128LoadName + "/align=4", body: load(OpcodeVecV128Load, 0, 4)},
  2890  		{name: OpcodeVecV128Load8x8SName, body: load(OpcodeVecV128Load8x8s, 1, 0)},
  2891  		{name: OpcodeVecV128Load8x8SName + "/align=1", body: load(OpcodeVecV128Load8x8s, 0, 1)},
  2892  		{name: OpcodeVecV128Load8x8UName, body: load(OpcodeVecV128Load8x8u, 0, 0)},
  2893  		{name: OpcodeVecV128Load8x8UName + "/align=1", body: load(OpcodeVecV128Load8x8u, 0, 1)},
  2894  		{name: OpcodeVecV128Load16x4SName, body: load(OpcodeVecV128Load16x4s, 1, 0)},
  2895  		{name: OpcodeVecV128Load16x4SName + "/align=2", body: load(OpcodeVecV128Load16x4s, 0, 2)},
  2896  		{name: OpcodeVecV128Load16x4UName, body: load(OpcodeVecV128Load16x4u, 0, 0)},
  2897  		{name: OpcodeVecV128Load16x4UName + "/align=2", body: load(OpcodeVecV128Load16x4u, 0, 2)},
  2898  		{name: OpcodeVecV128Load32x2SName, body: load(OpcodeVecV128Load32x2s, 1, 0)},
  2899  		{name: OpcodeVecV128Load32x2SName + "/align=3", body: load(OpcodeVecV128Load32x2s, 0, 3)},
  2900  		{name: OpcodeVecV128Load32x2UName, body: load(OpcodeVecV128Load32x2u, 0, 0)},
  2901  		{name: OpcodeVecV128Load32x2UName + "/align=3", body: load(OpcodeVecV128Load32x2u, 0, 3)},
  2902  		{name: OpcodeVecV128Load8SplatName, body: load(OpcodeVecV128Load8Splat, 2, 0)},
  2903  		{name: OpcodeVecV128Load16SplatName, body: load(OpcodeVecV128Load16Splat, 0, 1)},
  2904  		{name: OpcodeVecV128Load32SplatName, body: load(OpcodeVecV128Load32Splat, 3, 2)},
  2905  		{name: OpcodeVecV128Load64SplatName, body: load(OpcodeVecV128Load64Splat, 0, 3)},
  2906  		{name: OpcodeVecV128Load32zeroName, body: load(OpcodeVecV128Load32zero, 0, 2)},
  2907  		{name: OpcodeVecV128Load64zeroName, body: load(OpcodeVecV128Load64zero, 5, 3)},
  2908  		{name: OpcodeVecV128Load8LaneName, body: loadLane(OpcodeVecV128Load8Lane, 5, 0, 10)},
  2909  		{name: OpcodeVecV128Load16LaneName, body: loadLane(OpcodeVecV128Load16Lane, 100, 1, 7)},
  2910  		{name: OpcodeVecV128Load32LaneName, body: loadLane(OpcodeVecV128Load32Lane, 0, 2, 3)},
  2911  		{name: OpcodeVecV128Load64LaneName, body: loadLane(OpcodeVecV128Load64Lane, 0, 3, 1)},
  2912  		{
  2913  			name: OpcodeVecV128StoreName, body: []byte{
  2914  				OpcodeI32Const,
  2915  				1, 1, 1, 1,
  2916  				OpcodeVecPrefix,
  2917  				OpcodeVecV128Const,
  2918  				1, 1, 1, 1, 1, 1, 1, 1,
  2919  				1, 1, 1, 1, 1, 1, 1, 1,
  2920  				OpcodeVecPrefix,
  2921  				OpcodeVecV128Store,
  2922  				4,  // alignment
  2923  				10, // offset
  2924  				OpcodeEnd,
  2925  			},
  2926  		},
  2927  		{name: OpcodeVecV128Store8LaneName, body: storeLane(OpcodeVecV128Store8Lane, 0, 0, 0)},
  2928  		{name: OpcodeVecV128Store8LaneName + "/lane=15", body: storeLane(OpcodeVecV128Store8Lane, 100, 0, 15)},
  2929  		{name: OpcodeVecV128Store16LaneName, body: storeLane(OpcodeVecV128Store16Lane, 0, 0, 0)},
  2930  		{name: OpcodeVecV128Store16LaneName + "/lane=7/align=1", body: storeLane(OpcodeVecV128Store16Lane, 100, 1, 7)},
  2931  		{name: OpcodeVecV128Store32LaneName, body: storeLane(OpcodeVecV128Store32Lane, 0, 0, 0)},
  2932  		{name: OpcodeVecV128Store32LaneName + "/lane=3/align=2", body: storeLane(OpcodeVecV128Store32Lane, 100, 2, 3)},
  2933  		{name: OpcodeVecV128Store64LaneName, body: storeLane(OpcodeVecV128Store64Lane, 0, 0, 0)},
  2934  		{name: OpcodeVecV128Store64LaneName + "/lane=1/align=3", body: storeLane(OpcodeVecV128Store64Lane, 50, 3, 1)},
  2935  		{name: OpcodeVecI8x16ExtractLaneSName, body: extractLane(OpcodeVecI8x16ExtractLaneS, 0)},
  2936  		{name: OpcodeVecI8x16ExtractLaneSName + "/lane=15", body: extractLane(OpcodeVecI8x16ExtractLaneS, 15)},
  2937  		{name: OpcodeVecI8x16ExtractLaneUName, body: extractLane(OpcodeVecI8x16ExtractLaneU, 0)},
  2938  		{name: OpcodeVecI8x16ExtractLaneUName + "/lane=15", body: extractLane(OpcodeVecI8x16ExtractLaneU, 15)},
  2939  		{name: OpcodeVecI16x8ExtractLaneSName, body: extractLane(OpcodeVecI16x8ExtractLaneS, 0)},
  2940  		{name: OpcodeVecI16x8ExtractLaneSName + "/lane=7", body: extractLane(OpcodeVecI16x8ExtractLaneS, 7)},
  2941  		{name: OpcodeVecI16x8ExtractLaneUName, body: extractLane(OpcodeVecI16x8ExtractLaneU, 0)},
  2942  		{name: OpcodeVecI16x8ExtractLaneUName + "/lane=8", body: extractLane(OpcodeVecI16x8ExtractLaneU, 7)},
  2943  		{name: OpcodeVecI32x4ExtractLaneName, body: extractLane(OpcodeVecI32x4ExtractLane, 0)},
  2944  		{name: OpcodeVecI32x4ExtractLaneName + "/lane=3", body: extractLane(OpcodeVecI32x4ExtractLane, 3)},
  2945  		{name: OpcodeVecI64x2ExtractLaneName, body: extractLane(OpcodeVecI64x2ExtractLane, 0)},
  2946  		{name: OpcodeVecI64x2ExtractLaneName + "/lane=1", body: extractLane(OpcodeVecI64x2ExtractLane, 1)},
  2947  		{name: OpcodeVecF32x4ExtractLaneName, body: extractLane(OpcodeVecF32x4ExtractLane, 0)},
  2948  		{name: OpcodeVecF32x4ExtractLaneName + "/lane=3", body: extractLane(OpcodeVecF32x4ExtractLane, 3)},
  2949  		{name: OpcodeVecF64x2ExtractLaneName, body: extractLane(OpcodeVecF64x2ExtractLane, 0)},
  2950  		{name: OpcodeVecF64x2ExtractLaneName + "/lane=1", body: extractLane(OpcodeVecF64x2ExtractLane, 1)},
  2951  		{name: OpcodeVecI8x16ReplaceLaneName, body: replaceLane(OpcodeVecI8x16ReplaceLane, 0)},
  2952  		{name: OpcodeVecI8x16ReplaceLaneName + "/lane=15", body: replaceLane(OpcodeVecI8x16ReplaceLane, 15)},
  2953  		{name: OpcodeVecI16x8ReplaceLaneName, body: replaceLane(OpcodeVecI16x8ReplaceLane, 0)},
  2954  		{name: OpcodeVecI16x8ReplaceLaneName + "/lane=7", body: replaceLane(OpcodeVecI16x8ReplaceLane, 7)},
  2955  		{name: OpcodeVecI32x4ReplaceLaneName, body: replaceLane(OpcodeVecI32x4ReplaceLane, 0)},
  2956  		{name: OpcodeVecI32x4ReplaceLaneName + "/lane=3", body: replaceLane(OpcodeVecI32x4ReplaceLane, 3)},
  2957  		{name: OpcodeVecI64x2ReplaceLaneName, body: replaceLane(OpcodeVecI64x2ReplaceLane, 0)},
  2958  		{name: OpcodeVecI64x2ReplaceLaneName + "/lane=1", body: replaceLane(OpcodeVecI64x2ReplaceLane, 1)},
  2959  		{name: OpcodeVecF32x4ReplaceLaneName, body: replaceLane(OpcodeVecF32x4ReplaceLane, 0)},
  2960  		{name: OpcodeVecF32x4ReplaceLaneName + "/lane=3", body: replaceLane(OpcodeVecF32x4ReplaceLane, 3)},
  2961  		{name: OpcodeVecF64x2ReplaceLaneName, body: replaceLane(OpcodeVecF64x2ReplaceLane, 0)},
  2962  		{name: OpcodeVecF64x2ReplaceLaneName + "/lane=1", body: replaceLane(OpcodeVecF64x2ReplaceLane, 1)},
  2963  		{name: OpcodeVecI8x16SplatName, body: splat(OpcodeVecI8x16Splat)},
  2964  		{name: OpcodeVecI16x8SplatName, body: splat(OpcodeVecI16x8Splat)},
  2965  		{name: OpcodeVecI32x4SplatName, body: splat(OpcodeVecI32x4Splat)},
  2966  		{name: OpcodeVecI64x2SplatName, body: splat(OpcodeVecI64x2Splat)},
  2967  		{name: OpcodeVecF32x4SplatName, body: splat(OpcodeVecF32x4Splat)},
  2968  		{name: OpcodeVecF64x2SplatName, body: splat(OpcodeVecF64x2Splat)},
  2969  		{name: OpcodeVecI8x16SwizzleName, body: vv2v(OpcodeVecI8x16Swizzle)},
  2970  		{
  2971  			name: OpcodeVecV128i8x16ShuffleName, body: []byte{
  2972  				OpcodeVecPrefix,
  2973  				OpcodeVecV128Const,
  2974  				1, 1, 1, 1, 1, 1, 1, 1,
  2975  				1, 1, 1, 1, 1, 1, 1, 1,
  2976  				OpcodeVecPrefix,
  2977  				OpcodeVecV128Const,
  2978  				1, 1, 1, 1, 1, 1, 1, 1,
  2979  				1, 1, 1, 1, 1, 1, 1, 1,
  2980  				OpcodeVecPrefix,
  2981  				OpcodeVecV128i8x16Shuffle,
  2982  				1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
  2983  				OpcodeDrop,
  2984  				OpcodeEnd,
  2985  			},
  2986  		},
  2987  		{name: OpcodeVecV128NotName, body: v2v(OpcodeVecV128Not)},
  2988  		{name: OpcodeVecV128AndName, body: vv2v(OpcodeVecV128And)},
  2989  		{name: OpcodeVecV128AndNotName, body: vv2v(OpcodeVecV128AndNot)},
  2990  		{name: OpcodeVecV128OrName, body: vv2v(OpcodeVecV128Or)},
  2991  		{name: OpcodeVecV128XorName, body: vv2v(OpcodeVecV128Xor)},
  2992  		{name: OpcodeVecV128BitselectName, body: vvv2v(OpcodeVecV128Bitselect)},
  2993  		{name: OpcodeVecI8x16ShlName, body: vi2v(OpcodeVecI8x16Shl)},
  2994  		{name: OpcodeVecI8x16ShrSName, body: vi2v(OpcodeVecI8x16ShrS)},
  2995  		{name: OpcodeVecI8x16ShrUName, body: vi2v(OpcodeVecI8x16ShrU)},
  2996  		{name: OpcodeVecI16x8ShlName, body: vi2v(OpcodeVecI16x8Shl)},
  2997  		{name: OpcodeVecI16x8ShrSName, body: vi2v(OpcodeVecI16x8ShrS)},
  2998  		{name: OpcodeVecI16x8ShrUName, body: vi2v(OpcodeVecI16x8ShrU)},
  2999  		{name: OpcodeVecI32x4ShlName, body: vi2v(OpcodeVecI32x4Shl)},
  3000  		{name: OpcodeVecI32x4ShrSName, body: vi2v(OpcodeVecI32x4ShrS)},
  3001  		{name: OpcodeVecI32x4ShrUName, body: vi2v(OpcodeVecI32x4ShrU)},
  3002  		{name: OpcodeVecI64x2ShlName, body: vi2v(OpcodeVecI64x2Shl)},
  3003  		{name: OpcodeVecI64x2ShrSName, body: vi2v(OpcodeVecI64x2ShrS)},
  3004  		{name: OpcodeVecI64x2ShrUName, body: vi2v(OpcodeVecI64x2ShrU)},
  3005  		{name: OpcodeVecI8x16EqName, body: vv2v(OpcodeVecI8x16Eq)},
  3006  		{name: OpcodeVecI8x16NeName, body: vv2v(OpcodeVecI8x16Ne)},
  3007  		{name: OpcodeVecI8x16LtSName, body: vv2v(OpcodeVecI8x16LtS)},
  3008  		{name: OpcodeVecI8x16LtUName, body: vv2v(OpcodeVecI8x16LtU)},
  3009  		{name: OpcodeVecI8x16GtSName, body: vv2v(OpcodeVecI8x16GtS)},
  3010  		{name: OpcodeVecI8x16GtUName, body: vv2v(OpcodeVecI8x16GtU)},
  3011  		{name: OpcodeVecI8x16LeSName, body: vv2v(OpcodeVecI8x16LeS)},
  3012  		{name: OpcodeVecI8x16LeUName, body: vv2v(OpcodeVecI8x16LeU)},
  3013  		{name: OpcodeVecI8x16GeSName, body: vv2v(OpcodeVecI8x16GeS)},
  3014  		{name: OpcodeVecI8x16GeUName, body: vv2v(OpcodeVecI8x16GeU)},
  3015  		{name: OpcodeVecI16x8EqName, body: vv2v(OpcodeVecI16x8Eq)},
  3016  		{name: OpcodeVecI16x8NeName, body: vv2v(OpcodeVecI16x8Ne)},
  3017  		{name: OpcodeVecI16x8LtSName, body: vv2v(OpcodeVecI16x8LtS)},
  3018  		{name: OpcodeVecI16x8LtUName, body: vv2v(OpcodeVecI16x8LtU)},
  3019  		{name: OpcodeVecI16x8GtSName, body: vv2v(OpcodeVecI16x8GtS)},
  3020  		{name: OpcodeVecI16x8GtUName, body: vv2v(OpcodeVecI16x8GtU)},
  3021  		{name: OpcodeVecI16x8LeSName, body: vv2v(OpcodeVecI16x8LeS)},
  3022  		{name: OpcodeVecI16x8LeUName, body: vv2v(OpcodeVecI16x8LeU)},
  3023  		{name: OpcodeVecI16x8GeSName, body: vv2v(OpcodeVecI16x8GeS)},
  3024  		{name: OpcodeVecI16x8GeUName, body: vv2v(OpcodeVecI16x8GeU)},
  3025  		{name: OpcodeVecI32x4EqName, body: vv2v(OpcodeVecI32x4Eq)},
  3026  		{name: OpcodeVecI32x4NeName, body: vv2v(OpcodeVecI32x4Ne)},
  3027  		{name: OpcodeVecI32x4LtSName, body: vv2v(OpcodeVecI32x4LtS)},
  3028  		{name: OpcodeVecI32x4LtUName, body: vv2v(OpcodeVecI32x4LtU)},
  3029  		{name: OpcodeVecI32x4GtSName, body: vv2v(OpcodeVecI32x4GtS)},
  3030  		{name: OpcodeVecI32x4GtUName, body: vv2v(OpcodeVecI32x4GtU)},
  3031  		{name: OpcodeVecI32x4LeSName, body: vv2v(OpcodeVecI32x4LeS)},
  3032  		{name: OpcodeVecI32x4LeUName, body: vv2v(OpcodeVecI32x4LeU)},
  3033  		{name: OpcodeVecI32x4GeSName, body: vv2v(OpcodeVecI32x4GeS)},
  3034  		{name: OpcodeVecI32x4GeUName, body: vv2v(OpcodeVecI32x4GeU)},
  3035  		{name: OpcodeVecI64x2EqName, body: vv2v(OpcodeVecI64x2Eq)},
  3036  		{name: OpcodeVecI64x2NeName, body: vv2v(OpcodeVecI64x2Ne)},
  3037  		{name: OpcodeVecI64x2LtSName, body: vv2v(OpcodeVecI64x2LtS)},
  3038  		{name: OpcodeVecI64x2GtSName, body: vv2v(OpcodeVecI64x2GtS)},
  3039  		{name: OpcodeVecI64x2LeSName, body: vv2v(OpcodeVecI64x2LeS)},
  3040  		{name: OpcodeVecI64x2GeSName, body: vv2v(OpcodeVecI64x2GeS)},
  3041  		{name: OpcodeVecF32x4EqName, body: vv2v(OpcodeVecF32x4Eq)},
  3042  		{name: OpcodeVecF32x4NeName, body: vv2v(OpcodeVecF32x4Ne)},
  3043  		{name: OpcodeVecF32x4LtName, body: vv2v(OpcodeVecF32x4Lt)},
  3044  		{name: OpcodeVecF32x4GtName, body: vv2v(OpcodeVecF32x4Gt)},
  3045  		{name: OpcodeVecF32x4LeName, body: vv2v(OpcodeVecF32x4Le)},
  3046  		{name: OpcodeVecF32x4GeName, body: vv2v(OpcodeVecF32x4Ge)},
  3047  		{name: OpcodeVecF64x2EqName, body: vv2v(OpcodeVecF64x2Eq)},
  3048  		{name: OpcodeVecF64x2NeName, body: vv2v(OpcodeVecF64x2Ne)},
  3049  		{name: OpcodeVecF64x2LtName, body: vv2v(OpcodeVecF64x2Lt)},
  3050  		{name: OpcodeVecF64x2GtName, body: vv2v(OpcodeVecF64x2Gt)},
  3051  		{name: OpcodeVecF64x2LeName, body: vv2v(OpcodeVecF64x2Le)},
  3052  		{name: OpcodeVecF64x2GeName, body: vv2v(OpcodeVecF64x2Ge)},
  3053  		{name: OpcodeVecI8x16AddName, body: vv2v(OpcodeVecI8x16Add)},
  3054  		{name: OpcodeVecI8x16AddSatSName, body: vv2v(OpcodeVecI8x16AddSatS)},
  3055  		{name: OpcodeVecI8x16AddSatUName, body: vv2v(OpcodeVecI8x16AddSatU)},
  3056  		{name: OpcodeVecI8x16SubName, body: vv2v(OpcodeVecI8x16Sub)},
  3057  		{name: OpcodeVecI8x16SubSatSName, body: vv2v(OpcodeVecI8x16SubSatS)},
  3058  		{name: OpcodeVecI8x16SubSatUName, body: vv2v(OpcodeVecI8x16SubSatU)},
  3059  		{name: OpcodeVecI16x8AddName, body: vv2v(OpcodeVecI16x8Add)},
  3060  		{name: OpcodeVecI16x8AddSatSName, body: vv2v(OpcodeVecI16x8AddSatS)},
  3061  		{name: OpcodeVecI16x8AddSatUName, body: vv2v(OpcodeVecI16x8AddSatU)},
  3062  		{name: OpcodeVecI16x8SubName, body: vv2v(OpcodeVecI16x8Sub)},
  3063  		{name: OpcodeVecI16x8SubSatSName, body: vv2v(OpcodeVecI16x8SubSatS)},
  3064  		{name: OpcodeVecI16x8SubSatUName, body: vv2v(OpcodeVecI16x8SubSatU)},
  3065  		{name: OpcodeVecI16x8MulName, body: vv2v(OpcodeVecI16x8Mul)},
  3066  		{name: OpcodeVecI32x4AddName, body: vv2v(OpcodeVecI32x4Add)},
  3067  		{name: OpcodeVecI32x4SubName, body: vv2v(OpcodeVecI32x4Sub)},
  3068  		{name: OpcodeVecI32x4MulName, body: vv2v(OpcodeVecI32x4Mul)},
  3069  		{name: OpcodeVecI64x2AddName, body: vv2v(OpcodeVecI64x2Add)},
  3070  		{name: OpcodeVecI64x2SubName, body: vv2v(OpcodeVecI64x2Sub)},
  3071  		{name: OpcodeVecI64x2MulName, body: vv2v(OpcodeVecI64x2Mul)},
  3072  		{name: OpcodeVecF32x4AddName, body: vv2v(OpcodeVecF32x4Add)},
  3073  		{name: OpcodeVecF32x4SubName, body: vv2v(OpcodeVecF32x4Sub)},
  3074  		{name: OpcodeVecF32x4MulName, body: vv2v(OpcodeVecF32x4Mul)},
  3075  		{name: OpcodeVecF32x4DivName, body: vv2v(OpcodeVecF32x4Div)},
  3076  		{name: OpcodeVecF64x2AddName, body: vv2v(OpcodeVecF64x2Add)},
  3077  		{name: OpcodeVecF64x2SubName, body: vv2v(OpcodeVecF64x2Sub)},
  3078  		{name: OpcodeVecF64x2MulName, body: vv2v(OpcodeVecF64x2Mul)},
  3079  		{name: OpcodeVecF64x2DivName, body: vv2v(OpcodeVecF64x2Div)},
  3080  		{name: OpcodeVecI8x16NegName, body: v2v(OpcodeVecI8x16Neg)},
  3081  		{name: OpcodeVecI16x8NegName, body: v2v(OpcodeVecI16x8Neg)},
  3082  		{name: OpcodeVecI32x4NegName, body: v2v(OpcodeVecI32x4Neg)},
  3083  		{name: OpcodeVecI64x2NegName, body: v2v(OpcodeVecI64x2Neg)},
  3084  		{name: OpcodeVecF32x4NegName, body: v2v(OpcodeVecF32x4Neg)},
  3085  		{name: OpcodeVecF64x2NegName, body: v2v(OpcodeVecF64x2Neg)},
  3086  		{name: OpcodeVecF32x4SqrtName, body: v2v(OpcodeVecF32x4Sqrt)},
  3087  		{name: OpcodeVecF64x2SqrtName, body: v2v(OpcodeVecF64x2Sqrt)},
  3088  		{name: OpcodeVecI8x16MinSName, body: vv2v(OpcodeVecI8x16MinS)},
  3089  		{name: OpcodeVecI8x16MinUName, body: vv2v(OpcodeVecI8x16MinU)},
  3090  		{name: OpcodeVecI8x16MaxSName, body: vv2v(OpcodeVecI8x16MaxS)},
  3091  		{name: OpcodeVecI8x16MaxUName, body: vv2v(OpcodeVecI8x16MaxU)},
  3092  		{name: OpcodeVecI8x16AvgrUName, body: vv2v(OpcodeVecI8x16AvgrU)},
  3093  		{name: OpcodeVecI8x16AbsName, body: v2v(OpcodeVecI8x16Abs)},
  3094  		{name: OpcodeVecI8x16PopcntName, body: v2v(OpcodeVecI8x16Popcnt)},
  3095  		{name: OpcodeVecI16x8MinSName, body: vv2v(OpcodeVecI16x8MinS)},
  3096  		{name: OpcodeVecI16x8MinUName, body: vv2v(OpcodeVecI16x8MinU)},
  3097  		{name: OpcodeVecI16x8MaxSName, body: vv2v(OpcodeVecI16x8MaxS)},
  3098  		{name: OpcodeVecI16x8MaxUName, body: vv2v(OpcodeVecI16x8MaxU)},
  3099  		{name: OpcodeVecI16x8AvgrUName, body: vv2v(OpcodeVecI16x8AvgrU)},
  3100  		{name: OpcodeVecI16x8AbsName, body: v2v(OpcodeVecI16x8Abs)},
  3101  		{name: OpcodeVecI32x4MinSName, body: vv2v(OpcodeVecI32x4MinS)},
  3102  		{name: OpcodeVecI32x4MinUName, body: vv2v(OpcodeVecI32x4MinU)},
  3103  		{name: OpcodeVecI32x4MaxSName, body: vv2v(OpcodeVecI32x4MaxS)},
  3104  		{name: OpcodeVecI32x4MaxUName, body: vv2v(OpcodeVecI32x4MaxU)},
  3105  		{name: OpcodeVecI32x4AbsName, body: v2v(OpcodeVecI32x4Abs)},
  3106  		{name: OpcodeVecI64x2AbsName, body: v2v(OpcodeVecI64x2Abs)},
  3107  		{name: OpcodeVecF32x4AbsName, body: v2v(OpcodeVecF32x4Abs)},
  3108  		{name: OpcodeVecF64x2AbsName, body: v2v(OpcodeVecF64x2Abs)},
  3109  		{name: OpcodeVecF32x4MinName, body: vv2v(OpcodeVecF32x4Min)},
  3110  		{name: OpcodeVecF32x4MaxName, body: vv2v(OpcodeVecF32x4Max)},
  3111  		{name: OpcodeVecF64x2MinName, body: vv2v(OpcodeVecF64x2Min)},
  3112  		{name: OpcodeVecF64x2MaxName, body: vv2v(OpcodeVecF64x2Max)},
  3113  		{name: OpcodeVecF32x4CeilName, body: v2v(OpcodeVecF32x4Ceil)},
  3114  		{name: OpcodeVecF32x4FloorName, body: v2v(OpcodeVecF32x4Floor)},
  3115  		{name: OpcodeVecF32x4TruncName, body: v2v(OpcodeVecF32x4Trunc)},
  3116  		{name: OpcodeVecF32x4NearestName, body: v2v(OpcodeVecF32x4Nearest)},
  3117  		{name: OpcodeVecF64x2CeilName, body: v2v(OpcodeVecF64x2Ceil)},
  3118  		{name: OpcodeVecF64x2FloorName, body: v2v(OpcodeVecF64x2Floor)},
  3119  		{name: OpcodeVecF64x2TruncName, body: v2v(OpcodeVecF64x2Trunc)},
  3120  		{name: OpcodeVecF64x2NearestName, body: v2v(OpcodeVecF64x2Nearest)},
  3121  		{name: OpcodeVecF32x4MinName, body: vv2v(OpcodeVecF32x4Pmin)},
  3122  		{name: OpcodeVecF32x4MaxName, body: vv2v(OpcodeVecF32x4Pmax)},
  3123  		{name: OpcodeVecF64x2MinName, body: vv2v(OpcodeVecF64x2Pmin)},
  3124  		{name: OpcodeVecF64x2MaxName, body: vv2v(OpcodeVecF64x2Pmax)},
  3125  		{name: OpcodeVecI16x8ExtendLowI8x16SName, body: v2v(OpcodeVecI16x8ExtendLowI8x16S)},
  3126  		{name: OpcodeVecI16x8ExtendHighI8x16SName, body: v2v(OpcodeVecI16x8ExtendHighI8x16S)},
  3127  		{name: OpcodeVecI16x8ExtendLowI8x16UName, body: v2v(OpcodeVecI16x8ExtendLowI8x16U)},
  3128  		{name: OpcodeVecI16x8ExtendHighI8x16UName, body: v2v(OpcodeVecI16x8ExtendHighI8x16U)},
  3129  		{name: OpcodeVecI32x4ExtendLowI16x8SName, body: v2v(OpcodeVecI32x4ExtendLowI16x8S)},
  3130  		{name: OpcodeVecI32x4ExtendHighI16x8SName, body: v2v(OpcodeVecI32x4ExtendHighI16x8S)},
  3131  		{name: OpcodeVecI32x4ExtendLowI16x8UName, body: v2v(OpcodeVecI32x4ExtendLowI16x8U)},
  3132  		{name: OpcodeVecI32x4ExtendHighI16x8UName, body: v2v(OpcodeVecI32x4ExtendHighI16x8U)},
  3133  		{name: OpcodeVecI64x2ExtendLowI32x4SName, body: v2v(OpcodeVecI64x2ExtendLowI32x4S)},
  3134  		{name: OpcodeVecI64x2ExtendHighI32x4SName, body: v2v(OpcodeVecI64x2ExtendHighI32x4S)},
  3135  		{name: OpcodeVecI64x2ExtendLowI32x4UName, body: v2v(OpcodeVecI64x2ExtendLowI32x4U)},
  3136  		{name: OpcodeVecI64x2ExtendHighI32x4UName, body: v2v(OpcodeVecI64x2ExtendHighI32x4U)},
  3137  		{name: OpcodeVecI16x8Q15mulrSatSName, body: vv2v(OpcodeVecI16x8Q15mulrSatS)},
  3138  		{name: OpcodeVecI16x8ExtMulLowI8x16SName, body: vv2v(OpcodeVecI16x8ExtMulLowI8x16S)},
  3139  		{name: OpcodeVecI16x8ExtMulHighI8x16SName, body: vv2v(OpcodeVecI16x8ExtMulHighI8x16S)},
  3140  		{name: OpcodeVecI16x8ExtMulLowI8x16UName, body: vv2v(OpcodeVecI16x8ExtMulLowI8x16U)},
  3141  		{name: OpcodeVecI16x8ExtMulHighI8x16UName, body: vv2v(OpcodeVecI16x8ExtMulHighI8x16U)},
  3142  		{name: OpcodeVecI32x4ExtMulLowI16x8SName, body: vv2v(OpcodeVecI32x4ExtMulLowI16x8S)},
  3143  		{name: OpcodeVecI32x4ExtMulHighI16x8SName, body: vv2v(OpcodeVecI32x4ExtMulHighI16x8S)},
  3144  		{name: OpcodeVecI32x4ExtMulLowI16x8UName, body: vv2v(OpcodeVecI32x4ExtMulLowI16x8U)},
  3145  		{name: OpcodeVecI32x4ExtMulHighI16x8UName, body: vv2v(OpcodeVecI32x4ExtMulHighI16x8U)},
  3146  		{name: OpcodeVecI64x2ExtMulLowI32x4SName, body: vv2v(OpcodeVecI64x2ExtMulLowI32x4S)},
  3147  		{name: OpcodeVecI64x2ExtMulHighI32x4SName, body: vv2v(OpcodeVecI64x2ExtMulHighI32x4S)},
  3148  		{name: OpcodeVecI64x2ExtMulLowI32x4UName, body: vv2v(OpcodeVecI64x2ExtMulLowI32x4U)},
  3149  		{name: OpcodeVecI64x2ExtMulHighI32x4UName, body: vv2v(OpcodeVecI64x2ExtMulHighI32x4U)},
  3150  		{name: OpcodeVecI16x8ExtaddPairwiseI8x16SName, body: v2v(OpcodeVecI16x8ExtaddPairwiseI8x16S)},
  3151  		{name: OpcodeVecI16x8ExtaddPairwiseI8x16UName, body: v2v(OpcodeVecI16x8ExtaddPairwiseI8x16U)},
  3152  		{name: OpcodeVecI32x4ExtaddPairwiseI16x8SName, body: v2v(OpcodeVecI32x4ExtaddPairwiseI16x8S)},
  3153  		{name: OpcodeVecI32x4ExtaddPairwiseI16x8UName, body: v2v(OpcodeVecI32x4ExtaddPairwiseI16x8U)},
  3154  		{name: OpcodeVecF64x2PromoteLowF32x4ZeroName, body: v2v(OpcodeVecF64x2PromoteLowF32x4Zero)},
  3155  		{name: OpcodeVecF32x4DemoteF64x2ZeroName, body: v2v(OpcodeVecF32x4DemoteF64x2Zero)},
  3156  		{name: OpcodeVecF32x4ConvertI32x4SName, body: v2v(OpcodeVecF32x4ConvertI32x4S)},
  3157  		{name: OpcodeVecF32x4ConvertI32x4UName, body: v2v(OpcodeVecF32x4ConvertI32x4U)},
  3158  		{name: OpcodeVecF64x2ConvertLowI32x4SName, body: v2v(OpcodeVecF64x2ConvertLowI32x4S)},
  3159  		{name: OpcodeVecF64x2ConvertLowI32x4UName, body: v2v(OpcodeVecF64x2ConvertLowI32x4U)},
  3160  		{name: OpcodeVecI32x4DotI16x8SName, body: vv2v(OpcodeVecI32x4DotI16x8S)},
  3161  		{name: OpcodeVecI8x16NarrowI16x8SName, body: vv2v(OpcodeVecI8x16NarrowI16x8S)},
  3162  		{name: OpcodeVecI8x16NarrowI16x8UName, body: vv2v(OpcodeVecI8x16NarrowI16x8U)},
  3163  		{name: OpcodeVecI16x8NarrowI32x4SName, body: vv2v(OpcodeVecI16x8NarrowI32x4S)},
  3164  		{name: OpcodeVecI16x8NarrowI32x4UName, body: vv2v(OpcodeVecI16x8NarrowI32x4U)},
  3165  		{name: OpcodeVecI32x4TruncSatF32x4SName, body: v2v(OpcodeVecI32x4TruncSatF32x4S)},
  3166  		{name: OpcodeVecI32x4TruncSatF32x4UName, body: v2v(OpcodeVecI32x4TruncSatF32x4U)},
  3167  		{name: OpcodeVecI32x4TruncSatF64x2SZeroName, body: v2v(OpcodeVecI32x4TruncSatF64x2SZero)},
  3168  		{name: OpcodeVecI32x4TruncSatF64x2UZeroName, body: v2v(OpcodeVecI32x4TruncSatF64x2UZero)},
  3169  	}
  3170  
  3171  	for _, tt := range tests {
  3172  		tc := tt
  3173  		t.Run(tc.name, func(t *testing.T) {
  3174  			m := &Module{
  3175  				TypeSection:     []FunctionType{v_v},
  3176  				FunctionSection: []Index{0},
  3177  				CodeSection:     []Code{{Body: tc.body}},
  3178  			}
  3179  			err := m.validateFunction(&stacks{}, api.CoreFeatureSIMD,
  3180  				0, []Index{0}, nil, &Memory{}, nil, nil, bytes.NewReader(nil))
  3181  			require.NoError(t, err)
  3182  		})
  3183  	}
  3184  }
  3185  
  3186  func TestModule_funcValidation_SIMD_error(t *testing.T) {
  3187  	type testCase struct {
  3188  		name        string
  3189  		body        []byte
  3190  		flag        api.CoreFeatures
  3191  		expectedErr string
  3192  	}
  3193  
  3194  	tests := []testCase{
  3195  		{
  3196  			name: "simd disabled",
  3197  			body: []byte{
  3198  				OpcodeVecPrefix,
  3199  				OpcodeVecF32x4Abs,
  3200  			},
  3201  			flag:        api.CoreFeaturesV1,
  3202  			expectedErr: "f32x4.abs invalid as feature \"simd\" is disabled",
  3203  		},
  3204  		{
  3205  			name: "v128.const immediate",
  3206  			body: []byte{
  3207  				OpcodeVecPrefix,
  3208  				OpcodeVecV128Const,
  3209  				1, 1, 1, 1, 1, 1, 1, 1,
  3210  				1, 1, 1, 1, 1, 1, 1,
  3211  			},
  3212  			flag:        api.CoreFeatureSIMD,
  3213  			expectedErr: "cannot read constant vector value for v128.const",
  3214  		},
  3215  		{
  3216  			name: "i32x4.add operand",
  3217  			body: []byte{
  3218  				OpcodeVecPrefix,
  3219  				OpcodeVecV128Const,
  3220  				1, 1, 1, 1, 1, 1, 1, 1,
  3221  				1, 1, 1, 1, 1, 1, 1, 1,
  3222  				OpcodeVecPrefix,
  3223  				OpcodeVecI32x4Add,
  3224  				OpcodeDrop,
  3225  				OpcodeEnd,
  3226  			},
  3227  			flag:        api.CoreFeatureSIMD,
  3228  			expectedErr: "cannot pop the operand for i32x4.add: v128 missing",
  3229  		},
  3230  		{
  3231  			name: "i64x2.add operand",
  3232  			body: []byte{
  3233  				OpcodeVecPrefix,
  3234  				OpcodeVecV128Const,
  3235  				1, 1, 1, 1, 1, 1, 1, 1,
  3236  				1, 1, 1, 1, 1, 1, 1, 1,
  3237  				OpcodeVecPrefix,
  3238  				OpcodeVecI64x2Add,
  3239  				OpcodeDrop,
  3240  				OpcodeEnd,
  3241  			},
  3242  			flag:        api.CoreFeatureSIMD,
  3243  			expectedErr: "cannot pop the operand for i64x2.add: v128 missing",
  3244  		},
  3245  		{
  3246  			name: "shuffle lane index not found",
  3247  			flag: api.CoreFeatureSIMD,
  3248  			body: []byte{
  3249  				OpcodeVecPrefix,
  3250  				OpcodeVecV128i8x16Shuffle,
  3251  			},
  3252  			expectedErr: "16 lane indexes for v128.shuffle not found",
  3253  		},
  3254  		{
  3255  			name: "shuffle lane index not found",
  3256  			flag: api.CoreFeatureSIMD,
  3257  			body: []byte{
  3258  				OpcodeVecPrefix,
  3259  				OpcodeVecV128i8x16Shuffle,
  3260  				0xff, 0, 0, 0, 0, 0, 0, 0,
  3261  				0, 0, 0, 0, 0, 0, 0, 0,
  3262  			},
  3263  			expectedErr: "invalid lane index[0] 255 >= 32 for v128.shuffle",
  3264  		},
  3265  	}
  3266  
  3267  	addExtractOrReplaceLaneOutOfIndexCase := func(op OpcodeVec, lane, laneCeil byte) {
  3268  		n := VectorInstructionName(op)
  3269  		tests = append(tests, testCase{
  3270  			name: n + "/lane index out of range",
  3271  			flag: api.CoreFeatureSIMD,
  3272  			body: []byte{
  3273  				OpcodeVecPrefix, op, lane,
  3274  			},
  3275  			expectedErr: fmt.Sprintf("invalid lane index %d >= %d for %s", lane, laneCeil, n),
  3276  		})
  3277  	}
  3278  
  3279  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ExtractLaneS, 16, 16)
  3280  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ExtractLaneU, 20, 16)
  3281  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ExtractLaneS, 8, 8)
  3282  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ExtractLaneU, 8, 8)
  3283  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI32x4ExtractLane, 4, 4)
  3284  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF32x4ExtractLane, 4, 4)
  3285  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI64x2ExtractLane, 2, 2)
  3286  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF64x2ExtractLane, 2, 2)
  3287  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ReplaceLane, 16, 16)
  3288  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ReplaceLane, 8, 8)
  3289  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI32x4ReplaceLane, 4, 4)
  3290  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI64x2ReplaceLane, 2, 2)
  3291  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF32x4ReplaceLane, 10, 4)
  3292  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF64x2ReplaceLane, 3, 2)
  3293  
  3294  	addStoreOrLoadLaneOutOfIndexCase := func(op OpcodeVec, lane, laneCeil byte) {
  3295  		n := VectorInstructionName(op)
  3296  		tests = append(tests, testCase{
  3297  			name: n + "/lane index out of range",
  3298  			flag: api.CoreFeatureSIMD,
  3299  			body: []byte{
  3300  				OpcodeVecPrefix, op,
  3301  				0, 0, // align and offset.
  3302  				lane,
  3303  			},
  3304  			expectedErr: fmt.Sprintf("invalid lane index %d >= %d for %s", lane, laneCeil, n),
  3305  		})
  3306  	}
  3307  
  3308  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load8Lane, 16, 16)
  3309  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load16Lane, 8, 8)
  3310  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load32Lane, 4, 4)
  3311  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load64Lane, 2, 2)
  3312  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store8Lane, 16, 16)
  3313  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store16Lane, 8, 8)
  3314  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store32Lane, 4, 4)
  3315  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store64Lane, 2, 2)
  3316  
  3317  	for _, tt := range tests {
  3318  		tc := tt
  3319  		t.Run(tc.name, func(t *testing.T) {
  3320  			m := &Module{
  3321  				TypeSection:     []FunctionType{v_v},
  3322  				FunctionSection: []Index{0},
  3323  				CodeSection:     []Code{{Body: tc.body}},
  3324  			}
  3325  			err := m.validateFunction(&stacks{}, tc.flag,
  3326  				0, []Index{0}, nil, &Memory{}, nil, nil, bytes.NewReader(nil))
  3327  			require.EqualError(t, err, tc.expectedErr)
  3328  		})
  3329  	}
  3330  }
  3331  
  3332  func TestDecodeBlockType(t *testing.T) {
  3333  	t.Run("primitive", func(t *testing.T) {
  3334  		for _, tc := range []struct {
  3335  			name                 string
  3336  			in                   byte
  3337  			exp                  ValueType
  3338  			expResultNumInUint64 int
  3339  		}{
  3340  			{name: "nil", in: 0x40},
  3341  			{name: "i32", in: 0x7f, exp: ValueTypeI32, expResultNumInUint64: 1},
  3342  			{name: "i64", in: 0x7e, exp: ValueTypeI64, expResultNumInUint64: 1},
  3343  			{name: "f32", in: 0x7d, exp: ValueTypeF32, expResultNumInUint64: 1},
  3344  			{name: "f64", in: 0x7c, exp: ValueTypeF64, expResultNumInUint64: 1},
  3345  			{name: "v128", in: 0x7b, exp: ValueTypeV128, expResultNumInUint64: 2},
  3346  			{name: "funcref", in: 0x70, exp: ValueTypeFuncref, expResultNumInUint64: 1},
  3347  			{name: "externref", in: 0x6f, exp: ValueTypeExternref, expResultNumInUint64: 1},
  3348  		} {
  3349  			tc := tc
  3350  			t.Run(tc.name, func(t *testing.T) {
  3351  				actual, read, err := DecodeBlockType(nil, bytes.NewReader([]byte{tc.in}), api.CoreFeaturesV2)
  3352  				require.NoError(t, err)
  3353  				require.Equal(t, uint64(1), read)
  3354  				require.Equal(t, 0, len(actual.Params))
  3355  				require.Equal(t, tc.expResultNumInUint64, actual.ResultNumInUint64)
  3356  				require.Equal(t, 0, actual.ParamNumInUint64)
  3357  				if tc.exp == 0 {
  3358  					require.Equal(t, 0, len(actual.Results))
  3359  				} else {
  3360  					require.Equal(t, 1, len(actual.Results))
  3361  					require.Equal(t, tc.exp, actual.Results[0])
  3362  				}
  3363  			})
  3364  		}
  3365  	})
  3366  	t.Run("function type", func(t *testing.T) {
  3367  		types := []FunctionType{
  3368  			{},
  3369  			{Params: []ValueType{ValueTypeI32}},
  3370  			{Results: []ValueType{ValueTypeI32}},
  3371  			{Params: []ValueType{ValueTypeF32, ValueTypeV128}, Results: []ValueType{ValueTypeI32}},
  3372  			{Params: []ValueType{ValueTypeF32, ValueTypeV128}, Results: []ValueType{ValueTypeI32, ValueTypeF32, ValueTypeV128}},
  3373  		}
  3374  		for index := range types {
  3375  			expected := &types[index]
  3376  			actual, read, err := DecodeBlockType(types, bytes.NewReader([]byte{byte(index)}), api.CoreFeatureMultiValue)
  3377  			require.NoError(t, err)
  3378  			require.Equal(t, uint64(1), read)
  3379  			require.Equal(t, expected, actual)
  3380  		}
  3381  	})
  3382  }
  3383  
  3384  // TestFuncValidation_UnreachableBrTable_NotModifyTypes ensures that we do not modify the
  3385  // original function type during the function validation with the presence of unreachable br_table
  3386  // targeting the function return label.
  3387  func TestFuncValidation_UnreachableBrTable_NotModifyTypes(t *testing.T) {
  3388  	funcType := FunctionType{Results: []ValueType{i32, i64}, Params: []ValueType{i32}}
  3389  	copiedFuncType := FunctionType{
  3390  		Params:  make([]ValueType, len(funcType.Params)),
  3391  		Results: make([]ValueType, len(funcType.Results)),
  3392  	}
  3393  
  3394  	copy(copiedFuncType.Results, funcType.Results)
  3395  	copy(copiedFuncType.Params, funcType.Params)
  3396  
  3397  	for _, tc := range []struct {
  3398  		name string
  3399  		m    *Module
  3400  	}{
  3401  		{
  3402  			name: "on function return",
  3403  			m: &Module{
  3404  				TypeSection:     []FunctionType{funcType},
  3405  				FunctionSection: []Index{0},
  3406  				CodeSection: []Code{
  3407  					{Body: []byte{
  3408  						OpcodeUnreachable,
  3409  						// Having br_table in unreachable state.
  3410  						OpcodeI32Const, 1,
  3411  						// Setting the destination as labels of index 0 which
  3412  						// is the function return.
  3413  						OpcodeBrTable, 2, 0, 0, 0,
  3414  						OpcodeEnd,
  3415  					}},
  3416  				},
  3417  			},
  3418  		},
  3419  		{
  3420  			name: "on loop return",
  3421  			m: &Module{
  3422  				TypeSection:     []FunctionType{funcType},
  3423  				FunctionSection: []Index{0},
  3424  				CodeSection: []Code{
  3425  					{Body: []byte{
  3426  						OpcodeUnreachable,
  3427  						OpcodeLoop, 0, // indicates that loop has funcType as its block type
  3428  						OpcodeUnreachable,
  3429  						// Having br_table in unreachable state.
  3430  						OpcodeI32Const, 1,
  3431  						// Setting the destination as labels of index 0 which
  3432  						// is the loop return.
  3433  						OpcodeBrTable, 2, 0, 0, 0,
  3434  						OpcodeEnd, // End of loop
  3435  						OpcodeEnd,
  3436  					}},
  3437  				},
  3438  			},
  3439  		},
  3440  	} {
  3441  		tc := tc
  3442  		t.Run(tc.name, func(t *testing.T) {
  3443  			err := tc.m.validateFunction(&stacks{}, api.CoreFeaturesV2,
  3444  				0, nil, nil, nil, nil, nil, bytes.NewReader(nil))
  3445  			require.NoError(t, err)
  3446  
  3447  			// Ensures that funcType has remained intact.
  3448  			require.Equal(t, copiedFuncType, funcType)
  3449  		})
  3450  	}
  3451  }
  3452  
  3453  func TestModule_funcValidation_loopWithParams(t *testing.T) {
  3454  	tests := []struct {
  3455  		name   string
  3456  		body   []byte
  3457  		expErr string
  3458  	}{
  3459  		{
  3460  			name: "br",
  3461  			body: []byte{
  3462  				OpcodeI32Const, 1,
  3463  				OpcodeLoop, 1, // loop (param i32)
  3464  				OpcodeBr, 0,
  3465  				OpcodeEnd,
  3466  				OpcodeUnreachable,
  3467  				OpcodeEnd,
  3468  			},
  3469  		},
  3470  		{
  3471  			name: "br_if",
  3472  			body: []byte{
  3473  				OpcodeI32Const, 1,
  3474  				OpcodeLoop, 1, // loop (param i32)
  3475  				OpcodeI32Const, 1, // operand for br_if
  3476  				OpcodeBrIf, 0,
  3477  				OpcodeUnreachable,
  3478  				OpcodeEnd,
  3479  				OpcodeUnreachable,
  3480  				OpcodeEnd,
  3481  			},
  3482  		},
  3483  		{
  3484  			name: "br_table",
  3485  			body: []byte{
  3486  				OpcodeI32Const, 1,
  3487  				OpcodeLoop, 1, // loop (param i32)
  3488  				OpcodeI32Const, 4, // Operand for br_table.
  3489  				OpcodeBrTable, 2, 0, 0, 0, 0, // Jump into the loop header anyway.
  3490  				OpcodeEnd,
  3491  				OpcodeUnreachable,
  3492  				OpcodeEnd,
  3493  			},
  3494  		},
  3495  		{
  3496  			name: "br_table - nested",
  3497  			body: []byte{
  3498  				OpcodeI32Const, 1,
  3499  				OpcodeLoop, 1, // loop (param i32)
  3500  				OpcodeLoop, 1, // loop (param i32)
  3501  				OpcodeI32Const, 4, // Operand for br_table.
  3502  				OpcodeBrTable, 2, 0, 1, 0, // Jump into the loop header anyway.
  3503  				OpcodeEnd,
  3504  				OpcodeEnd,
  3505  				OpcodeUnreachable,
  3506  				OpcodeEnd,
  3507  			},
  3508  		},
  3509  		{
  3510  			name: "br / mismatch",
  3511  			body: []byte{
  3512  				OpcodeI32Const, 1,
  3513  				OpcodeLoop, 1, // loop (param i32)
  3514  				OpcodeDrop,
  3515  				OpcodeBr, 0, // trying to jump the loop head after dropping the value which causes the type mismatch.
  3516  				OpcodeEnd,
  3517  				OpcodeUnreachable,
  3518  				OpcodeEnd,
  3519  			},
  3520  			expErr: `not enough results in br block
  3521  	have ()
  3522  	want (i32)`,
  3523  		},
  3524  		{
  3525  			name: "br_if / mismatch",
  3526  			body: []byte{
  3527  				OpcodeI32Const, 1,
  3528  				OpcodeLoop, 1, // loop (param i32)
  3529  				// Use up the param for the br_if, therefore at the time of jumping, we don't have any param to the header.
  3530  				OpcodeBrIf, 0, // trying to jump the loop head after dropping the value which causes the type mismatch.
  3531  				OpcodeUnreachable,
  3532  				OpcodeEnd,
  3533  				OpcodeUnreachable,
  3534  				OpcodeEnd,
  3535  			},
  3536  			expErr: `not enough results in br_if block
  3537  	have ()
  3538  	want (i32)`,
  3539  		},
  3540  		{
  3541  			name: "br_table",
  3542  			body: []byte{
  3543  				OpcodeI32Const, 1,
  3544  				OpcodeLoop, 1, // loop (param i32)
  3545  				// Use up the param for the br_table, therefore at the time of jumping, we don't have any param to the header.
  3546  				OpcodeBrTable, 2, 0, 0, 0, // Jump into the loop header anyway.
  3547  				OpcodeEnd,
  3548  				OpcodeUnreachable,
  3549  				OpcodeEnd,
  3550  			},
  3551  			expErr: `not enough results in br_table block
  3552  	have ()
  3553  	want (i32)`,
  3554  		},
  3555  	}
  3556  
  3557  	for _, tt := range tests {
  3558  		tc := tt
  3559  		t.Run(tc.name, func(t *testing.T) {
  3560  			m := &Module{
  3561  				TypeSection: []FunctionType{
  3562  					v_i32,
  3563  					i32_v,
  3564  				},
  3565  				FunctionSection: []Index{0},
  3566  				CodeSection:     []Code{{Body: tc.body}},
  3567  			}
  3568  			err := m.validateFunction(&stacks{}, api.CoreFeatureMultiValue,
  3569  				0, []Index{0}, nil, nil, nil, nil, bytes.NewReader(nil))
  3570  			if tc.expErr != "" {
  3571  				require.EqualError(t, err, tc.expErr)
  3572  			} else {
  3573  				require.NoError(t, err)
  3574  			}
  3575  		})
  3576  	}
  3577  }
  3578  
  3579  // TestFunctionValidation_redundantEnd is found in th validation fuzzing #879.
  3580  func TestFunctionValidation_redundantEnd(t *testing.T) {
  3581  	m := &Module{
  3582  		TypeSection:     []FunctionType{{}},
  3583  		FunctionSection: []Index{0},
  3584  		CodeSection:     []Code{{Body: []byte{OpcodeEnd, OpcodeEnd}}},
  3585  	}
  3586  	err := m.validateFunction(&stacks{}, api.CoreFeaturesV2,
  3587  		0, nil, nil, nil, nil, nil, bytes.NewReader(nil))
  3588  	require.EqualError(t, err, "redundant End instruction at 0x1")
  3589  }
  3590  
  3591  // TestFunctionValidation_redundantEnd is found in th validation fuzzing.
  3592  func TestFunctionValidation_redundantElse(t *testing.T) {
  3593  	m := &Module{
  3594  		TypeSection:     []FunctionType{{}},
  3595  		FunctionSection: []Index{0},
  3596  		CodeSection:     []Code{{Body: []byte{OpcodeEnd, OpcodeElse}}},
  3597  	}
  3598  	err := m.validateFunction(&stacks{}, api.CoreFeaturesV2,
  3599  		0, nil, nil, nil, nil, nil, bytes.NewReader(nil))
  3600  	require.EqualError(t, err, "redundant Else instruction at 0x1")
  3601  }
  3602  
  3603  func Test_SplitCallStack(t *testing.T) {
  3604  	oneToEight := []uint64{1, 2, 3, 4, 5, 6, 7, 8}
  3605  
  3606  	tests := []struct {
  3607  		name                                   string
  3608  		ft                                     *FunctionType
  3609  		stack, expectedParams, expectedResults []uint64
  3610  		expectedErr                            string
  3611  	}{
  3612  		{
  3613  			name:            "v_v",
  3614  			ft:              &v_v,
  3615  			stack:           oneToEight,
  3616  			expectedParams:  nil,
  3617  			expectedResults: nil,
  3618  		},
  3619  		{
  3620  			name:            "v_v - stack nil",
  3621  			ft:              &v_v,
  3622  			expectedParams:  nil,
  3623  			expectedResults: nil,
  3624  		},
  3625  		{
  3626  			name:            "v_i32",
  3627  			ft:              &v_i32,
  3628  			stack:           oneToEight,
  3629  			expectedParams:  nil,
  3630  			expectedResults: []uint64{1},
  3631  		},
  3632  		{
  3633  			name:            "f32i32_v",
  3634  			ft:              &f32i32_v,
  3635  			stack:           oneToEight,
  3636  			expectedParams:  []uint64{1, 2},
  3637  			expectedResults: nil,
  3638  		},
  3639  		{
  3640  			name:            "f64f32_i64",
  3641  			ft:              &f64f32_i64,
  3642  			stack:           oneToEight,
  3643  			expectedParams:  []uint64{1, 2},
  3644  			expectedResults: []uint64{1},
  3645  		},
  3646  		{
  3647  			name:            "f64i32_v128i64",
  3648  			ft:              &f64i32_v128i64,
  3649  			stack:           oneToEight,
  3650  			expectedParams:  []uint64{1, 2},
  3651  			expectedResults: []uint64{1, 2, 3},
  3652  		},
  3653  		{
  3654  			name:        "not enough room for params",
  3655  			ft:          &f64i32_v128i64,
  3656  			stack:       oneToEight[0:1],
  3657  			expectedErr: "need 2 params, but stack size is 1",
  3658  		},
  3659  		{
  3660  			name:        "not enough room for results",
  3661  			ft:          &f64i32_v128i64,
  3662  			stack:       oneToEight[0:2],
  3663  			expectedErr: "need 3 results, but stack size is 2",
  3664  		},
  3665  	}
  3666  
  3667  	for _, tt := range tests {
  3668  		tc := tt
  3669  
  3670  		t.Run(tc.name, func(t *testing.T) {
  3671  			params, results, err := SplitCallStack(tc.ft, tc.stack)
  3672  			if tc.expectedErr != "" {
  3673  				require.EqualError(t, err, tc.expectedErr)
  3674  			} else {
  3675  				require.Equal(t, tc.expectedParams, params)
  3676  				require.Equal(t, tc.expectedResults, results)
  3677  			}
  3678  		})
  3679  	}
  3680  }
  3681  
  3682  func TestModule_funcValidation_Atomic(t *testing.T) {
  3683  	t.Run("valid bytecode", func(t *testing.T) {
  3684  		tests := []struct {
  3685  			name               string
  3686  			body               []byte
  3687  			noDropBeforeReturn bool
  3688  		}{
  3689  			{
  3690  				name: "i32.atomic.load8_u",
  3691  				body: []byte{
  3692  					OpcodeI32Const, 0x0,
  3693  					OpcodeAtomicPrefix, OpcodeAtomicI32Load8U, 0x0, 0x8, // alignment=2^0, offset=8
  3694  				},
  3695  			},
  3696  			{
  3697  				name: "i32.atomic.load16_u",
  3698  				body: []byte{
  3699  					OpcodeI32Const, 0x0,
  3700  					OpcodeAtomicPrefix, OpcodeAtomicI32Load16U, 0x1, 0x8, // alignment=2^1, offset=8
  3701  				},
  3702  			},
  3703  			{
  3704  				name: "i32.atomic.load",
  3705  				body: []byte{
  3706  					OpcodeI32Const, 0x0,
  3707  					OpcodeAtomicPrefix, OpcodeAtomicI32Load, 0x2, 0x8, // alignment=2^2, offset=8
  3708  				},
  3709  			},
  3710  			{
  3711  				name: "i64.atomic.load8_u",
  3712  				body: []byte{
  3713  					OpcodeI32Const, 0x0,
  3714  					OpcodeAtomicPrefix, OpcodeAtomicI64Load8U, 0x0, 0x8, // alignment=2^0, offset=8
  3715  				},
  3716  			},
  3717  			{
  3718  				name: "i64.atomic.load16_u",
  3719  				body: []byte{
  3720  					OpcodeI32Const, 0x0,
  3721  					OpcodeAtomicPrefix, OpcodeAtomicI64Load16U, 0x1, 0x8, // alignment=2^1, offset=8
  3722  				},
  3723  			},
  3724  			{
  3725  				name: "i64.atomic.load32_u",
  3726  				body: []byte{
  3727  					OpcodeI32Const, 0x0,
  3728  					OpcodeAtomicPrefix, OpcodeAtomicI64Load32U, 0x2, 0x8, // alignment=2^2, offset=8
  3729  				},
  3730  			},
  3731  			{
  3732  				name: "i64.atomic.load",
  3733  				body: []byte{
  3734  					OpcodeI32Const, 0x0,
  3735  					OpcodeAtomicPrefix, OpcodeAtomicI64Load, 0x3, 0x8, // alignment=2^3, offset=8
  3736  				},
  3737  			},
  3738  			{
  3739  				name: "i32.atomic.store8",
  3740  				body: []byte{
  3741  					OpcodeI32Const, 0x1,
  3742  					OpcodeI32Const, 0x0,
  3743  					OpcodeAtomicPrefix, OpcodeAtomicI32Store8, 0x0, 0x8, // alignment=2^0, offset=8
  3744  				},
  3745  				noDropBeforeReturn: true,
  3746  			},
  3747  			{
  3748  				name: "i32.atomic.store16",
  3749  				body: []byte{
  3750  					OpcodeI32Const, 0x1,
  3751  					OpcodeI32Const, 0x0,
  3752  					OpcodeAtomicPrefix, OpcodeAtomicI32Store16, 0x1, 0x8, // alignment=2^1, offset=8
  3753  				},
  3754  				noDropBeforeReturn: true,
  3755  			},
  3756  			{
  3757  				name: "i32.atomic.store",
  3758  				body: []byte{
  3759  					OpcodeI32Const, 0x1,
  3760  					OpcodeI32Const, 0x0,
  3761  					OpcodeAtomicPrefix, OpcodeAtomicI32Store, 0x2, 0x8, // alignment=2^2, offset=8
  3762  				},
  3763  				noDropBeforeReturn: true,
  3764  			},
  3765  			{
  3766  				name: "i64.atomic.store8",
  3767  				body: []byte{
  3768  					OpcodeI32Const, 0x0,
  3769  					OpcodeI64Const, 0x1,
  3770  					OpcodeAtomicPrefix, OpcodeAtomicI64Store8, 0x0, 0x8, // alignment=2^0, offset=8
  3771  				},
  3772  				noDropBeforeReturn: true,
  3773  			},
  3774  			{
  3775  				name: "i64.atomic.store16",
  3776  				body: []byte{
  3777  					OpcodeI32Const, 0x0,
  3778  					OpcodeI64Const, 0x1,
  3779  					OpcodeAtomicPrefix, OpcodeAtomicI64Store16, 0x1, 0x8, // alignment=2^1, offset=8
  3780  				},
  3781  				noDropBeforeReturn: true,
  3782  			},
  3783  			{
  3784  				name: "i64.atomic.store32",
  3785  				body: []byte{
  3786  					OpcodeI32Const, 0x0,
  3787  					OpcodeI64Const, 0x1,
  3788  					OpcodeAtomicPrefix, OpcodeAtomicI64Store32, 0x2, 0x8, // alignment=2^2, offset=8
  3789  				},
  3790  				noDropBeforeReturn: true,
  3791  			},
  3792  			{
  3793  				name: "i64.atomic.store",
  3794  				body: []byte{
  3795  					OpcodeI32Const, 0x0,
  3796  					OpcodeI64Const, 0x1,
  3797  					OpcodeAtomicPrefix, OpcodeAtomicI64Store, 0x3, 0x8, // alignment=2^3, offset=8
  3798  				},
  3799  				noDropBeforeReturn: true,
  3800  			},
  3801  			{
  3802  				name: "i32.atomic.rmw8.add_u",
  3803  				body: []byte{
  3804  					OpcodeI32Const, 0x0,
  3805  					OpcodeI32Const, 0x1,
  3806  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AddU, 0x0, 0x8, // alignment=2^0, offset=8
  3807  				},
  3808  			},
  3809  			{
  3810  				name: "i32.atomic.rmw16.add_u",
  3811  				body: []byte{
  3812  					OpcodeI32Const, 0x0,
  3813  					OpcodeI32Const, 0x1,
  3814  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AddU, 0x1, 0x8, // alignment=2^1, offset=8
  3815  				},
  3816  			},
  3817  			{
  3818  				name: "i32.atomic.rmw.add",
  3819  				body: []byte{
  3820  					OpcodeI32Const, 0x0,
  3821  					OpcodeI32Const, 0x1,
  3822  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwAdd, 0x2, 0x8, // alignment=2^2, offset=8
  3823  				},
  3824  			},
  3825  			{
  3826  				name: "i64.atomic.rmw8.add_u",
  3827  				body: []byte{
  3828  					OpcodeI32Const, 0x0,
  3829  					OpcodeI64Const, 0x1,
  3830  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AddU, 0x0, 0x8, // alignment=2^0, offset=8
  3831  				},
  3832  			},
  3833  			{
  3834  				name: "i64.atomic.rmw16.add_u",
  3835  				body: []byte{
  3836  					OpcodeI32Const, 0x0,
  3837  					OpcodeI64Const, 0x1,
  3838  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AddU, 0x1, 0x8, // alignment=2^1, offset=8
  3839  				},
  3840  			},
  3841  			{
  3842  				name: "i64.atomic.rmw32.add_u",
  3843  				body: []byte{
  3844  					OpcodeI32Const, 0x0,
  3845  					OpcodeI64Const, 0x1,
  3846  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AddU, 0x2, 0x8, // alignment=2^2, offset=8
  3847  				},
  3848  			},
  3849  			{
  3850  				name: "i64.atomic.rmw.add",
  3851  				body: []byte{
  3852  					OpcodeI32Const, 0x0,
  3853  					OpcodeI64Const, 0x1,
  3854  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwAdd, 0x3, 0x8, // alignment=2^3, offset=8
  3855  				},
  3856  			},
  3857  			{
  3858  				name: "i32.atomic.rmw8.sub_u",
  3859  				body: []byte{
  3860  					OpcodeI32Const, 0x0,
  3861  					OpcodeI32Const, 0x1,
  3862  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8SubU, 0x0, 0x8, // alignment=2^0, offset=8
  3863  				},
  3864  			},
  3865  			{
  3866  				name: "i32.atomic.rmw16.sub_u",
  3867  				body: []byte{
  3868  					OpcodeI32Const, 0x0,
  3869  					OpcodeI32Const, 0x1,
  3870  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16SubU, 0x1, 0x8, // alignment=2^1, offset=8
  3871  				},
  3872  			},
  3873  			{
  3874  				name: "i32.atomic.rmw.sub",
  3875  				body: []byte{
  3876  					OpcodeI32Const, 0x0,
  3877  					OpcodeI32Const, 0x1,
  3878  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwSub, 0x2, 0x8, // alignment=2^2, offset=8
  3879  				},
  3880  			},
  3881  			{
  3882  				name: "i64.atomic.rmw8.sub_u",
  3883  				body: []byte{
  3884  					OpcodeI32Const, 0x0,
  3885  					OpcodeI64Const, 0x1,
  3886  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8SubU, 0x0, 0x8, // alignment=2^0, offset=8
  3887  				},
  3888  			},
  3889  			{
  3890  				name: "i64.atomic.rmw16.sub_u",
  3891  				body: []byte{
  3892  					OpcodeI32Const, 0x0,
  3893  					OpcodeI64Const, 0x1,
  3894  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16SubU, 0x1, 0x8, // alignment=2^1, offset=8
  3895  				},
  3896  			},
  3897  			{
  3898  				name: "i64.atomic.rmw32.sub_u",
  3899  				body: []byte{
  3900  					OpcodeI32Const, 0x0,
  3901  					OpcodeI64Const, 0x1,
  3902  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32SubU, 0x2, 0x8, // alignment=2^2, offset=8
  3903  				},
  3904  			},
  3905  			{
  3906  				name: "i64.atomic.rmw.sub",
  3907  				body: []byte{
  3908  					OpcodeI32Const, 0x0,
  3909  					OpcodeI64Const, 0x1,
  3910  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwSub, 0x3, 0x8, // alignment=2^3, offset=8
  3911  				},
  3912  			},
  3913  			{
  3914  				name: "i32.atomic.rmw8.and_u",
  3915  				body: []byte{
  3916  					OpcodeI32Const, 0x0,
  3917  					OpcodeI32Const, 0x1,
  3918  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AndU, 0x0, 0x8, // alignment=2^0, offset=8
  3919  				},
  3920  			},
  3921  			{
  3922  				name: "i32.atomic.rmw16.and_u",
  3923  				body: []byte{
  3924  					OpcodeI32Const, 0x0,
  3925  					OpcodeI32Const, 0x1,
  3926  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AndU, 0x1, 0x8, // alignment=2^1, offset=8
  3927  				},
  3928  			},
  3929  			{
  3930  				name: "i32.atomic.rmw.and",
  3931  				body: []byte{
  3932  					OpcodeI32Const, 0x0,
  3933  					OpcodeI32Const, 0x1,
  3934  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwAnd, 0x2, 0x8, // alignment=2^2, offset=8
  3935  				},
  3936  			},
  3937  			{
  3938  				name: "i64.atomic.rmw8.and_u",
  3939  				body: []byte{
  3940  					OpcodeI32Const, 0x0,
  3941  					OpcodeI64Const, 0x1,
  3942  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AndU, 0x0, 0x8, // alignment=2^0, offset=8
  3943  				},
  3944  			},
  3945  			{
  3946  				name: "i64.atomic.rmw16.and_u",
  3947  				body: []byte{
  3948  					OpcodeI32Const, 0x0,
  3949  					OpcodeI64Const, 0x1,
  3950  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AndU, 0x1, 0x8, // alignment=2^1, offset=8
  3951  				},
  3952  			},
  3953  			{
  3954  				name: "i64.atomic.rmw32.and_u",
  3955  				body: []byte{
  3956  					OpcodeI32Const, 0x0,
  3957  					OpcodeI64Const, 0x1,
  3958  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AndU, 0x2, 0x8, // alignment=2^2, offset=8
  3959  				},
  3960  			},
  3961  			{
  3962  				name: "i64.atomic.rmw.and",
  3963  				body: []byte{
  3964  					OpcodeI32Const, 0x0,
  3965  					OpcodeI64Const, 0x1,
  3966  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwAnd, 0x3, 0x8, // alignment=2^3, offset=8
  3967  				},
  3968  			},
  3969  			{
  3970  				name: "i32.atomic.rmw8.or",
  3971  				body: []byte{
  3972  					OpcodeI32Const, 0x0,
  3973  					OpcodeI32Const, 0x1,
  3974  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8OrU, 0x0, 0x8, // alignment=2^0, offset=8
  3975  				},
  3976  			},
  3977  			{
  3978  				name: "i32.atomic.rmw16.or_u",
  3979  				body: []byte{
  3980  					OpcodeI32Const, 0x0,
  3981  					OpcodeI32Const, 0x1,
  3982  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16OrU, 0x1, 0x8, // alignment=2^1, offset=8
  3983  				},
  3984  			},
  3985  			{
  3986  				name: "i32.atomic.rmw.or",
  3987  				body: []byte{
  3988  					OpcodeI32Const, 0x0,
  3989  					OpcodeI32Const, 0x1,
  3990  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwOr, 0x2, 0x8, // alignment=2^2, offset=8
  3991  				},
  3992  			},
  3993  			{
  3994  				name: "i64.atomic.rmw8.or_u",
  3995  				body: []byte{
  3996  					OpcodeI32Const, 0x0,
  3997  					OpcodeI64Const, 0x1,
  3998  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8OrU, 0x0, 0x8, // alignment=2^0, offset=8
  3999  				},
  4000  			},
  4001  			{
  4002  				name: "i64.atomic.rmw16.or_u",
  4003  				body: []byte{
  4004  					OpcodeI32Const, 0x0,
  4005  					OpcodeI64Const, 0x1,
  4006  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16OrU, 0x1, 0x8, // alignment=2^1, offset=8
  4007  				},
  4008  			},
  4009  			{
  4010  				name: "i64.atomic.rmw32.or_u",
  4011  				body: []byte{
  4012  					OpcodeI32Const, 0x0,
  4013  					OpcodeI64Const, 0x1,
  4014  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32OrU, 0x2, 0x8, // alignment=2^2, offset=8
  4015  				},
  4016  			},
  4017  			{
  4018  				name: "i64.atomic.rmw.or",
  4019  				body: []byte{
  4020  					OpcodeI32Const, 0x0,
  4021  					OpcodeI64Const, 0x1,
  4022  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwOr, 0x3, 0x8, // alignment=2^3, offset=8
  4023  				},
  4024  			},
  4025  			{
  4026  				name: "i32.atomic.rmw8.xor_u",
  4027  				body: []byte{
  4028  					OpcodeI32Const, 0x0,
  4029  					OpcodeI32Const, 0x1,
  4030  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XorU, 0x0, 0x8, // alignment=2^0, offset=8
  4031  				},
  4032  			},
  4033  			{
  4034  				name: "i32.atomic.rmw16.xor_u",
  4035  				body: []byte{
  4036  					OpcodeI32Const, 0x0,
  4037  					OpcodeI32Const, 0x1,
  4038  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XorU, 0x1, 0x8, // alignment=2^1, offset=8
  4039  				},
  4040  			},
  4041  			{
  4042  				name: "i32.atomic.rmw.xor",
  4043  				body: []byte{
  4044  					OpcodeI32Const, 0x0,
  4045  					OpcodeI32Const, 0x1,
  4046  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwXor, 0x2, 0x8, // alignment=2^2, offset=8
  4047  				},
  4048  			},
  4049  			{
  4050  				name: "i64.atomic.rmw8.xor_u",
  4051  				body: []byte{
  4052  					OpcodeI32Const, 0x0,
  4053  					OpcodeI64Const, 0x1,
  4054  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XorU, 0x0, 0x8, // alignment=2^0, offset=8
  4055  				},
  4056  			},
  4057  			{
  4058  				name: "i64.atomic.rmw16.xor_u",
  4059  				body: []byte{
  4060  					OpcodeI32Const, 0x0,
  4061  					OpcodeI64Const, 0x1,
  4062  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XorU, 0x1, 0x8, // alignment=2^1, offset=8
  4063  				},
  4064  			},
  4065  			{
  4066  				name: "i64.atomic.rmw32.xor_u",
  4067  				body: []byte{
  4068  					OpcodeI32Const, 0x0,
  4069  					OpcodeI64Const, 0x1,
  4070  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XorU, 0x2, 0x8, // alignment=2^2, offset=8
  4071  				},
  4072  			},
  4073  			{
  4074  				name: "i64.atomic.rmw.xor",
  4075  				body: []byte{
  4076  					OpcodeI32Const, 0x0,
  4077  					OpcodeI64Const, 0x1,
  4078  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwXor, 0x3, 0x8, // alignment=2^3, offset=8
  4079  				},
  4080  			},
  4081  			{
  4082  				name: "i32.atomic.rmw8.xchg_u",
  4083  				body: []byte{
  4084  					OpcodeI32Const, 0x0,
  4085  					OpcodeI32Const, 0x1,
  4086  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XchgU, 0x0, 0x8, // alignment=2^0, offset=8
  4087  				},
  4088  			},
  4089  			{
  4090  				name: "i32.atomic.rmw16.xchg_u",
  4091  				body: []byte{
  4092  					OpcodeI32Const, 0x0,
  4093  					OpcodeI32Const, 0x1,
  4094  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XchgU, 0x1, 0x8, // alignment=2^1, offset=8
  4095  				},
  4096  			},
  4097  			{
  4098  				name: "i32.atomic.rmw.xchg",
  4099  				body: []byte{
  4100  					OpcodeI32Const, 0x0,
  4101  					OpcodeI32Const, 0x1,
  4102  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwXchg, 0x2, 0x8, // alignment=2^2, offset=8
  4103  				},
  4104  			},
  4105  			{
  4106  				name: "i64.atomic.rmw8.xchg_u",
  4107  				body: []byte{
  4108  					OpcodeI32Const, 0x0,
  4109  					OpcodeI64Const, 0x1,
  4110  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XchgU, 0x0, 0x8, // alignment=2^0, offset=8
  4111  				},
  4112  			},
  4113  			{
  4114  				name: "i64.atomic.rmw16.xchg_u",
  4115  				body: []byte{
  4116  					OpcodeI32Const, 0x0,
  4117  					OpcodeI64Const, 0x1,
  4118  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XchgU, 0x1, 0x8, // alignment=2^1, offset=8
  4119  				},
  4120  			},
  4121  			{
  4122  				name: "i64.atomic.rmw32.xchg_u",
  4123  				body: []byte{
  4124  					OpcodeI32Const, 0x0,
  4125  					OpcodeI64Const, 0x1,
  4126  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XchgU, 0x2, 0x8, // alignment=2^2, offset=8
  4127  				},
  4128  			},
  4129  			{
  4130  				name: "i64.atomic.rmw.xchg",
  4131  				body: []byte{
  4132  					OpcodeI32Const, 0x0,
  4133  					OpcodeI64Const, 0x1,
  4134  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwXchg, 0x3, 0x8, // alignment=2^3, offset=8
  4135  				},
  4136  			},
  4137  			{
  4138  				name: "i32.atomic.rmw8.cmpxchg_u",
  4139  				body: []byte{
  4140  					OpcodeI32Const, 0x0,
  4141  					OpcodeI32Const, 0x1,
  4142  					OpcodeI32Const, 0x2,
  4143  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8CmpxchgU, 0x0, 0x8, // alignment=2^0, offset=8
  4144  				},
  4145  			},
  4146  			{
  4147  				name: "i32.atomic.rmw16.cmpxchg_u",
  4148  				body: []byte{
  4149  					OpcodeI32Const, 0x0,
  4150  					OpcodeI32Const, 0x1,
  4151  					OpcodeI32Const, 0x2,
  4152  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8
  4153  				},
  4154  			},
  4155  			{
  4156  				name: "i32.atomic.rmw.cmpxchg",
  4157  				body: []byte{
  4158  					OpcodeI32Const, 0x0,
  4159  					OpcodeI32Const, 0x1,
  4160  					OpcodeI32Const, 0x2,
  4161  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwCmpxchg, 0x2, 0x8, // alignment=2^2, offset=8
  4162  				},
  4163  			},
  4164  			{
  4165  				name: "i64.atomic.rmw8.xchg_u",
  4166  				body: []byte{
  4167  					OpcodeI32Const, 0x0,
  4168  					OpcodeI64Const, 0x1,
  4169  					OpcodeI64Const, 0x2,
  4170  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8CmpxchgU, 0x0, 0x8, // alignment=2^0, offset=8
  4171  				},
  4172  			},
  4173  			{
  4174  				name: "i64.atomic.rmw16.cmpxchg_u",
  4175  				body: []byte{
  4176  					OpcodeI32Const, 0x0,
  4177  					OpcodeI64Const, 0x1,
  4178  					OpcodeI64Const, 0x2,
  4179  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8
  4180  				},
  4181  			},
  4182  			{
  4183  				name: "i64.atomic.rmw32.cmpxchg_u",
  4184  				body: []byte{
  4185  					OpcodeI32Const, 0x0,
  4186  					OpcodeI64Const, 0x1,
  4187  					OpcodeI64Const, 0x1,
  4188  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8
  4189  				},
  4190  			},
  4191  			{
  4192  				name: "i64.atomic.rmw.cmpxchg",
  4193  				body: []byte{
  4194  					OpcodeI32Const, 0x0,
  4195  					OpcodeI64Const, 0x1,
  4196  					OpcodeI64Const, 0x2,
  4197  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwCmpxchg, 0x3, 0x8, // alignment=2^3, offset=8
  4198  				},
  4199  			},
  4200  			{
  4201  				name: "memory.atomic.wait32",
  4202  				body: []byte{
  4203  					OpcodeI32Const, 0x0,
  4204  					OpcodeI32Const, 0x1,
  4205  					OpcodeI64Const, 0x2,
  4206  					OpcodeAtomicPrefix, OpcodeAtomicMemoryWait32, 0x2, 0x8, // alignment=2^2, offset=8
  4207  				},
  4208  			},
  4209  			{
  4210  				name: "memory.atomic.wait64",
  4211  				body: []byte{
  4212  					OpcodeI32Const, 0x0,
  4213  					OpcodeI64Const, 0x1,
  4214  					OpcodeI64Const, 0x2,
  4215  					OpcodeAtomicPrefix, OpcodeAtomicMemoryWait64, 0x3, 0x8, // alignment=2^3, offset=8
  4216  				},
  4217  			},
  4218  			{
  4219  				name: "memory.atomic.notify",
  4220  				body: []byte{
  4221  					OpcodeI32Const, 0x0,
  4222  					OpcodeI32Const, 0x1,
  4223  					OpcodeAtomicPrefix, OpcodeAtomicMemoryNotify, 0x2, 0x8, // alignment=2^2, offset=8
  4224  				},
  4225  			},
  4226  			{
  4227  				name: "memory.atomic.fence",
  4228  				body: []byte{
  4229  					OpcodeAtomicPrefix, OpcodeAtomicFence, 0x0,
  4230  				},
  4231  				noDropBeforeReturn: true,
  4232  			},
  4233  		}
  4234  
  4235  		for _, tt := range tests {
  4236  			tc := tt
  4237  			t.Run(tc.name, func(t *testing.T) {
  4238  				body := append([]byte{}, tc.body...)
  4239  				if !tt.noDropBeforeReturn {
  4240  					body = append(body, OpcodeDrop)
  4241  				}
  4242  				body = append(body, OpcodeEnd)
  4243  				m := &Module{
  4244  					TypeSection:     []FunctionType{v_v},
  4245  					FunctionSection: []Index{0},
  4246  					CodeSection:     []Code{{Body: body}},
  4247  				}
  4248  
  4249  				t.Run("with memory", func(t *testing.T) {
  4250  					err := m.validateFunction(&stacks{}, api.CoreFeaturesV2,
  4251  						0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil))
  4252  					require.NoError(t, err)
  4253  				})
  4254  
  4255  				t.Run("without memory", func(t *testing.T) {
  4256  					err := m.validateFunction(&stacks{}, api.CoreFeaturesV2,
  4257  						0, []Index{0}, nil, nil, []Table{}, nil, bytes.NewReader(nil))
  4258  					// Only fence doesn't require memory
  4259  					if tc.name == "memory.atomic.fence" {
  4260  						require.NoError(t, err)
  4261  					} else {
  4262  						require.Error(t, err, fmt.Sprintf("memory must exist for %s", tc.name))
  4263  					}
  4264  				})
  4265  			})
  4266  		}
  4267  	})
  4268  
  4269  	t.Run("atomic.fence bad immediate", func(t *testing.T) {
  4270  		body := []byte{
  4271  			OpcodeAtomicPrefix, OpcodeAtomicFence, 0x1,
  4272  			OpcodeEnd,
  4273  		}
  4274  		m := &Module{
  4275  			TypeSection:     []FunctionType{v_v},
  4276  			FunctionSection: []Index{0},
  4277  			CodeSection:     []Code{{Body: body}},
  4278  		}
  4279  		err := m.validateFunction(&stacks{}, api.CoreFeaturesV2,
  4280  			0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil))
  4281  		require.Error(t, err, "invalid immediate value for atomic.fence")
  4282  	})
  4283  
  4284  	t.Run("bad alignment", func(t *testing.T) {
  4285  		tests := []struct {
  4286  			name               string
  4287  			body               []byte
  4288  			noDropBeforeReturn bool
  4289  		}{
  4290  			{
  4291  				name: "i32.atomic.load8_u",
  4292  				body: []byte{
  4293  					OpcodeI32Const, 0x0,
  4294  					OpcodeAtomicPrefix, OpcodeAtomicI32Load8U, 0x1, 0x8, // alignment=2^1, offset=8
  4295  				},
  4296  			},
  4297  			{
  4298  				name: "i32.atomic.load16_u",
  4299  				body: []byte{
  4300  					OpcodeI32Const, 0x0,
  4301  					OpcodeAtomicPrefix, OpcodeAtomicI32Load16U, 0x2, 0x8, // alignment=2^2, offset=8
  4302  				},
  4303  			},
  4304  			{
  4305  				name: "i32.atomic.load",
  4306  				body: []byte{
  4307  					OpcodeI32Const, 0x0,
  4308  					OpcodeAtomicPrefix, OpcodeAtomicI32Load, 0x3, 0x8, // alignment=2^3, offset=8
  4309  				},
  4310  			},
  4311  			{
  4312  				name: "i64.atomic.load8_u",
  4313  				body: []byte{
  4314  					OpcodeI32Const, 0x0,
  4315  					OpcodeAtomicPrefix, OpcodeAtomicI64Load8U, 0x1, 0x8, // alignment=2^1, offset=8
  4316  				},
  4317  			},
  4318  			{
  4319  				name: "i64.atomic.load16_u",
  4320  				body: []byte{
  4321  					OpcodeI32Const, 0x0,
  4322  					OpcodeAtomicPrefix, OpcodeAtomicI64Load16U, 0x2, 0x8, // alignment=2^2, offset=8
  4323  				},
  4324  			},
  4325  			{
  4326  				name: "i64.atomic.load32_u",
  4327  				body: []byte{
  4328  					OpcodeI32Const, 0x0,
  4329  					OpcodeAtomicPrefix, OpcodeAtomicI64Load32U, 0x3, 0x8, // alignment=2^3, offset=8
  4330  				},
  4331  			},
  4332  			{
  4333  				name: "i64.atomic.load",
  4334  				body: []byte{
  4335  					OpcodeI32Const, 0x0,
  4336  					OpcodeAtomicPrefix, OpcodeAtomicI64Load, 0x4, 0x8, // alignment=2^4, offset=8
  4337  				},
  4338  			},
  4339  			{
  4340  				name: "i32.atomic.store8",
  4341  				body: []byte{
  4342  					OpcodeI32Const, 0x1,
  4343  					OpcodeI32Const, 0x0,
  4344  					OpcodeAtomicPrefix, OpcodeAtomicI32Store8, 0x1, 0x8, // alignment=2^1, offset=8
  4345  				},
  4346  				noDropBeforeReturn: true,
  4347  			},
  4348  			{
  4349  				name: "i32.atomic.store16",
  4350  				body: []byte{
  4351  					OpcodeI32Const, 0x1,
  4352  					OpcodeI32Const, 0x0,
  4353  					OpcodeAtomicPrefix, OpcodeAtomicI32Store16, 0x2, 0x8, // alignment=2^2, offset=8
  4354  				},
  4355  				noDropBeforeReturn: true,
  4356  			},
  4357  			{
  4358  				name: "i32.atomic.store",
  4359  				body: []byte{
  4360  					OpcodeI32Const, 0x1,
  4361  					OpcodeI32Const, 0x0,
  4362  					OpcodeAtomicPrefix, OpcodeAtomicI32Store, 0x3, 0x8, // alignment=2^3, offset=8
  4363  				},
  4364  				noDropBeforeReturn: true,
  4365  			},
  4366  			{
  4367  				name: "i64.atomic.store8",
  4368  				body: []byte{
  4369  					OpcodeI32Const, 0x0,
  4370  					OpcodeI64Const, 0x1,
  4371  					OpcodeAtomicPrefix, OpcodeAtomicI64Store8, 0x1, 0x8, // alignment=2^1, offset=8
  4372  				},
  4373  				noDropBeforeReturn: true,
  4374  			},
  4375  			{
  4376  				name: "i64.atomic.store16",
  4377  				body: []byte{
  4378  					OpcodeI32Const, 0x0,
  4379  					OpcodeI64Const, 0x1,
  4380  					OpcodeAtomicPrefix, OpcodeAtomicI64Store16, 0x2, 0x8, // alignment=2^2, offset=8
  4381  				},
  4382  				noDropBeforeReturn: true,
  4383  			},
  4384  			{
  4385  				name: "i64.atomic.store32",
  4386  				body: []byte{
  4387  					OpcodeI32Const, 0x0,
  4388  					OpcodeI64Const, 0x1,
  4389  					OpcodeAtomicPrefix, OpcodeAtomicI64Store32, 0x3, 0x8, // alignment=2^3, offset=8
  4390  				},
  4391  				noDropBeforeReturn: true,
  4392  			},
  4393  			{
  4394  				name: "i64.atomic.store",
  4395  				body: []byte{
  4396  					OpcodeI32Const, 0x0,
  4397  					OpcodeI64Const, 0x1,
  4398  					OpcodeAtomicPrefix, OpcodeAtomicI64Store, 0x4, 0x8, // alignment=2^4, offset=8
  4399  				},
  4400  				noDropBeforeReturn: true,
  4401  			},
  4402  			{
  4403  				name: "i32.atomic.rmw8.add_u",
  4404  				body: []byte{
  4405  					OpcodeI32Const, 0x0,
  4406  					OpcodeI32Const, 0x1,
  4407  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AddU, 0x1, 0x8, // alignment=2^1, offset=8
  4408  				},
  4409  			},
  4410  			{
  4411  				name: "i32.atomic.rmw16.add_u",
  4412  				body: []byte{
  4413  					OpcodeI32Const, 0x0,
  4414  					OpcodeI32Const, 0x1,
  4415  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AddU, 0x2, 0x8, // alignment=2^2, offset=8
  4416  				},
  4417  			},
  4418  			{
  4419  				name: "i32.atomic.rmw.add",
  4420  				body: []byte{
  4421  					OpcodeI32Const, 0x0,
  4422  					OpcodeI32Const, 0x1,
  4423  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwAdd, 0x3, 0x8, // alignment=2^3, offset=8
  4424  				},
  4425  			},
  4426  			{
  4427  				name: "i64.atomic.rmw8.add_u",
  4428  				body: []byte{
  4429  					OpcodeI32Const, 0x0,
  4430  					OpcodeI64Const, 0x1,
  4431  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AddU, 0x1, 0x8, // alignment=2^1, offset=8
  4432  				},
  4433  			},
  4434  			{
  4435  				name: "i64.atomic.rmw16.add_u",
  4436  				body: []byte{
  4437  					OpcodeI32Const, 0x0,
  4438  					OpcodeI64Const, 0x1,
  4439  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AddU, 0x2, 0x8, // alignment=2^2, offset=8
  4440  				},
  4441  			},
  4442  			{
  4443  				name: "i64.atomic.rmw32.add_u",
  4444  				body: []byte{
  4445  					OpcodeI32Const, 0x0,
  4446  					OpcodeI64Const, 0x1,
  4447  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AddU, 0x3, 0x8, // alignment=2^3, offset=8
  4448  				},
  4449  			},
  4450  			{
  4451  				name: "i64.atomic.rmw.add",
  4452  				body: []byte{
  4453  					OpcodeI32Const, 0x0,
  4454  					OpcodeI64Const, 0x1,
  4455  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwAdd, 0x4, 0x8, // alignment=2^4, offset=8
  4456  				},
  4457  			},
  4458  			{
  4459  				name: "i32.atomic.rmw8.sub_u",
  4460  				body: []byte{
  4461  					OpcodeI32Const, 0x0,
  4462  					OpcodeI32Const, 0x1,
  4463  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8SubU, 0x1, 0x8, // alignment=2^1, offset=8
  4464  				},
  4465  			},
  4466  			{
  4467  				name: "i32.atomic.rmw16.sub_u",
  4468  				body: []byte{
  4469  					OpcodeI32Const, 0x0,
  4470  					OpcodeI32Const, 0x1,
  4471  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16SubU, 0x2, 0x8, // alignment=2^2, offset=8
  4472  				},
  4473  			},
  4474  			{
  4475  				name: "i32.atomic.rmw.sub",
  4476  				body: []byte{
  4477  					OpcodeI32Const, 0x0,
  4478  					OpcodeI32Const, 0x1,
  4479  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwSub, 0x3, 0x8, // alignment=2^3, offset=8
  4480  				},
  4481  			},
  4482  			{
  4483  				name: "i64.atomic.rmw8.sub_u",
  4484  				body: []byte{
  4485  					OpcodeI32Const, 0x0,
  4486  					OpcodeI64Const, 0x1,
  4487  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8SubU, 0x1, 0x8, // alignment=2^1, offset=8
  4488  				},
  4489  			},
  4490  			{
  4491  				name: "i64.atomic.rmw16.sub_u",
  4492  				body: []byte{
  4493  					OpcodeI32Const, 0x0,
  4494  					OpcodeI64Const, 0x1,
  4495  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16SubU, 0x2, 0x8, // alignment=2^2, offset=8
  4496  				},
  4497  			},
  4498  			{
  4499  				name: "i64.atomic.rmw32.sub_u",
  4500  				body: []byte{
  4501  					OpcodeI32Const, 0x0,
  4502  					OpcodeI64Const, 0x1,
  4503  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32SubU, 0x3, 0x8, // alignment=2^3, offset=8
  4504  				},
  4505  			},
  4506  			{
  4507  				name: "i64.atomic.rmw.sub",
  4508  				body: []byte{
  4509  					OpcodeI32Const, 0x0,
  4510  					OpcodeI64Const, 0x1,
  4511  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwSub, 0x4, 0x8, // alignment=2^4, offset=8
  4512  				},
  4513  			},
  4514  			{
  4515  				name: "i32.atomic.rmw8.and_u",
  4516  				body: []byte{
  4517  					OpcodeI32Const, 0x0,
  4518  					OpcodeI32Const, 0x1,
  4519  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8AndU, 0x1, 0x8, // alignment=2^1, offset=8
  4520  				},
  4521  			},
  4522  			{
  4523  				name: "i32.atomic.rmw16.and_u",
  4524  				body: []byte{
  4525  					OpcodeI32Const, 0x0,
  4526  					OpcodeI32Const, 0x1,
  4527  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16AndU, 0x2, 0x8, // alignment=2^2, offset=8
  4528  				},
  4529  			},
  4530  			{
  4531  				name: "i32.atomic.rmw.and",
  4532  				body: []byte{
  4533  					OpcodeI32Const, 0x0,
  4534  					OpcodeI32Const, 0x1,
  4535  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwAnd, 0x3, 0x8, // alignment=2^3, offset=8
  4536  				},
  4537  			},
  4538  			{
  4539  				name: "i64.atomic.rmw8.and_u",
  4540  				body: []byte{
  4541  					OpcodeI32Const, 0x0,
  4542  					OpcodeI64Const, 0x1,
  4543  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8AndU, 0x1, 0x8, // alignment=2^1, offset=8
  4544  				},
  4545  			},
  4546  			{
  4547  				name: "i64.atomic.rmw16.and_u",
  4548  				body: []byte{
  4549  					OpcodeI32Const, 0x0,
  4550  					OpcodeI64Const, 0x1,
  4551  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16AndU, 0x2, 0x8, // alignment=2^2, offset=8
  4552  				},
  4553  			},
  4554  			{
  4555  				name: "i64.atomic.rmw32.and_u",
  4556  				body: []byte{
  4557  					OpcodeI32Const, 0x0,
  4558  					OpcodeI64Const, 0x1,
  4559  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32AndU, 0x3, 0x8, // alignment=2^3, offset=8
  4560  				},
  4561  			},
  4562  			{
  4563  				name: "i64.atomic.rmw.and",
  4564  				body: []byte{
  4565  					OpcodeI32Const, 0x0,
  4566  					OpcodeI64Const, 0x1,
  4567  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwAnd, 0x4, 0x8, // alignment=2^4, offset=8
  4568  				},
  4569  			},
  4570  			{
  4571  				name: "i32.atomic.rmw8.or",
  4572  				body: []byte{
  4573  					OpcodeI32Const, 0x0,
  4574  					OpcodeI32Const, 0x1,
  4575  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8OrU, 0x1, 0x8, // alignment=2^1, offset=8
  4576  				},
  4577  			},
  4578  			{
  4579  				name: "i32.atomic.rmw16.or_u",
  4580  				body: []byte{
  4581  					OpcodeI32Const, 0x0,
  4582  					OpcodeI32Const, 0x1,
  4583  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16OrU, 0x2, 0x8, // alignment=2^2, offset=8
  4584  				},
  4585  			},
  4586  			{
  4587  				name: "i32.atomic.rmw.or",
  4588  				body: []byte{
  4589  					OpcodeI32Const, 0x0,
  4590  					OpcodeI32Const, 0x1,
  4591  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwOr, 0x3, 0x8, // alignment=2^3, offset=8
  4592  				},
  4593  			},
  4594  			{
  4595  				name: "i64.atomic.rmw8.or_u",
  4596  				body: []byte{
  4597  					OpcodeI32Const, 0x0,
  4598  					OpcodeI64Const, 0x1,
  4599  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8OrU, 0x1, 0x8, // alignment=2^1, offset=8
  4600  				},
  4601  			},
  4602  			{
  4603  				name: "i64.atomic.rmw16.or_u",
  4604  				body: []byte{
  4605  					OpcodeI32Const, 0x0,
  4606  					OpcodeI64Const, 0x1,
  4607  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16OrU, 0x2, 0x8, // alignment=2^2, offset=8
  4608  				},
  4609  			},
  4610  			{
  4611  				name: "i64.atomic.rmw32.or_u",
  4612  				body: []byte{
  4613  					OpcodeI32Const, 0x0,
  4614  					OpcodeI64Const, 0x1,
  4615  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32OrU, 0x3, 0x8, // alignment=2^3, offset=8
  4616  				},
  4617  			},
  4618  			{
  4619  				name: "i64.atomic.rmw.or",
  4620  				body: []byte{
  4621  					OpcodeI32Const, 0x0,
  4622  					OpcodeI64Const, 0x1,
  4623  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwOr, 0x4, 0x8, // alignment=2^4, offset=8
  4624  				},
  4625  			},
  4626  			{
  4627  				name: "i32.atomic.rmw8.xor_u",
  4628  				body: []byte{
  4629  					OpcodeI32Const, 0x0,
  4630  					OpcodeI32Const, 0x1,
  4631  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XorU, 0x1, 0x8, // alignment=2^1, offset=8
  4632  				},
  4633  			},
  4634  			{
  4635  				name: "i32.atomic.rmw16.xor_u",
  4636  				body: []byte{
  4637  					OpcodeI32Const, 0x0,
  4638  					OpcodeI32Const, 0x1,
  4639  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XorU, 0x2, 0x8, // alignment=2^2, offset=8
  4640  				},
  4641  			},
  4642  			{
  4643  				name: "i32.atomic.rmw.xor",
  4644  				body: []byte{
  4645  					OpcodeI32Const, 0x0,
  4646  					OpcodeI32Const, 0x1,
  4647  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwXor, 0x3, 0x8, // alignment=2^3, offset=8
  4648  				},
  4649  			},
  4650  			{
  4651  				name: "i64.atomic.rmw8.xor_u",
  4652  				body: []byte{
  4653  					OpcodeI32Const, 0x0,
  4654  					OpcodeI64Const, 0x1,
  4655  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XorU, 0x1, 0x8, // alignment=2^1, offset=8
  4656  				},
  4657  			},
  4658  			{
  4659  				name: "i64.atomic.rmw16.xor_u",
  4660  				body: []byte{
  4661  					OpcodeI32Const, 0x0,
  4662  					OpcodeI64Const, 0x1,
  4663  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XorU, 0x2, 0x8, // alignment=2^2, offset=8
  4664  				},
  4665  			},
  4666  			{
  4667  				name: "i64.atomic.rmw32.xor_u",
  4668  				body: []byte{
  4669  					OpcodeI32Const, 0x0,
  4670  					OpcodeI64Const, 0x1,
  4671  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XorU, 0x3, 0x8, // alignment=2^3, offset=8
  4672  				},
  4673  			},
  4674  			{
  4675  				name: "i64.atomic.rmw.xor",
  4676  				body: []byte{
  4677  					OpcodeI32Const, 0x0,
  4678  					OpcodeI64Const, 0x1,
  4679  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwXor, 0x4, 0x8, // alignment=2^4, offset=8
  4680  				},
  4681  			},
  4682  			{
  4683  				name: "i32.atomic.rmw8.xchg_u",
  4684  				body: []byte{
  4685  					OpcodeI32Const, 0x0,
  4686  					OpcodeI32Const, 0x1,
  4687  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8XchgU, 0x1, 0x8, // alignment=2^1, offset=8
  4688  				},
  4689  			},
  4690  			{
  4691  				name: "i32.atomic.rmw16.xchg_u",
  4692  				body: []byte{
  4693  					OpcodeI32Const, 0x0,
  4694  					OpcodeI32Const, 0x1,
  4695  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16XchgU, 0x2, 0x8, // alignment=2^2, offset=8
  4696  				},
  4697  			},
  4698  			{
  4699  				name: "i32.atomic.rmw.xchg",
  4700  				body: []byte{
  4701  					OpcodeI32Const, 0x0,
  4702  					OpcodeI32Const, 0x1,
  4703  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwXchg, 0x3, 0x8, // alignment=2^3, offset=8
  4704  				},
  4705  			},
  4706  			{
  4707  				name: "i64.atomic.rmw8.xchg_u",
  4708  				body: []byte{
  4709  					OpcodeI32Const, 0x0,
  4710  					OpcodeI64Const, 0x1,
  4711  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8XchgU, 0x1, 0x8, // alignment=2^1, offset=8
  4712  				},
  4713  			},
  4714  			{
  4715  				name: "i64.atomic.rmw16.xchg_u",
  4716  				body: []byte{
  4717  					OpcodeI32Const, 0x0,
  4718  					OpcodeI64Const, 0x1,
  4719  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16XchgU, 0x2, 0x8, // alignment=2^2, offset=8
  4720  				},
  4721  			},
  4722  			{
  4723  				name: "i64.atomic.rmw32.xchg_u",
  4724  				body: []byte{
  4725  					OpcodeI32Const, 0x0,
  4726  					OpcodeI64Const, 0x1,
  4727  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32XchgU, 0x3, 0x8, // alignment=2^3, offset=8
  4728  				},
  4729  			},
  4730  			{
  4731  				name: "i64.atomic.rmw.xchg",
  4732  				body: []byte{
  4733  					OpcodeI32Const, 0x0,
  4734  					OpcodeI64Const, 0x1,
  4735  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwXchg, 0x4, 0x8, // alignment=2^4, offset=8
  4736  				},
  4737  			},
  4738  			{
  4739  				name: "i32.atomic.rmw8.cmpxchg_u",
  4740  				body: []byte{
  4741  					OpcodeI32Const, 0x0,
  4742  					OpcodeI32Const, 0x1,
  4743  					OpcodeI32Const, 0x2,
  4744  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw8CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8
  4745  				},
  4746  			},
  4747  			{
  4748  				name: "i32.atomic.rmw16.cmpxchg_u",
  4749  				body: []byte{
  4750  					OpcodeI32Const, 0x0,
  4751  					OpcodeI32Const, 0x1,
  4752  					OpcodeI32Const, 0x2,
  4753  					OpcodeAtomicPrefix, OpcodeAtomicI32Rmw16CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8
  4754  				},
  4755  			},
  4756  			{
  4757  				name: "i32.atomic.rmw.cmpxchg",
  4758  				body: []byte{
  4759  					OpcodeI32Const, 0x0,
  4760  					OpcodeI32Const, 0x1,
  4761  					OpcodeI32Const, 0x2,
  4762  					OpcodeAtomicPrefix, OpcodeAtomicI32RmwCmpxchg, 0x3, 0x8, // alignment=2^3, offset=8
  4763  				},
  4764  			},
  4765  			{
  4766  				name: "i64.atomic.rmw8.xchg_u",
  4767  				body: []byte{
  4768  					OpcodeI32Const, 0x0,
  4769  					OpcodeI64Const, 0x1,
  4770  					OpcodeI64Const, 0x2,
  4771  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw8CmpxchgU, 0x1, 0x8, // alignment=2^1, offset=8
  4772  				},
  4773  			},
  4774  			{
  4775  				name: "i64.atomic.rmw16.cmpxchg_u",
  4776  				body: []byte{
  4777  					OpcodeI32Const, 0x0,
  4778  					OpcodeI64Const, 0x1,
  4779  					OpcodeI64Const, 0x2,
  4780  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw16CmpxchgU, 0x2, 0x8, // alignment=2^2, offset=8
  4781  				},
  4782  			},
  4783  			{
  4784  				name: "i64.atomic.rmw32.cmpxchg_u",
  4785  				body: []byte{
  4786  					OpcodeI32Const, 0x0,
  4787  					OpcodeI64Const, 0x1,
  4788  					OpcodeI64Const, 0x1,
  4789  					OpcodeAtomicPrefix, OpcodeAtomicI64Rmw32CmpxchgU, 0x3, 0x8, // alignment=2^3, offset=8
  4790  				},
  4791  			},
  4792  			{
  4793  				name: "i64.atomic.rmw.cmpxchg",
  4794  				body: []byte{
  4795  					OpcodeI32Const, 0x0,
  4796  					OpcodeI64Const, 0x1,
  4797  					OpcodeI64Const, 0x2,
  4798  					OpcodeAtomicPrefix, OpcodeAtomicI64RmwCmpxchg, 0x4, 0x8, // alignment=2^4, offset=8
  4799  				},
  4800  			},
  4801  			{
  4802  				name: "memory.atomic.wait32",
  4803  				body: []byte{
  4804  					OpcodeI32Const, 0x0,
  4805  					OpcodeI32Const, 0x1,
  4806  					OpcodeI64Const, 0x2,
  4807  					OpcodeAtomicPrefix, OpcodeAtomicMemoryWait32, 0x3, 0x8, // alignment=2^3, offset=8
  4808  				},
  4809  			},
  4810  			{
  4811  				name: "memory.atomic.wait64",
  4812  				body: []byte{
  4813  					OpcodeI32Const, 0x0,
  4814  					OpcodeI64Const, 0x1,
  4815  					OpcodeI64Const, 0x2,
  4816  					OpcodeAtomicPrefix, OpcodeAtomicMemoryWait64, 0x4, 0x8, // alignment=2^4, offset=8
  4817  				},
  4818  			},
  4819  			{
  4820  				name: "memory.atomic.notify",
  4821  				body: []byte{
  4822  					OpcodeI32Const, 0x0,
  4823  					OpcodeI32Const, 0x1,
  4824  					OpcodeAtomicPrefix, OpcodeAtomicMemoryNotify, 0x3, 0x8, // alignment=2^3, offset=8
  4825  				},
  4826  			},
  4827  		}
  4828  
  4829  		for _, tt := range tests {
  4830  			tc := tt
  4831  			t.Run(tc.name, func(t *testing.T) {
  4832  				body := append([]byte{}, tc.body...)
  4833  				if !tt.noDropBeforeReturn {
  4834  					body = append(body, OpcodeDrop)
  4835  				}
  4836  				body = append(body, OpcodeEnd)
  4837  				m := &Module{
  4838  					TypeSection:     []FunctionType{v_v},
  4839  					FunctionSection: []Index{0},
  4840  					CodeSection:     []Code{{Body: body}},
  4841  				}
  4842  				err := m.validateFunction(&stacks{}, api.CoreFeaturesV2,
  4843  					0, []Index{0}, nil, &Memory{}, []Table{}, nil, bytes.NewReader(nil))
  4844  				require.Error(t, err, "invalid memory alignment")
  4845  			})
  4846  		}
  4847  	})
  4848  }