github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/wasm/func_validation_test.go (about)

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