wa-lang.org/wazero@v1.0.2/internal/wasm/func_validation_test.go (about)

     1  package wasm
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"wa-lang.org/wazero/api"
     9  	"wa-lang.org/wazero/internal/leb128"
    10  	"wa-lang.org/wazero/internal/testing/require"
    11  )
    12  
    13  func TestModule_ValidateFunction_validateFunctionWithMaxStackValues(t *testing.T) {
    14  	const max = 100
    15  	const valuesNum = max + 1
    16  
    17  	// Compile a function which has max+1 const instructions.
    18  	var body []byte
    19  	for i := 0; i < valuesNum; i++ {
    20  		body = append(body, OpcodeI32Const, 1)
    21  	}
    22  
    23  	// Drop all the consts so that if the max is higher, this function body would be sound.
    24  	for i := 0; i < valuesNum; i++ {
    25  		body = append(body, OpcodeDrop)
    26  	}
    27  
    28  	// Plus all functions must end with End opcode.
    29  	body = append(body, OpcodeEnd)
    30  
    31  	m := &Module{
    32  		TypeSection:     []*FunctionType{v_v},
    33  		FunctionSection: []Index{0},
    34  		CodeSection:     []*Code{{Body: body}},
    35  	}
    36  
    37  	t.Run("not exceed", func(t *testing.T) {
    38  		err := m.validateFunctionWithMaxStackValues(api.CoreFeaturesV1, 0, []Index{0}, nil, nil, nil, max+1, nil)
    39  		require.NoError(t, err)
    40  	})
    41  	t.Run("exceed", func(t *testing.T) {
    42  		err := m.validateFunctionWithMaxStackValues(api.CoreFeaturesV1, 0, []Index{0}, nil, nil, nil, max, nil)
    43  		require.Error(t, err)
    44  		expMsg := fmt.Sprintf("function may have %d stack values, which exceeds limit %d", valuesNum, max)
    45  		require.Equal(t, expMsg, err.Error())
    46  	})
    47  }
    48  
    49  func TestModule_ValidateFunction_SignExtensionOps(t *testing.T) {
    50  	tests := []struct {
    51  		input                Opcode
    52  		expectedErrOnDisable string
    53  	}{
    54  		{
    55  			input:                OpcodeI32Extend8S,
    56  			expectedErrOnDisable: "i32.extend8_s invalid as feature \"sign-extension-ops\" is disabled",
    57  		},
    58  		{
    59  			input:                OpcodeI32Extend16S,
    60  			expectedErrOnDisable: "i32.extend16_s invalid as feature \"sign-extension-ops\" is disabled",
    61  		},
    62  		{
    63  			input:                OpcodeI64Extend8S,
    64  			expectedErrOnDisable: "i64.extend8_s invalid as feature \"sign-extension-ops\" is disabled",
    65  		},
    66  		{
    67  			input:                OpcodeI64Extend16S,
    68  			expectedErrOnDisable: "i64.extend16_s invalid as feature \"sign-extension-ops\" is disabled",
    69  		},
    70  		{
    71  			input:                OpcodeI64Extend32S,
    72  			expectedErrOnDisable: "i64.extend32_s invalid as feature \"sign-extension-ops\" is disabled",
    73  		},
    74  	}
    75  
    76  	for _, tt := range tests {
    77  		tc := tt
    78  		t.Run(InstructionName(tc.input), func(t *testing.T) {
    79  			t.Run("disabled", func(t *testing.T) {
    80  				m := &Module{
    81  					TypeSection:     []*FunctionType{v_v},
    82  					FunctionSection: []Index{0},
    83  					CodeSection:     []*Code{{Body: []byte{tc.input}}},
    84  				}
    85  				err := m.validateFunction(api.CoreFeaturesV1, 0, []Index{0}, nil, nil, nil, nil)
    86  				require.EqualError(t, err, tc.expectedErrOnDisable)
    87  			})
    88  			t.Run("enabled", func(t *testing.T) {
    89  				is32bit := tc.input == OpcodeI32Extend8S || tc.input == OpcodeI32Extend16S
    90  				var body []byte
    91  				if is32bit {
    92  					body = append(body, OpcodeI32Const)
    93  				} else {
    94  					body = append(body, OpcodeI64Const)
    95  				}
    96  				body = append(body, tc.input, 123, OpcodeDrop, OpcodeEnd)
    97  				m := &Module{
    98  					TypeSection:     []*FunctionType{v_v},
    99  					FunctionSection: []Index{0},
   100  					CodeSection:     []*Code{{Body: body}},
   101  				}
   102  				err := m.validateFunction(api.CoreFeatureSignExtensionOps, 0, []Index{0}, nil, nil, nil, nil)
   103  				require.NoError(t, err)
   104  			})
   105  		})
   106  	}
   107  }
   108  
   109  func TestModule_ValidateFunction_NonTrappingFloatToIntConversion(t *testing.T) {
   110  	tests := []struct {
   111  		input                Opcode
   112  		expectedErrOnDisable string
   113  	}{
   114  		{
   115  			input:                OpcodeMiscI32TruncSatF32S,
   116  			expectedErrOnDisable: "i32.trunc_sat_f32_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   117  		},
   118  		{
   119  			input:                OpcodeMiscI32TruncSatF32U,
   120  			expectedErrOnDisable: "i32.trunc_sat_f32_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   121  		},
   122  		{
   123  			input:                OpcodeMiscI32TruncSatF64S,
   124  			expectedErrOnDisable: "i32.trunc_sat_f64_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   125  		},
   126  		{
   127  			input:                OpcodeMiscI32TruncSatF64U,
   128  			expectedErrOnDisable: "i32.trunc_sat_f64_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   129  		},
   130  		{
   131  			input:                OpcodeMiscI64TruncSatF32S,
   132  			expectedErrOnDisable: "i64.trunc_sat_f32_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   133  		},
   134  		{
   135  			input:                OpcodeMiscI64TruncSatF32U,
   136  			expectedErrOnDisable: "i64.trunc_sat_f32_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   137  		},
   138  		{
   139  			input:                OpcodeMiscI64TruncSatF64S,
   140  			expectedErrOnDisable: "i64.trunc_sat_f64_s invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   141  		},
   142  		{
   143  			input:                OpcodeMiscI64TruncSatF64U,
   144  			expectedErrOnDisable: "i64.trunc_sat_f64_u invalid as feature \"nontrapping-float-to-int-conversion\" is disabled",
   145  		},
   146  	}
   147  
   148  	for _, tt := range tests {
   149  		tc := tt
   150  		t.Run(InstructionName(tc.input), func(t *testing.T) {
   151  			t.Run("disabled", func(t *testing.T) {
   152  				m := &Module{
   153  					TypeSection:     []*FunctionType{v_v},
   154  					FunctionSection: []Index{0},
   155  					CodeSection:     []*Code{{Body: []byte{OpcodeMiscPrefix, tc.input}}},
   156  				}
   157  				err := m.validateFunction(api.CoreFeaturesV1, 0, []Index{0}, nil, nil, nil, nil)
   158  				require.EqualError(t, err, tc.expectedErrOnDisable)
   159  			})
   160  			t.Run("enabled", func(t *testing.T) {
   161  				var body []byte
   162  				switch tc.input {
   163  				case OpcodeMiscI32TruncSatF32S, OpcodeMiscI32TruncSatF32U, OpcodeMiscI64TruncSatF32S, OpcodeMiscI64TruncSatF32U:
   164  					body = []byte{OpcodeF32Const, 1, 2, 3, 4}
   165  				case OpcodeMiscI32TruncSatF64S, OpcodeMiscI32TruncSatF64U, OpcodeMiscI64TruncSatF64S, OpcodeMiscI64TruncSatF64U:
   166  					body = []byte{OpcodeF64Const, 1, 2, 3, 4, 5, 6, 7, 8}
   167  				}
   168  				body = append(body, OpcodeMiscPrefix, tc.input, OpcodeDrop, OpcodeEnd)
   169  
   170  				m := &Module{
   171  					TypeSection:     []*FunctionType{v_v},
   172  					FunctionSection: []Index{0},
   173  					CodeSection:     []*Code{{Body: body}},
   174  				}
   175  				err := m.validateFunction(api.CoreFeatureNonTrappingFloatToIntConversion, 0, []Index{0}, nil, nil, nil, nil)
   176  				require.NoError(t, err)
   177  			})
   178  		})
   179  	}
   180  }
   181  
   182  // TestModule_ValidateFunction_MultiValue only tests what can't yet be detected during compilation. These examples are
   183  // from test/core/if.wast from the commit that added "multi-value" support.
   184  //
   185  // See https://github.com/WebAssembly/spec/commit/484180ba3d9d7638ba1cb400b699ffede796927c
   186  func TestModule_ValidateFunction_MultiValue(t *testing.T) {
   187  	tests := []struct {
   188  		name                 string
   189  		module               *Module
   190  		expectedErrOnDisable string
   191  	}{
   192  		{
   193  			name: "block with function type",
   194  			module: &Module{
   195  				TypeSection:     []*FunctionType{v_f64f64},
   196  				FunctionSection: []Index{0},
   197  				CodeSection: []*Code{{Body: []byte{
   198  					OpcodeBlock, 0, // (block (result f64 f64)
   199  					OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x10, 0x40, // (f64.const 4)
   200  					OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x14, 0x40, // (f64.const 5)
   201  					OpcodeBr, 0,
   202  					OpcodeF64Add,
   203  					OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0x18, 0x40, // (f64.const 6)
   204  					OpcodeEnd,
   205  					OpcodeEnd,
   206  				}}},
   207  			},
   208  			expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled",
   209  		},
   210  		{
   211  			name: "if with function type", // a.k.a. "param"
   212  			module: &Module{
   213  				TypeSection:     []*FunctionType{i32_i32}, // (func (param i32) (result i32)
   214  				FunctionSection: []Index{0},
   215  				CodeSection: []*Code{{Body: []byte{
   216  					OpcodeI32Const, 1, // (i32.const 1)
   217  					OpcodeLocalGet, 0, OpcodeIf, 0, // (if (param i32) (result i32) (local.get 0)
   218  					OpcodeI32Const, 2, OpcodeI32Add, // (then (i32.const 2) (i32.add))
   219  					OpcodeElse, OpcodeI32Const, 0x7e, OpcodeI32Add, // (else (i32.const -2) (i32.add))
   220  					OpcodeEnd, // )
   221  					OpcodeEnd, // )
   222  				}}},
   223  			},
   224  			expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled",
   225  		},
   226  		{
   227  			name: "if with function type - br", // a.k.a. "params-break"
   228  			module: &Module{
   229  				TypeSection: []*FunctionType{
   230  					i32_i32,    // (func (param i32) (result i32)
   231  					i32i32_i32, // (if (param i32 i32) (result i32)
   232  				},
   233  				FunctionSection: []Index{0},
   234  				CodeSection: []*Code{{Body: []byte{
   235  					OpcodeI32Const, 1, // (i32.const 1)
   236  					OpcodeI32Const, 2, // (i32.const 2)
   237  					OpcodeLocalGet, 0, OpcodeIf, 1, // (if (param i32) (result i32) (local.get 0)
   238  					OpcodeI32Add, OpcodeBr, 0, // (then (i32.add) (br 0))
   239  					OpcodeElse, OpcodeI32Sub, OpcodeBr, 0, // (else (i32.sub) (br 0))
   240  					OpcodeEnd, // )
   241  					OpcodeEnd, // )
   242  				}}},
   243  			},
   244  			expectedErrOnDisable: "read block: block with function type return invalid as feature \"multi-value\" is disabled",
   245  		},
   246  	}
   247  
   248  	for _, tt := range tests {
   249  		tc := tt
   250  		t.Run(tc.name, func(t *testing.T) {
   251  			t.Run("disabled", func(t *testing.T) {
   252  				err := tc.module.validateFunction(api.CoreFeaturesV1, 0, []Index{0}, nil, nil, nil, nil)
   253  				require.EqualError(t, err, tc.expectedErrOnDisable)
   254  			})
   255  			t.Run("enabled", func(t *testing.T) {
   256  				err := tc.module.validateFunction(api.CoreFeatureMultiValue, 0, []Index{0}, nil, nil, nil, nil)
   257  				require.NoError(t, err)
   258  			})
   259  		})
   260  	}
   261  }
   262  
   263  func TestModule_ValidateFunction_BulkMemoryOperations(t *testing.T) {
   264  	t.Run("ok", func(t *testing.T) {
   265  		for _, op := range []OpcodeMisc{
   266  			OpcodeMiscMemoryInit, OpcodeMiscDataDrop, OpcodeMiscMemoryCopy,
   267  			OpcodeMiscMemoryFill, OpcodeMiscTableInit, OpcodeMiscElemDrop, OpcodeMiscTableCopy,
   268  		} {
   269  			t.Run(MiscInstructionName(op), func(t *testing.T) {
   270  				var body []byte
   271  				if op != OpcodeMiscDataDrop && op != OpcodeMiscElemDrop {
   272  					body = append(body, OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeI32Const, 3)
   273  				}
   274  
   275  				body = append(body, OpcodeMiscPrefix, op)
   276  				if op != OpcodeMiscDataDrop && op != OpcodeMiscMemoryFill && op != OpcodeMiscElemDrop {
   277  					body = append(body, 0, 0)
   278  				} else {
   279  					body = append(body, 0)
   280  				}
   281  
   282  				body = append(body, OpcodeEnd)
   283  
   284  				c := uint32(0)
   285  				m := &Module{
   286  					TypeSection:      []*FunctionType{v_v},
   287  					FunctionSection:  []Index{0},
   288  					CodeSection:      []*Code{{Body: body}},
   289  					DataSection:      []*DataSegment{{}},
   290  					ElementSection:   []*ElementSegment{{}},
   291  					DataCountSection: &c,
   292  				}
   293  				err := m.validateFunction(api.CoreFeatureBulkMemoryOperations, 0, []Index{0}, nil, &Memory{}, []*Table{{}, {}}, nil)
   294  				require.NoError(t, err)
   295  			})
   296  		}
   297  	})
   298  	t.Run("errors", func(t *testing.T) {
   299  		tests := []struct {
   300  			body                []byte
   301  			dataSection         []*DataSegment
   302  			elementSection      []*ElementSegment
   303  			dataCountSectionNil bool
   304  			memory              *Memory
   305  			tables              []*Table
   306  			flag                api.CoreFeatures
   307  			expectedErr         string
   308  		}{
   309  			// memory.init
   310  			{
   311  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
   312  				flag:        api.CoreFeatureBulkMemoryOperations,
   313  				memory:      nil,
   314  				expectedErr: "memory must exist for memory.init",
   315  			},
   316  			{
   317  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
   318  				flag:        api.CoreFeaturesV1,
   319  				expectedErr: `memory.init invalid as feature "bulk-memory-operations" is disabled`,
   320  			},
   321  			{
   322  				body:                []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
   323  				flag:                api.CoreFeatureBulkMemoryOperations,
   324  				dataCountSectionNil: true,
   325  				expectedErr:         `memory must exist for memory.init`,
   326  			},
   327  			{
   328  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit},
   329  				flag:        api.CoreFeatureBulkMemoryOperations,
   330  				memory:      &Memory{},
   331  				expectedErr: "failed to read data segment index for memory.init: EOF",
   332  			},
   333  			{
   334  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 100 /* data section out of range */},
   335  				flag:        api.CoreFeatureBulkMemoryOperations,
   336  				memory:      &Memory{},
   337  				dataSection: []*DataSegment{{}},
   338  				expectedErr: "index 100 out of range of data section(len=1)",
   339  			},
   340  			{
   341  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0},
   342  				flag:        api.CoreFeatureBulkMemoryOperations,
   343  				memory:      &Memory{},
   344  				dataSection: []*DataSegment{{}},
   345  				expectedErr: "failed to read memory index for memory.init: EOF",
   346  			},
   347  			{
   348  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 1},
   349  				flag:        api.CoreFeatureBulkMemoryOperations,
   350  				memory:      &Memory{},
   351  				dataSection: []*DataSegment{{}},
   352  				expectedErr: "memory.init reserved byte must be zero encoded with 1 byte",
   353  			},
   354  			{
   355  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0},
   356  				flag:        api.CoreFeatureBulkMemoryOperations,
   357  				memory:      &Memory{},
   358  				dataSection: []*DataSegment{{}},
   359  				expectedErr: "cannot pop the operand for memory.init: i32 missing",
   360  			},
   361  			{
   362  				body:        []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0},
   363  				flag:        api.CoreFeatureBulkMemoryOperations,
   364  				memory:      &Memory{},
   365  				dataSection: []*DataSegment{{}},
   366  				expectedErr: "cannot pop the operand for memory.init: i32 missing",
   367  			},
   368  			{
   369  				body:        []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryInit, 0, 0},
   370  				flag:        api.CoreFeatureBulkMemoryOperations,
   371  				memory:      &Memory{},
   372  				dataSection: []*DataSegment{{}},
   373  				expectedErr: "cannot pop the operand for memory.init: i32 missing",
   374  			},
   375  			// data.drop
   376  			{
   377  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop},
   378  				flag:        api.CoreFeaturesV1,
   379  				expectedErr: `data.drop invalid as feature "bulk-memory-operations" is disabled`,
   380  			},
   381  			{
   382  				body:                []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop},
   383  				dataCountSectionNil: true,
   384  				memory:              &Memory{},
   385  				flag:                api.CoreFeatureBulkMemoryOperations,
   386  				expectedErr:         `data.drop requires data count section`,
   387  			},
   388  			{
   389  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop},
   390  				flag:        api.CoreFeatureBulkMemoryOperations,
   391  				memory:      &Memory{},
   392  				expectedErr: "failed to read data segment index for data.drop: EOF",
   393  			},
   394  			{
   395  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscDataDrop, 100 /* data section out of range */},
   396  				flag:        api.CoreFeatureBulkMemoryOperations,
   397  				memory:      &Memory{},
   398  				dataSection: []*DataSegment{{}},
   399  				expectedErr: "index 100 out of range of data section(len=1)",
   400  			},
   401  			// memory.copy
   402  			{
   403  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy},
   404  				flag:        api.CoreFeatureBulkMemoryOperations,
   405  				memory:      nil,
   406  				expectedErr: "memory must exist for memory.copy",
   407  			},
   408  			{
   409  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy},
   410  				flag:        api.CoreFeaturesV1,
   411  				expectedErr: `memory.copy invalid as feature "bulk-memory-operations" is disabled`,
   412  			},
   413  			{
   414  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy},
   415  				flag:        api.CoreFeatureBulkMemoryOperations,
   416  				memory:      &Memory{},
   417  				expectedErr: `failed to read memory index for memory.copy: EOF`,
   418  			},
   419  			{
   420  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0},
   421  				flag:        api.CoreFeatureBulkMemoryOperations,
   422  				memory:      &Memory{},
   423  				expectedErr: "failed to read memory index for memory.copy: EOF",
   424  			},
   425  			{
   426  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 1},
   427  				flag:        api.CoreFeatureBulkMemoryOperations,
   428  				memory:      &Memory{},
   429  				expectedErr: "memory.copy reserved byte must be zero encoded with 1 byte",
   430  			},
   431  			{
   432  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0},
   433  				flag:        api.CoreFeatureBulkMemoryOperations,
   434  				memory:      &Memory{},
   435  				expectedErr: "cannot pop the operand for memory.copy: i32 missing",
   436  			},
   437  			{
   438  				body:        []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0},
   439  				flag:        api.CoreFeatureBulkMemoryOperations,
   440  				memory:      &Memory{},
   441  				expectedErr: "cannot pop the operand for memory.copy: i32 missing",
   442  			},
   443  			{
   444  				body:        []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryCopy, 0, 0},
   445  				flag:        api.CoreFeatureBulkMemoryOperations,
   446  				memory:      &Memory{},
   447  				expectedErr: "cannot pop the operand for memory.copy: i32 missing",
   448  			},
   449  			// memory.fill
   450  			{
   451  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill},
   452  				flag:        api.CoreFeatureBulkMemoryOperations,
   453  				memory:      nil,
   454  				expectedErr: "memory must exist for memory.fill",
   455  			},
   456  			{
   457  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill},
   458  				flag:        api.CoreFeaturesV1,
   459  				expectedErr: `memory.fill invalid as feature "bulk-memory-operations" is disabled`,
   460  			},
   461  			{
   462  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill},
   463  				flag:        api.CoreFeatureBulkMemoryOperations,
   464  				memory:      &Memory{},
   465  				expectedErr: `failed to read memory index for memory.fill: EOF`,
   466  			},
   467  			{
   468  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill, 1},
   469  				flag:        api.CoreFeatureBulkMemoryOperations,
   470  				memory:      &Memory{},
   471  				expectedErr: `memory.fill reserved byte must be zero encoded with 1 byte`,
   472  			},
   473  			{
   474  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0},
   475  				flag:        api.CoreFeatureBulkMemoryOperations,
   476  				memory:      &Memory{},
   477  				expectedErr: "cannot pop the operand for memory.fill: i32 missing",
   478  			},
   479  			{
   480  				body:        []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0},
   481  				flag:        api.CoreFeatureBulkMemoryOperations,
   482  				memory:      &Memory{},
   483  				expectedErr: "cannot pop the operand for memory.fill: i32 missing",
   484  			},
   485  			{
   486  				body:        []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscMemoryFill, 0},
   487  				flag:        api.CoreFeatureBulkMemoryOperations,
   488  				memory:      &Memory{},
   489  				expectedErr: "cannot pop the operand for memory.fill: i32 missing",
   490  			},
   491  			// table.init
   492  			{
   493  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableInit},
   494  				flag:        api.CoreFeaturesV1,
   495  				tables:      []*Table{{}},
   496  				expectedErr: `table.init invalid as feature "bulk-memory-operations" is disabled`,
   497  			},
   498  			{
   499  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableInit},
   500  				flag:        api.CoreFeatureBulkMemoryOperations,
   501  				tables:      []*Table{{}},
   502  				expectedErr: "failed to read element segment index for table.init: EOF",
   503  			},
   504  			{
   505  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 100 /* data section out of range */},
   506  				flag:           api.CoreFeatureBulkMemoryOperations,
   507  				tables:         []*Table{{}},
   508  				elementSection: []*ElementSegment{{}},
   509  				expectedErr:    "index 100 out of range of element section(len=1)",
   510  			},
   511  			{
   512  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0},
   513  				flag:           api.CoreFeatureBulkMemoryOperations,
   514  				tables:         []*Table{{}},
   515  				elementSection: []*ElementSegment{{}},
   516  				expectedErr:    "failed to read source table index for table.init: EOF",
   517  			},
   518  			{
   519  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 10},
   520  				flag:           api.CoreFeatureBulkMemoryOperations,
   521  				tables:         []*Table{{}},
   522  				elementSection: []*ElementSegment{{}},
   523  				expectedErr:    "source table index must be zero for table.init as feature \"reference-types\" is disabled",
   524  			},
   525  			{
   526  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 10},
   527  				flag:           api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
   528  				tables:         []*Table{{}},
   529  				elementSection: []*ElementSegment{{}},
   530  				expectedErr:    "table of index 10 not found",
   531  			},
   532  			{
   533  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 1},
   534  				flag:           api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
   535  				tables:         []*Table{{}, {Type: RefTypeExternref}},
   536  				elementSection: []*ElementSegment{{Type: RefTypeFuncref}},
   537  				expectedErr:    "type mismatch for table.init: element type funcref does not match table type externref",
   538  			},
   539  			{
   540  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0},
   541  				flag:           api.CoreFeatureBulkMemoryOperations,
   542  				tables:         []*Table{{}},
   543  				elementSection: []*ElementSegment{{}},
   544  				expectedErr:    "cannot pop the operand for table.init: i32 missing",
   545  			},
   546  			{
   547  				body:           []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0},
   548  				flag:           api.CoreFeatureBulkMemoryOperations,
   549  				tables:         []*Table{{}},
   550  				elementSection: []*ElementSegment{{}},
   551  				expectedErr:    "cannot pop the operand for table.init: i32 missing",
   552  			},
   553  			{
   554  				body:           []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableInit, 0, 0},
   555  				flag:           api.CoreFeatureBulkMemoryOperations,
   556  				tables:         []*Table{{}},
   557  				elementSection: []*ElementSegment{{}},
   558  				expectedErr:    "cannot pop the operand for table.init: i32 missing",
   559  			},
   560  			// elem.drop
   561  			{
   562  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop},
   563  				flag:        api.CoreFeaturesV1,
   564  				tables:      []*Table{{}},
   565  				expectedErr: `elem.drop invalid as feature "bulk-memory-operations" is disabled`,
   566  			},
   567  			{
   568  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop},
   569  				flag:        api.CoreFeatureBulkMemoryOperations,
   570  				tables:      []*Table{{}},
   571  				expectedErr: "failed to read element segment index for elem.drop: EOF",
   572  			},
   573  			{
   574  				body:           []byte{OpcodeMiscPrefix, OpcodeMiscElemDrop, 100 /* element section out of range */},
   575  				flag:           api.CoreFeatureBulkMemoryOperations,
   576  				tables:         []*Table{{}},
   577  				elementSection: []*ElementSegment{{}},
   578  				expectedErr:    "index 100 out of range of element section(len=1)",
   579  			},
   580  			// table.copy
   581  			{
   582  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy},
   583  				flag:        api.CoreFeaturesV1,
   584  				tables:      []*Table{{}},
   585  				expectedErr: `table.copy invalid as feature "bulk-memory-operations" is disabled`,
   586  			},
   587  			{
   588  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy},
   589  				flag:        api.CoreFeatureBulkMemoryOperations,
   590  				tables:      []*Table{{}},
   591  				expectedErr: `failed to read destination table index for table.copy: EOF`,
   592  			},
   593  			{
   594  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 10},
   595  				flag:        api.CoreFeatureBulkMemoryOperations,
   596  				tables:      []*Table{{}},
   597  				expectedErr: "destination table index must be zero for table.copy as feature \"reference-types\" is disabled",
   598  			},
   599  			{
   600  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3},
   601  				flag:        api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
   602  				tables:      []*Table{{}, {}},
   603  				expectedErr: "table of index 3 not found",
   604  			},
   605  			{
   606  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3},
   607  				flag:        api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
   608  				tables:      []*Table{{}, {}, {}, {}},
   609  				expectedErr: "failed to read source table index for table.copy: EOF",
   610  			},
   611  			{
   612  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 3},
   613  				flag:        api.CoreFeatureBulkMemoryOperations, // Multiple tables require api.CoreFeatureReferenceTypes.
   614  				tables:      []*Table{{}, {}, {}, {}},
   615  				expectedErr: "source table index must be zero for table.copy as feature \"reference-types\" is disabled",
   616  			},
   617  			{
   618  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 3, 1},
   619  				flag:        api.CoreFeatureBulkMemoryOperations | api.CoreFeatureReferenceTypes,
   620  				tables:      []*Table{{}, {Type: RefTypeFuncref}, {}, {Type: RefTypeExternref}},
   621  				expectedErr: "table type mismatch for table.copy: funcref (src) != externref (dst)",
   622  			},
   623  			{
   624  				body:        []byte{OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 0},
   625  				flag:        api.CoreFeatureBulkMemoryOperations,
   626  				tables:      []*Table{{}},
   627  				expectedErr: "cannot pop the operand for table.copy: i32 missing",
   628  			},
   629  			{
   630  				body:        []byte{OpcodeI32Const, 0, OpcodeMiscPrefix, OpcodeMiscTableCopy, 0, 0},
   631  				flag:        api.CoreFeatureBulkMemoryOperations,
   632  				tables:      []*Table{{}},
   633  				expectedErr: "cannot pop the operand for table.copy: i32 missing",
   634  			},
   635  			{
   636  				body:        []byte{OpcodeI32Const, 0, OpcodeI32Const, 0, 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  
   643  		for _, tt := range tests {
   644  			tc := tt
   645  			t.Run(tc.expectedErr, func(t *testing.T) {
   646  				m := &Module{
   647  					TypeSection:     []*FunctionType{v_v},
   648  					FunctionSection: []Index{0},
   649  					CodeSection:     []*Code{{Body: tc.body}},
   650  					ElementSection:  tc.elementSection,
   651  					DataSection:     tc.dataSection,
   652  				}
   653  				if !tc.dataCountSectionNil {
   654  					c := uint32(0)
   655  					m.DataCountSection = &c
   656  				}
   657  				err := m.validateFunction(tc.flag, 0, []Index{0}, nil, tc.memory, tc.tables, nil)
   658  				require.EqualError(t, err, tc.expectedErr)
   659  			})
   660  		}
   661  	})
   662  }
   663  
   664  var (
   665  	f32, f64, i32, i64, externref = ValueTypeF32, ValueTypeF64, ValueTypeI32, ValueTypeI64, ValueTypeExternref
   666  	f32i32_v                      = &FunctionType{Params: []ValueType{f32, i32}}
   667  	i32_i32                       = &FunctionType{Params: []ValueType{i32}, Results: []ValueType{i32}}
   668  	i32f64_v                      = &FunctionType{Params: []ValueType{i32, f64}}
   669  	i32i32_i32                    = &FunctionType{Params: []ValueType{i32, i32}, Results: []ValueType{i32}}
   670  	i32_v                         = &FunctionType{Params: []ValueType{i32}}
   671  	v_v                           = &FunctionType{}
   672  	v_f32                         = &FunctionType{Results: []ValueType{f32}}
   673  	v_f32f32                      = &FunctionType{Results: []ValueType{f32, f32}}
   674  	v_f64i32                      = &FunctionType{Results: []ValueType{f64, i32}}
   675  	v_f64f64                      = &FunctionType{Results: []ValueType{f64, f64}}
   676  	v_i32                         = &FunctionType{Results: []ValueType{i32}}
   677  	v_i32i32                      = &FunctionType{Results: []ValueType{i32, i32}}
   678  	v_i32i64                      = &FunctionType{Results: []ValueType{i32, i64}}
   679  	v_i64i64                      = &FunctionType{Results: []ValueType{i64, i64}}
   680  )
   681  
   682  // TestModule_ValidateFunction_TypeMismatchSpecTests are "type mismatch" tests when "multi-value" was merged.
   683  //
   684  // See https://github.com/WebAssembly/spec/commit/484180ba3d9d7638ba1cb400b699ffede796927c
   685  func TestModule_ValidateFunction_MultiValue_TypeMismatch(t *testing.T) {
   686  	tests := []struct {
   687  		name            string
   688  		module          *Module
   689  		expectedErr     string
   690  		enabledFeatures api.CoreFeatures
   691  	}{
   692  		// test/core/func.wast
   693  
   694  		{
   695  			name: `func.wast - type-empty-f64-i32`,
   696  			module: &Module{
   697  				TypeSection:     []*FunctionType{v_f64i32},
   698  				FunctionSection: []Index{0},
   699  				CodeSection:     []*Code{{Body: []byte{OpcodeEnd}}},
   700  			},
   701  			expectedErr: `not enough results
   702  	have ()
   703  	want (f64, i32)`,
   704  		},
   705  		{
   706  			name: `func.wast - type-value-void-vs-nums`,
   707  			module: &Module{
   708  				TypeSection:     []*FunctionType{v_i32i32},
   709  				FunctionSection: []Index{0},
   710  				CodeSection:     []*Code{{Body: []byte{OpcodeNop, OpcodeEnd}}},
   711  			},
   712  			expectedErr: `not enough results
   713  	have ()
   714  	want (i32, i32)`,
   715  		},
   716  		{
   717  			name: `func.wast - type-value-nums-vs-void`,
   718  			module: &Module{
   719  				TypeSection:     []*FunctionType{v_v},
   720  				FunctionSection: []Index{0},
   721  				CodeSection:     []*Code{{Body: []byte{OpcodeI32Const, 0, OpcodeI64Const, 0, OpcodeEnd}}},
   722  			},
   723  			expectedErr: `too many results
   724  	have (i32, i64)
   725  	want ()`,
   726  		},
   727  		{
   728  			name: `func.wast - type-value-num-vs-nums - v_f32f32 -> f32`,
   729  			module: &Module{
   730  				TypeSection:     []*FunctionType{v_f32f32},
   731  				FunctionSection: []Index{0},
   732  				CodeSection: []*Code{{Body: []byte{
   733  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
   734  					OpcodeEnd, // func
   735  				}}},
   736  			},
   737  			expectedErr: `not enough results
   738  	have (f32)
   739  	want (f32, f32)`,
   740  		},
   741  		{
   742  			name: `func.wast - type-value-num-vs-nums - v_f32 -> f32f32`,
   743  			module: &Module{
   744  				TypeSection:     []*FunctionType{v_f32},
   745  				FunctionSection: []Index{0},
   746  				CodeSection: []*Code{{Body: []byte{
   747  					OpcodeF32Const, 0, 0, 0, 0, OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0) (f32.const 0)
   748  					OpcodeEnd, // func
   749  				}}},
   750  			},
   751  			expectedErr: `too many results
   752  	have (f32, f32)
   753  	want (f32)`,
   754  		},
   755  		{
   756  			name: `func.wast - type-return-last-empty-vs-nums`,
   757  			module: &Module{
   758  				TypeSection:     []*FunctionType{v_f32f32},
   759  				FunctionSection: []Index{0},
   760  				CodeSection:     []*Code{{Body: []byte{OpcodeReturn, OpcodeEnd}}},
   761  			},
   762  			expectedErr: `not enough results
   763  	have ()
   764  	want (f32, f32)`,
   765  		},
   766  		{
   767  			name: `func.wast - type-return-last-void-vs-nums`,
   768  			module: &Module{
   769  				TypeSection:     []*FunctionType{v_i32i64},
   770  				FunctionSection: []Index{0},
   771  				CodeSection:     []*Code{{Body: []byte{OpcodeNop, OpcodeReturn, OpcodeEnd}}}, // (return (nop))
   772  			},
   773  			expectedErr: `not enough results
   774  	have ()
   775  	want (i32, i64)`,
   776  		},
   777  		{
   778  			name: `func.wast - type-return-last-num-vs-nums`,
   779  			module: &Module{
   780  				TypeSection:     []*FunctionType{v_i64i64},
   781  				FunctionSection: []Index{0},
   782  				CodeSection: []*Code{{Body: []byte{
   783  					OpcodeI64Const, 0, OpcodeReturn, // (return (i64.const 0))
   784  					OpcodeEnd, // func
   785  				}}},
   786  			},
   787  			expectedErr: `not enough results
   788  	have (i64)
   789  	want (i64, i64)`,
   790  		},
   791  		{
   792  			name: `func.wast - type-return-empty-vs-nums`,
   793  			// This should err because (return) precedes the values expected in the signature (i32i32):
   794  			//	(module (func $type-return-empty-vs-nums (result i32 i32)
   795  			//	  (return) (i32.const 1) (i32.const 2)
   796  			//	))
   797  			module: &Module{
   798  				TypeSection:     []*FunctionType{v_i32i32},
   799  				FunctionSection: []Index{0},
   800  				CodeSection: []*Code{{Body: []byte{
   801  					OpcodeReturn, OpcodeI32Const, 1, OpcodeI32Const, 2,
   802  					OpcodeEnd, // func
   803  				}}},
   804  			},
   805  			expectedErr: `not enough results
   806  	have ()
   807  	want (i32, i32)`,
   808  		},
   809  		{
   810  			name: `func.wast - type-return-partial-vs-nums`,
   811  			// This should err because (return) precedes one of the values expected in the signature (i32i32):
   812  			//	(module (func $type-return-partial-vs-nums (result i32 i32)
   813  			//	  (i32.const 1) (return) (i32.const 2)
   814  			//	))
   815  			module: &Module{
   816  				TypeSection:     []*FunctionType{v_i32i32},
   817  				FunctionSection: []Index{0},
   818  				CodeSection: []*Code{{Body: []byte{
   819  					OpcodeI32Const, 1, OpcodeReturn, OpcodeI32Const, 2,
   820  					OpcodeEnd, // func
   821  				}}},
   822  			},
   823  			expectedErr: `not enough results
   824  	have (i32)
   825  	want (i32, i32)`,
   826  		},
   827  		{
   828  			name: `func.wast - type-return-void-vs-nums`,
   829  			// This should err because (return) is empty due to nop, but the signature requires i32i32:
   830  			//	(module (func $type-return-void-vs-nums (result i32 i32)
   831  			//	  (return (nop)) (i32.const 1)
   832  			//	))
   833  			module: &Module{
   834  				TypeSection:     []*FunctionType{v_i32i32},
   835  				FunctionSection: []Index{0},
   836  				CodeSection: []*Code{{Body: []byte{
   837  					OpcodeNop, OpcodeReturn, // (return (nop))
   838  					OpcodeI32Const, 1, // (i32.const 1)
   839  					OpcodeEnd, // func
   840  				}}},
   841  			},
   842  			expectedErr: `not enough results
   843  	have ()
   844  	want (i32, i32)`,
   845  		},
   846  
   847  		{
   848  			name: `func.wast - type-return-num-vs-nums`,
   849  			module: &Module{
   850  				TypeSection:     []*FunctionType{v_i32i32},
   851  				FunctionSection: []Index{0},
   852  				CodeSection: []*Code{{Body: []byte{
   853  					OpcodeI64Const, 1, OpcodeReturn, // (return (i64.const 1))
   854  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2)
   855  					OpcodeEnd, // func
   856  				}}},
   857  			},
   858  			expectedErr: `not enough results
   859  	have (i64)
   860  	want (i32, i32)`,
   861  		},
   862  		{
   863  			name: `func.wast - type-return-first-num-vs-nums`,
   864  			// This should err because the return block doesn't return enough values.
   865  			//	(module (func $type-return-first-num-vs-nums (result i32 i32)
   866  			//	  (return (i32.const 1)) (return (i32.const 1) (i32.const 2))
   867  			//	))
   868  			module: &Module{
   869  				TypeSection:     []*FunctionType{v_i32i32},
   870  				FunctionSection: []Index{0},
   871  				CodeSection: []*Code{{Body: []byte{
   872  					OpcodeI64Const, 1, OpcodeReturn, // (return (i64.const 1))
   873  					OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeReturn, // (return (i32.const 1) (i32.const 2))
   874  					OpcodeEnd, // func
   875  				}}},
   876  			},
   877  			expectedErr: `not enough results
   878  	have (i64)
   879  	want (i32, i32)`,
   880  		},
   881  		{
   882  			name: `func.wast - type-break-last-num-vs-nums`,
   883  			module: &Module{
   884  				TypeSection:     []*FunctionType{v_i32i32},
   885  				FunctionSection: []Index{0},
   886  				CodeSection: []*Code{{Body: []byte{
   887  					OpcodeI32Const, 0, OpcodeBr, 0, // (br 0 (i32.const 0))
   888  					OpcodeEnd, // func
   889  				}}},
   890  			},
   891  			expectedErr: `not enough results in br block
   892  	have (i32)
   893  	want (i32, i32)`,
   894  		},
   895  		{
   896  			name: `func.wast - type-break-void-vs-nums`,
   897  			// This should err because (br 0) returns no values, but its enclosing function requires two:
   898  			//	(module (func $type-break-void-vs-nums (result i32 i32)
   899  			//	  (br 0) (i32.const 1) (i32.const 2)
   900  			//	))
   901  			module: &Module{
   902  				TypeSection:     []*FunctionType{v_i32i32},
   903  				FunctionSection: []Index{0},
   904  				CodeSection: []*Code{{Body: []byte{
   905  					OpcodeBr, 0, // (br 0)
   906  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2)
   907  					OpcodeEnd, // func
   908  				}}},
   909  			},
   910  			expectedErr: `not enough results in br block
   911  	have ()
   912  	want (i32, i32)`,
   913  		},
   914  		{
   915  			name: `func.wast - type-break-num-vs-nums`,
   916  			// This should err because (br 0) returns one value, but its enclosing function requires two:
   917  			//	(module (func $type-break-num-vs-nums (result i32 i32)
   918  			//	  (br 0 (i32.const 1)) (i32.const 1) (i32.const 2)
   919  			//	))
   920  			module: &Module{
   921  				TypeSection:     []*FunctionType{v_i32i32},
   922  				FunctionSection: []Index{0},
   923  				CodeSection: []*Code{{Body: []byte{
   924  					OpcodeI32Const, 1, OpcodeBr, 0, // (br 0 (i32.const 1))
   925  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2)
   926  					OpcodeEnd, // func
   927  				}}},
   928  			},
   929  			expectedErr: `not enough results in br block
   930  	have (i32)
   931  	want (i32, i32)`,
   932  		},
   933  		{
   934  			name: `func.wast - type-break-nested-empty-vs-nums`,
   935  			// This should err because (br 1) doesn't return values, but its enclosing function does:
   936  			//	(module (func $type-break-nested-empty-vs-nums (result i32 i32)
   937  			//	  (block (br 1)) (br 0 (i32.const 1) (i32.const 2))
   938  			//	))
   939  			module: &Module{
   940  				TypeSection:     []*FunctionType{v_i32i32},
   941  				FunctionSection: []Index{0},
   942  				CodeSection: []*Code{{Body: []byte{
   943  					OpcodeBlock, 0x40, OpcodeBr, 0x01, OpcodeEnd, // (block (br 1))
   944  					OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2))
   945  					OpcodeEnd, // func
   946  				}}},
   947  			},
   948  			expectedErr: `not enough results in br block
   949  	have ()
   950  	want (i32, i32)`,
   951  		},
   952  		{
   953  			name: `func.wast - type-break-nested-void-vs-nums`,
   954  			// This should err because nop returns the empty type, but the enclosing function returns i32i32:
   955  			//	(module (func $type-break-nested-void-vs-nums (result i32 i32)
   956  			//	  (block (br 1 (nop))) (br 0 (i32.const 1) (i32.const 2))
   957  			//	))
   958  			module: &Module{
   959  				TypeSection:     []*FunctionType{v_i32i32},
   960  				FunctionSection: []Index{0},
   961  				CodeSection: []*Code{{Body: []byte{
   962  					OpcodeBlock, 0x40, OpcodeNop, OpcodeBr, 0x01, OpcodeEnd, // (block (br 1 (nop)))
   963  					OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2))
   964  					OpcodeEnd, // func
   965  				}}},
   966  			},
   967  			expectedErr: `not enough results in br block
   968  	have ()
   969  	want (i32, i32)`,
   970  		},
   971  		{
   972  			name: `func.wast - type-break-nested-num-vs-nums`,
   973  			// This should err because the block signature is v_i32, but the enclosing function is v_i32i32:
   974  			//	(module (func $type-break-nested-num-vs-nums (result i32 i32)
   975  			//	  (block (result i32) (br 1 (i32.const 1))) (br 0 (i32.const 1) (i32.const 2))
   976  			//	))
   977  			module: &Module{
   978  				TypeSection:     []*FunctionType{v_i32i32},
   979  				FunctionSection: []Index{0},
   980  				CodeSection: []*Code{{Body: []byte{
   981  					OpcodeBlock, 0x7f, OpcodeI32Const, 1, OpcodeBr, 1, OpcodeEnd, // (block (result i32) (br 1 (i32.const 1)))
   982  					OpcodeI32Const, 1, OpcodeI32Const, 2, OpcodeBr, 0, // (br 0 (i32.const 1) (i32.const 2))
   983  					OpcodeEnd, // func
   984  				}}},
   985  			},
   986  			expectedErr: `not enough results in br block
   987  	have (i32)
   988  	want (i32, i32)`,
   989  		},
   990  
   991  		// test/core/if.wast
   992  		{
   993  			name: `if.wast - wrong signature for if type use`,
   994  			// This should err because (br 0) returns no values, but its enclosing function requires two:
   995  			//  (module
   996  			//    (type $sig (func))
   997  			//    (func (i32.const 1) (if (type $sig) (i32.const 0) (then)))
   998  			//  )
   999  			module: &Module{
  1000  				TypeSection:     []*FunctionType{v_v},
  1001  				FunctionSection: []Index{0},
  1002  				CodeSection: []*Code{{Body: []byte{
  1003  					OpcodeI32Const, 1, // (i32.const 1)
  1004  					OpcodeI32Const, 0, OpcodeIf, 0, // (if (type $sig) (i32.const 0)
  1005  					OpcodeEnd, // if
  1006  					OpcodeEnd, // func
  1007  				}}},
  1008  			},
  1009  			expectedErr: `too many results
  1010  	have (i32)
  1011  	want ()`,
  1012  		},
  1013  		{
  1014  			name: `if.wast - type-then-value-nums-vs-void`,
  1015  			// This should err because (if) without a type use returns no values, but its (then) returns two:
  1016  			//	(module (func $type-then-value-nums-vs-void
  1017  			//	  (if (i32.const 1) (then (i32.const 1) (i32.const 2)))
  1018  			//	))
  1019  			module: &Module{
  1020  				TypeSection:     []*FunctionType{v_v},
  1021  				FunctionSection: []Index{0},
  1022  				CodeSection: []*Code{{Body: []byte{
  1023  					OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1)
  1024  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (then (i32.const 1) (i32.const 2))
  1025  					OpcodeEnd, // if
  1026  					OpcodeEnd, // func
  1027  				}}},
  1028  			},
  1029  			expectedErr: `too many results in if block
  1030  	have (i32, i32)
  1031  	want ()`,
  1032  		},
  1033  		{
  1034  			name: `if.wast - type-then-value-nums-vs-void-else`,
  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-else
  1037  			//	  (if (i32.const 1) (then (i32.const 1) (i32.const 2)) (else))
  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  					OpcodeElse, // (else)
  1046  					OpcodeEnd,  // if
  1047  					OpcodeEnd,  // func
  1048  				}}},
  1049  			},
  1050  			expectedErr: `too many results in if block
  1051  	have (i32, i32)
  1052  	want ()`,
  1053  		},
  1054  		{
  1055  			name: `if.wast - type-else-value-nums-vs-void`,
  1056  			// This should err because (if) without a type use returns no values, but its (else) returns two:
  1057  			//	(module (func $type-else-value-nums-vs-void
  1058  			//	  (if (i32.const 1) (then) (else (i32.const 1) (i32.const 2)))
  1059  			//	))
  1060  			module: &Module{
  1061  				TypeSection:     []*FunctionType{v_v},
  1062  				FunctionSection: []Index{0},
  1063  				CodeSection: []*Code{{Body: []byte{
  1064  					OpcodeI32Const, 1, OpcodeIf, 0x40, // (if (i32.const 1) (then)
  1065  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 2, // (else (i32.const 1) (i32.const 2))
  1066  					OpcodeEnd, // if
  1067  					OpcodeEnd, // func
  1068  				}}},
  1069  			},
  1070  			expectedErr: `too many results in else block
  1071  	have (i32, i32)
  1072  	want ()`,
  1073  		},
  1074  		{
  1075  			name: `if.wast - type-both-value-nums-vs-void`,
  1076  			// This should err because (if) without a type use returns no values, each branch returns two:
  1077  			//	(module (func $type-both-value-nums-vs-void
  1078  			//	  (if (i32.const 1) (then (i32.const 1) (i32.const 2)) (else (i32.const 2) (i32.const 1)))
  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)
  1085  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (then (i32.const 1) (i32.const 2))
  1086  					OpcodeElse, OpcodeI32Const, 2, OpcodeI32Const, 1, // (else (i32.const 2) (i32.const 1))
  1087  					OpcodeEnd, // if
  1088  					OpcodeEnd, // func
  1089  				}}},
  1090  			},
  1091  			expectedErr: `too many results in if block
  1092  	have (i32, i32)
  1093  	want ()`,
  1094  		},
  1095  		{
  1096  			name: `if.wast - type-then-value-empty-vs-nums`,
  1097  			// This should err because the if branch is empty, but its type use requires two i32s:
  1098  			//	(module (func $type-then-value-empty-vs-nums (result i32 i32)
  1099  			//	  (if (result i32 i32) (i32.const 1) (then) (else (i32.const 0) (i32.const 2)))
  1100  			//	))
  1101  			module: &Module{
  1102  				TypeSection:     []*FunctionType{v_v, v_i32i32},
  1103  				FunctionSection: []Index{0},
  1104  				CodeSection: []*Code{{Body: []byte{
  1105  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1) (then)
  1106  					OpcodeElse, OpcodeI32Const, 0, OpcodeI32Const, 2, // (else (i32.const 0) (i32.const 2)))
  1107  					OpcodeEnd, // if
  1108  					OpcodeEnd, // func
  1109  				}}},
  1110  			},
  1111  			expectedErr: `not enough results in if block
  1112  	have ()
  1113  	want (i32, i32)`,
  1114  		},
  1115  		{
  1116  			name: `if.wast - type-else-value-empty-vs-nums`,
  1117  			// This should err because the else branch is empty, but its type use requires two i32s:
  1118  			//	(module (func $type-else-value-empty-vs-nums (result i32 i32)
  1119  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 0) (i32.const 1)) (else))
  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)
  1126  					OpcodeI32Const, 0, OpcodeI32Const, 2, // (then (i32.const 0) (i32.const 1))
  1127  					OpcodeElse, // (else)
  1128  					OpcodeEnd,  // if
  1129  					OpcodeEnd,  // func
  1130  				}}},
  1131  			},
  1132  			expectedErr: `not enough results in else block
  1133  	have ()
  1134  	want (i32, i32)`,
  1135  		},
  1136  		{
  1137  			name: `if.wast - type-both-value-empty-vs-nums`,
  1138  			// This should err because the both branches are empty, but the if type use requires two i32s:
  1139  			//	(module (func $type-both-value-empty-vs-nums (result i32 i32)
  1140  			//	  (if (result i32 i32) (i32.const 1) (then) (else))
  1141  			//	))
  1142  			module: &Module{
  1143  				TypeSection:     []*FunctionType{v_v, v_i32i32},
  1144  				FunctionSection: []Index{0},
  1145  				CodeSection: []*Code{{Body: []byte{
  1146  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (result i32 i32) (i32.const 1) (then)
  1147  					OpcodeElse, // (else)
  1148  					OpcodeEnd,  // if
  1149  					OpcodeEnd,  // func
  1150  				}}},
  1151  			},
  1152  			expectedErr: `not enough results in if block
  1153  	have ()
  1154  	want (i32, i32)`,
  1155  		},
  1156  		{
  1157  			name: `if.wast - type-no-else-vs-nums`,
  1158  			// This should err because the else branch is missing, but its type use requires two i32s:
  1159  			//	(module (func $type-no-else-vs-nums (result i32 i32)
  1160  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)))
  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)
  1167  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1168  					OpcodeEnd, // if
  1169  					OpcodeEnd, // func
  1170  				}}},
  1171  			},
  1172  			expectedErr: `not enough results in else block
  1173  	have ()
  1174  	want (i32, i32)`,
  1175  		},
  1176  		{
  1177  			name: `if.wast - type-then-value-void-vs-nums`,
  1178  			// This should err because the then branch evaluates to empty, but its type use requires two i32s:
  1179  			//	(module (func $type-then-value-void-vs-nums (result i32 i32)
  1180  			//	  (if (result i32 i32) (i32.const 1) (then (nop)) (else (i32.const 0) (i32.const 0)))
  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  					OpcodeNop,                                        // (then (nop))
  1188  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1189  					OpcodeEnd, // if
  1190  					OpcodeEnd, // func
  1191  				}}},
  1192  			},
  1193  			expectedErr: `not enough results in if block
  1194  	have ()
  1195  	want (i32, i32)`,
  1196  		},
  1197  		{
  1198  			name: `if.wast - type-then-value-void-vs-nums`,
  1199  			// This should err because the else branch evaluates to empty, but its type use requires two i32s:
  1200  			//	(module (func $type-else-value-void-vs-nums (result i32 i32)
  1201  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 0) (i32.const 0)) (else (nop)))
  1202  			//	))
  1203  			module: &Module{
  1204  				TypeSection:     []*FunctionType{v_i32i32},
  1205  				FunctionSection: []Index{0},
  1206  				CodeSection: []*Code{{Body: []byte{
  1207  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1208  					OpcodeI32Const, 0, OpcodeI32Const, 0, // (then (i32.const 0) (i32.const 0))
  1209  					OpcodeElse, OpcodeNop, // (else (nop))
  1210  					OpcodeEnd, // if
  1211  					OpcodeEnd, // func
  1212  				}}},
  1213  			},
  1214  			expectedErr: `not enough results in else block
  1215  	have ()
  1216  	want (i32, i32)`,
  1217  		},
  1218  		{
  1219  			name: `if.wast - type-both-value-void-vs-nums`,
  1220  			// This should err because the if branch evaluates to empty, but its type use requires two i32s:
  1221  			//	(module (func $type-both-value-void-vs-nums (result i32 i32)
  1222  			//	  (if (result i32 i32) (i32.const 1) (then (nop)) (else (nop)))
  1223  			//	))
  1224  			module: &Module{
  1225  				TypeSection:     []*FunctionType{v_i32i32},
  1226  				FunctionSection: []Index{0},
  1227  				CodeSection: []*Code{{Body: []byte{
  1228  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1229  					OpcodeNop,             // (then (nop))
  1230  					OpcodeElse, OpcodeNop, // (else (nop))
  1231  					OpcodeEnd, // if
  1232  					OpcodeEnd, // func
  1233  				}}},
  1234  			},
  1235  			expectedErr: `not enough results in if block
  1236  	have ()
  1237  	want (i32, i32)`,
  1238  		},
  1239  		{
  1240  			name: `if.wast - type-then-value-num-vs-nums`,
  1241  			// This should err because the if branch returns one value, but its type use requires two:
  1242  			//	(module (func $type-then-value-num-vs-nums (result i32 i32)
  1243  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1)))
  1244  			//	))
  1245  			module: &Module{
  1246  				TypeSection:     []*FunctionType{v_i32i32},
  1247  				FunctionSection: []Index{0},
  1248  				CodeSection: []*Code{{Body: []byte{
  1249  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1250  					OpcodeI32Const, 1, // (then (i32.const 1))
  1251  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)))
  1252  					OpcodeEnd, // if
  1253  					OpcodeEnd, // func
  1254  				}}},
  1255  			},
  1256  			expectedErr: `not enough results in if block
  1257  	have (i32)
  1258  	want (i32, i32)`,
  1259  		},
  1260  		{
  1261  			name: `if.wast - type-else-value-num-vs-nums`,
  1262  			// This should err because the else branch returns one value, but its type use requires two:
  1263  			//	(module (func $type-else-value-num-vs-nums (result i32 i32)
  1264  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1)))
  1265  			//	))
  1266  			module: &Module{
  1267  				TypeSection:     []*FunctionType{v_i32i32},
  1268  				FunctionSection: []Index{0},
  1269  				CodeSection: []*Code{{Body: []byte{
  1270  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1271  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1272  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)))
  1273  					OpcodeEnd, // if
  1274  					OpcodeEnd, // func
  1275  				}}},
  1276  			},
  1277  			expectedErr: `not enough results in else block
  1278  	have (i32)
  1279  	want (i32, i32)`,
  1280  		},
  1281  		{
  1282  			name: `if.wast - type-both-value-num-vs-nums`,
  1283  			// This should err because the if branch returns one value, but its type use requires two:
  1284  			//	(module (func $type-both-value-num-vs-nums (result i32 i32)
  1285  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1)))
  1286  			//	))
  1287  			module: &Module{
  1288  				TypeSection:     []*FunctionType{v_i32i32},
  1289  				FunctionSection: []Index{0},
  1290  				CodeSection: []*Code{{Body: []byte{
  1291  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1292  					OpcodeI32Const, 1, // (then (i32.const 1))
  1293  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1)))
  1294  					OpcodeEnd, // if
  1295  					OpcodeEnd, // func
  1296  				}}},
  1297  			},
  1298  			expectedErr: `not enough results in if block
  1299  	have (i32)
  1300  	want (i32, i32)`,
  1301  		},
  1302  		{
  1303  			name: `if.wast - type-then-value-partial-vs-nums`,
  1304  			// This should err because the if branch returns one value, but its type use requires two:
  1305  			//	(module (func $type-then-value-partial-vs-nums (result i32 i32)
  1306  			//	  (i32.const 0)
  1307  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1)))
  1308  			//	))
  1309  			module: &Module{
  1310  				TypeSection:     []*FunctionType{v_i32i32},
  1311  				FunctionSection: []Index{0},
  1312  				CodeSection: []*Code{{Body: []byte{
  1313  					OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if)
  1314  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1315  					OpcodeI32Const, 1, // (then (i32.const 1))
  1316  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1317  					OpcodeEnd, // if
  1318  					OpcodeEnd, // func
  1319  				}}},
  1320  			},
  1321  			expectedErr: `not enough results in if block
  1322  	have (i32)
  1323  	want (i32, i32)`,
  1324  		},
  1325  		{
  1326  			name: `if.wast - type-else-value-partial-vs-nums`,
  1327  			// This should err because the else branch returns one value, but its type use requires two:
  1328  			//	(module (func $type-else-value-partial-vs-nums (result i32 i32)
  1329  			//	  (i32.const 0)
  1330  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1)))
  1331  			//	))
  1332  			module: &Module{
  1333  				TypeSection:     []*FunctionType{v_i32i32},
  1334  				FunctionSection: []Index{0},
  1335  				CodeSection: []*Code{{Body: []byte{
  1336  					OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if)
  1337  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1338  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1339  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))
  1340  					OpcodeEnd, // if
  1341  					OpcodeEnd, // func
  1342  				}}},
  1343  			},
  1344  			expectedErr: `not enough results in else block
  1345  	have (i32)
  1346  	want (i32, i32)`,
  1347  		},
  1348  		{
  1349  			name: `if.wast - type-both-value-partial-vs-nums`,
  1350  			// This should err because the if branch returns one value, but its type use requires two:
  1351  			//  (module (func $type-both-value-partial-vs-nums (result i32 i32)
  1352  			//    (i32.const 0)
  1353  			//    (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1)))
  1354  			//  ))
  1355  			module: &Module{
  1356  				TypeSection:     []*FunctionType{v_i32i32},
  1357  				FunctionSection: []Index{0},
  1358  				CodeSection: []*Code{{Body: []byte{
  1359  					OpcodeI32Const, 0, // (i32.const 0) - NOTE: this is outside the (if)
  1360  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1361  					OpcodeI32Const, 1, // (then (i32.const 1))
  1362  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))
  1363  					OpcodeEnd, // if
  1364  					OpcodeEnd, // func
  1365  				}}},
  1366  			},
  1367  			expectedErr: `not enough results in if block
  1368  	have (i32)
  1369  	want (i32, i32)`,
  1370  		},
  1371  		{
  1372  			name: `if.wast - type-then-value-nums-vs-num`,
  1373  			// This should err because the if branch returns two values, but its type use requires one:
  1374  			//	(module (func $type-then-value-nums-vs-num (result i32)
  1375  			//	  (if (result i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1)))
  1376  			//	))
  1377  			module: &Module{
  1378  				TypeSection:     []*FunctionType{v_i32},
  1379  				FunctionSection: []Index{0},
  1380  				CodeSection: []*Code{{Body: []byte{
  1381  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1)
  1382  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1383  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))
  1384  					OpcodeEnd, // if
  1385  					OpcodeEnd, // func
  1386  				}}},
  1387  			},
  1388  			expectedErr: `too many results in if block
  1389  	have (i32, i32)
  1390  	want (i32)`,
  1391  		},
  1392  		{
  1393  			name: `if.wast - type-else-value-nums-vs-num`,
  1394  			// This should err because the else branch returns two values, but its type use requires one:
  1395  			//	(module (func $type-else-value-nums-vs-num (result i32)
  1396  			//	  (if (result i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1)))
  1397  			//	))
  1398  			module: &Module{
  1399  				TypeSection:     []*FunctionType{v_i32},
  1400  				FunctionSection: []Index{0},
  1401  				CodeSection: []*Code{{Body: []byte{
  1402  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1)
  1403  					OpcodeI32Const, 1, // (then (i32.const 1))
  1404  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1405  					OpcodeEnd, // if
  1406  					OpcodeEnd, // func
  1407  				}}},
  1408  			},
  1409  			expectedErr: `too many results in else block
  1410  	have (i32, i32)
  1411  	want (i32)`,
  1412  		},
  1413  		{
  1414  			name: `if.wast - type-both-value-nums-vs-num`,
  1415  			// This should err because the if branch returns two values, but its type use requires one:
  1416  			//	(module (func $type-both-value-nums-vs-num (result i32)
  1417  			//	  (if (result i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1) (i32.const 1)))
  1418  			//	))
  1419  			module: &Module{
  1420  				TypeSection:     []*FunctionType{v_i32},
  1421  				FunctionSection: []Index{0},
  1422  				CodeSection: []*Code{{Body: []byte{
  1423  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32) (i32.const 1)
  1424  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1425  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1426  					OpcodeEnd, // if
  1427  					OpcodeEnd, // func
  1428  				}}},
  1429  			},
  1430  			expectedErr: `too many results in if block
  1431  	have (i32, i32)
  1432  	want (i32)`,
  1433  		},
  1434  		{
  1435  			name: `if.wast - type-both-different-value-nums-vs-nums`,
  1436  			// This should err because the if branch returns three values, but its type use requires two:
  1437  			//	(module (func $type-both-different-value-nums-vs-nums (result i32 i32)
  1438  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1) (i32.const 1)) (else (i32.const 1)))
  1439  			//	))
  1440  			module: &Module{
  1441  				TypeSection:     []*FunctionType{v_i32i32},
  1442  				FunctionSection: []Index{0},
  1443  				CodeSection: []*Code{{Body: []byte{
  1444  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1445  					OpcodeI32Const, 1, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1) (i32.const 1))
  1446  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))
  1447  					OpcodeEnd, // if
  1448  					OpcodeEnd, // func
  1449  				}}},
  1450  			},
  1451  			expectedErr: `too many results in if block
  1452  	have (i32, i32, i32)
  1453  	want (i32, i32)`,
  1454  		},
  1455  		{
  1456  			name: `if.wast - type-then-break-last-void-vs-nums`,
  1457  			// This should err because the branch in the if returns no values, but its type use requires two:
  1458  			//	(module (func $type-then-break-last-void-vs-nums (result i32 i32)
  1459  			//	  (if (result i32 i32) (i32.const 1) (then (br 0)) (else (i32.const 1) (i32.const 1)))
  1460  			//	))
  1461  			module: &Module{
  1462  				TypeSection:     []*FunctionType{v_i32i32},
  1463  				FunctionSection: []Index{0},
  1464  				CodeSection: []*Code{{Body: []byte{
  1465  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1466  					OpcodeBr, 0, // (then (br 0))
  1467  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1)))
  1468  					OpcodeEnd, // if
  1469  					OpcodeEnd, // func
  1470  				}}},
  1471  			},
  1472  			expectedErr: `not enough results in br block
  1473  	have ()
  1474  	want (i32, i32)`,
  1475  		},
  1476  		{
  1477  			name: `if.wast - type-else-break-last-void-vs-nums`,
  1478  			// This should err because the branch in the else returns no values, but its type use requires two:
  1479  			//	(module (func $type-else-break-last-void-vs-nums (result i32 i32)
  1480  			//	  (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (br 0)))
  1481  			//	))
  1482  			module: &Module{
  1483  				TypeSection:     []*FunctionType{v_i32i32},
  1484  				FunctionSection: []Index{0},
  1485  				CodeSection: []*Code{{Body: []byte{
  1486  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1487  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1488  					OpcodeElse, OpcodeBr, 0, // (else (br 0))
  1489  					OpcodeEnd, // if
  1490  					OpcodeEnd, // func
  1491  				}}},
  1492  			},
  1493  			expectedErr: `not enough results in br block
  1494  	have ()
  1495  	want (i32, i32)`,
  1496  		},
  1497  		{
  1498  			name: `if.wast - type-then-break-empty-vs-nums`,
  1499  			// This should err because the branch in the if returns no values, but its type use requires two:
  1500  			//	(module (func $type-then-break-empty-vs-nums (result i32 i32)
  1501  			//	  (if (result i32 i32) (i32.const 1)
  1502  			//	    (then (br 0) (i32.const 1) (i32.const 1))
  1503  			//	    (else (i32.const 1) (i32.const 1))
  1504  			//	  )
  1505  			//	))
  1506  			module: &Module{
  1507  				TypeSection:     []*FunctionType{v_i32i32},
  1508  				FunctionSection: []Index{0},
  1509  				CodeSection: []*Code{{Body: []byte{
  1510  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1511  					OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0) (i32.const 1) (i32.const 1))
  1512  					// ^^ NOTE: consts are outside the br block
  1513  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1514  					OpcodeEnd, // if
  1515  					OpcodeEnd, // func
  1516  				}}},
  1517  			},
  1518  			expectedErr: `not enough results in br block
  1519  	have ()
  1520  	want (i32, i32)`,
  1521  		},
  1522  		{
  1523  			name: `if.wast - type-else-break-empty-vs-nums`,
  1524  			// This should err because the branch in the else returns no values, but its type use requires two:
  1525  			//	(module (func $type-else-break-empty-vs-nums (result i32 i32)
  1526  			//	  (if (result i32 i32) (i32.const 1)
  1527  			//	    (then (i32.const 1) (i32.const 1))
  1528  			//	    (else (br 0) (i32.const 1) (i32.const 1))
  1529  			//	  )
  1530  			//	))
  1531  			module: &Module{
  1532  				TypeSection:     []*FunctionType{v_i32i32},
  1533  				FunctionSection: []Index{0},
  1534  				CodeSection: []*Code{{Body: []byte{
  1535  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1536  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1537  					OpcodeElse, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0) (i32.const 1) (i32.const 1))
  1538  					// ^^ NOTE: consts are outside the br block
  1539  					OpcodeEnd, // if
  1540  					OpcodeEnd, // func
  1541  				}}},
  1542  			},
  1543  			expectedErr: `not enough results in br block
  1544  	have ()
  1545  	want (i32, i32)`,
  1546  		},
  1547  		{
  1548  			name: `if.wast - type-then-break-void-vs-nums`,
  1549  			// This should err because the branch in the if evaluates to no values, but its type use requires two:
  1550  			//	(module (func $type-then-break-void-vs-nums (result i32 i32)
  1551  			//	  (if (result i32 i32) (i32.const 1)
  1552  			//	    (then (br 0 (nop)) (i32.const 1) (i32.const 1))
  1553  			//	    (else (i32.const 1) (i32.const 1))
  1554  			//	  )
  1555  			//	))
  1556  			module: &Module{
  1557  				TypeSection:     []*FunctionType{v_i32i32},
  1558  				FunctionSection: []Index{0},
  1559  				CodeSection: []*Code{{Body: []byte{
  1560  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1561  					OpcodeNop, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0 (nop)) (i32.const 1) (i32.const 1))
  1562  					// ^^ NOTE: consts are outside the br block
  1563  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1564  					OpcodeEnd, // if
  1565  					OpcodeEnd, // func
  1566  				}}},
  1567  			},
  1568  			expectedErr: `not enough results in br block
  1569  	have ()
  1570  	want (i32, i32)`,
  1571  		},
  1572  		{
  1573  			name: `if.wast - type-else-break-void-vs-nums`,
  1574  			// This should err because the branch in the else evaluates to no values, but its type use requires two:
  1575  			//	(module (func $type-else-break-void-vs-nums (result i32 i32)
  1576  			//	  (if (result i32 i32) (i32.const 1)
  1577  			//	    (then (i32.const 1) (i32.const 1))
  1578  			//	    (else (br 0 (nop)) (i32.const 1) (i32.const 1))
  1579  			//	  )
  1580  			//	))
  1581  			module: &Module{
  1582  				TypeSection:     []*FunctionType{v_i32i32},
  1583  				FunctionSection: []Index{0},
  1584  				CodeSection: []*Code{{Body: []byte{
  1585  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1586  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1587  					OpcodeElse, OpcodeNop, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0 (nop)) (i32.const 1) (i32.const 1))
  1588  					// ^^ NOTE: consts are outside the br block
  1589  					OpcodeEnd, // if
  1590  					OpcodeEnd, // func
  1591  				}}},
  1592  			},
  1593  			expectedErr: `not enough results in br block
  1594  	have ()
  1595  	want (i32, i32)`,
  1596  		},
  1597  		{
  1598  			name: `if.wast - type-then-break-num-vs-nums`,
  1599  			// This should err because the branch in the if evaluates to one value, but its type use requires two:
  1600  			//	(module (func $type-then-break-num-vs-nums (result i32 i32)
  1601  			//	  (if (result i32 i32) (i32.const 1)
  1602  			//	    (then (br 0 (i64.const 1)) (i32.const 1) (i32.const 1))
  1603  			//	    (else (i32.const 1) (i32.const 1))
  1604  			//	  )
  1605  			//	))
  1606  			module: &Module{
  1607  				TypeSection:     []*FunctionType{v_i32i32},
  1608  				FunctionSection: []Index{0},
  1609  				CodeSection: []*Code{{Body: []byte{
  1610  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1611  					OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (br 0 (i64.const 1)) (i32.const 1) (i32.const 1))
  1612  					// ^^ NOTE: only one (incorrect) const is inside the br block
  1613  					OpcodeElse, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (i32.const 1) (i32.const 1))
  1614  					OpcodeEnd, // if
  1615  					OpcodeEnd, // func
  1616  				}}},
  1617  			},
  1618  			expectedErr: `not enough results in br block
  1619  	have (i64)
  1620  	want (i32, i32)`,
  1621  		},
  1622  		{
  1623  			name: `if.wast - type-else-break-num-vs-nums`,
  1624  			// This should err because the branch in the else evaluates to one value, but its type use requires two:
  1625  			//	(module (func $type-else-break-num-vs-nums (result i32 i32)
  1626  			//	  (if (result i32 i32) (i32.const 1)
  1627  			//	    (then (i32.const 1) (i32.const 1))
  1628  			//	    (else (br 0 (i64.const 1)) (i32.const 1) (i32.const 1))
  1629  			//	  )
  1630  			//	))
  1631  			module: &Module{
  1632  				TypeSection:     []*FunctionType{v_i32i32},
  1633  				FunctionSection: []Index{0},
  1634  				CodeSection: []*Code{{Body: []byte{
  1635  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1636  					OpcodeI32Const, 1, OpcodeI32Const, 1, // (then (i32.const 1) (i32.const 1))
  1637  					OpcodeElse, OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, OpcodeI32Const, 1, // (else (br 0 (i64.const 1)) (i32.const 1) (i32.const 1))
  1638  					// ^^ NOTE: only one (incorrect) const is inside the br block
  1639  					OpcodeEnd, // if
  1640  					OpcodeEnd, // func
  1641  				}}},
  1642  			},
  1643  			expectedErr: `not enough results in br block
  1644  	have (i64)
  1645  	want (i32, i32)`,
  1646  		},
  1647  		{
  1648  			name: `if.wast - type-then-break-partial-vs-nums`,
  1649  			// This should err because the branch in the if evaluates to one value, but its type use requires two:
  1650  			//	(module (func $type-then-break-partial-vs-nums (result i32 i32)
  1651  			//	  (i32.const 1)
  1652  			//	  (if (result i32 i32) (i32.const 1)
  1653  			//	    (then (br 0 (i64.const 1)) (i32.const 1))
  1654  			//	    (else (i32.const 1))
  1655  			//	  )
  1656  			//	))
  1657  			module: &Module{
  1658  				TypeSection:     []*FunctionType{v_i32i32},
  1659  				FunctionSection: []Index{0},
  1660  				CodeSection: []*Code{{Body: []byte{
  1661  					OpcodeI32Const, 1, // (i32.const 1)
  1662  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1663  					OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, // (then (br 0 (i64.const 1)) (i32.const 1))
  1664  					// ^^ NOTE: only one (incorrect) const is inside the br block
  1665  					OpcodeElse, OpcodeI32Const, 1, // (else (i32.const 1))
  1666  					OpcodeEnd, // if
  1667  					OpcodeEnd, // func
  1668  				}}},
  1669  			},
  1670  			expectedErr: `not enough results in br block
  1671  	have (i64)
  1672  	want (i32, i32)`,
  1673  		},
  1674  		{
  1675  			name: `if.wast - type-else-break-partial-vs-nums`,
  1676  			// This should err because the branch in the if evaluates to one value, but its type use requires two:
  1677  			//	(module (func $type-else-break-partial-vs-nums (result i32 i32)
  1678  			//	  (i32.const 1)
  1679  			//	  (if (result i32 i32) (i32.const 1)
  1680  			//	    (then (i32.const 1))
  1681  			//	    (else (br 0 (i64.const 1)) (i32.const 1))
  1682  			//	  )
  1683  			//	))
  1684  			module: &Module{
  1685  				TypeSection:     []*FunctionType{v_i32i32},
  1686  				FunctionSection: []Index{0},
  1687  				CodeSection: []*Code{{Body: []byte{
  1688  					OpcodeI32Const, 1, // (i32.const 1)
  1689  					OpcodeI32Const, 1, OpcodeIf, 0x00, // (if (result i32 i32) (i32.const 1)
  1690  					OpcodeI32Const, 1, // (then (i32.const 1))
  1691  					OpcodeElse, OpcodeI64Const, 1, OpcodeBr, 0, OpcodeI32Const, 1, // (else (br 0 (i64.const 1)) (i32.const 1))
  1692  					// ^^ NOTE: only one (incorrect) const is inside the br block
  1693  					OpcodeEnd, // if
  1694  					OpcodeEnd, // func
  1695  				}}},
  1696  			},
  1697  			expectedErr: `not enough results in if block
  1698  	have (i32)
  1699  	want (i32, i32)`,
  1700  		},
  1701  		{
  1702  			name: `if.wast - type-param-void-vs-num`,
  1703  			// This should err because the stack has no values, but the if type use requires two:
  1704  			//	(module (func $type-param-void-vs-num
  1705  			//	  (if (param i32) (i32.const 1) (then (drop)))
  1706  			//	))
  1707  			module: &Module{
  1708  				TypeSection:     []*FunctionType{v_v, i32_v},
  1709  				FunctionSection: []Index{0},
  1710  				CodeSection: []*Code{{Body: []byte{
  1711  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1)
  1712  					OpcodeDrop, // (then (drop)))
  1713  					OpcodeEnd,  // if
  1714  					OpcodeEnd,  // func
  1715  				}}},
  1716  			},
  1717  			expectedErr: `not enough params for if block
  1718  	have ()
  1719  	want (i32)`,
  1720  		},
  1721  		{
  1722  			name: `if.wast - type-param-void-vs-nums`,
  1723  			// This should err because the stack has no values, but the if type use requires two:
  1724  			//	(module (func $type-param-void-vs-nums
  1725  			//	  (if (param i32 f64) (i32.const 1) (then (drop) (drop)))
  1726  			//	))
  1727  			module: &Module{
  1728  				TypeSection:     []*FunctionType{v_v, i32f64_v},
  1729  				FunctionSection: []Index{0},
  1730  				CodeSection: []*Code{{Body: []byte{
  1731  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32 f64) (i32.const 1)
  1732  					OpcodeI32Const, 1, OpcodeDrop, // (then (drop) (drop))
  1733  					OpcodeEnd, // if
  1734  					OpcodeEnd, // func
  1735  				}}},
  1736  			},
  1737  			expectedErr: `not enough params for if block
  1738  	have ()
  1739  	want (i32, f64)`,
  1740  		},
  1741  		{
  1742  			name: `if.wast - type-param-num-vs-num`,
  1743  			// This should err because the stack has a different value that what the if type use requires:
  1744  			//	(module (func $type-param-num-vs-num
  1745  			//	  (f32.const 0) (if (param i32) (i32.const 1) (then (drop)))
  1746  			//	))
  1747  			module: &Module{
  1748  				TypeSection:     []*FunctionType{v_v, i32_v},
  1749  				FunctionSection: []Index{0},
  1750  				CodeSection: []*Code{{Body: []byte{
  1751  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  1752  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1)
  1753  					OpcodeDrop, // (then (drop))
  1754  					OpcodeEnd,  // if
  1755  					OpcodeEnd,  // func
  1756  				}}},
  1757  			},
  1758  			expectedErr: "cannot use f32 in if block as param[0] type i32",
  1759  		},
  1760  		{
  1761  			name: `if.wast - type-param-num-vs-nums`,
  1762  			// This should err because the stack has one value, but the if type use requires two:
  1763  			//	(module (func $type-param-num-vs-nums
  1764  			//	  (f32.const 0) (if (param f32 i32) (i32.const 1) (then (drop) (drop)))
  1765  			//	))
  1766  			module: &Module{
  1767  				TypeSection:     []*FunctionType{v_v, f32i32_v},
  1768  				FunctionSection: []Index{0},
  1769  				CodeSection: []*Code{{Body: []byte{
  1770  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  1771  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param f32 i32) (i32.const 1)
  1772  					OpcodeDrop, OpcodeDrop, // (then (drop) (drop))
  1773  					OpcodeEnd, // if
  1774  					OpcodeEnd, // func
  1775  				}}},
  1776  			},
  1777  			expectedErr: `not enough params for if block
  1778  	have (f32)
  1779  	want (f32, i32)`,
  1780  		},
  1781  		{
  1782  			name: `if.wast - type-param-nested-void-vs-num`,
  1783  			// This should err because the stack has no values, but the if type use requires one:
  1784  			//	(module (func $type-param-nested-void-vs-num
  1785  			//	  (block (if (param i32) (i32.const 1) (then (drop))))
  1786  			//	))
  1787  			module: &Module{
  1788  				TypeSection:     []*FunctionType{v_v, i32_v},
  1789  				FunctionSection: []Index{0},
  1790  				CodeSection: []*Code{{Body: []byte{
  1791  					OpcodeBlock, 0x40, // (block
  1792  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1)
  1793  					OpcodeDrop, // (then (drop))
  1794  					OpcodeEnd,  // block
  1795  					OpcodeEnd,  // if
  1796  					OpcodeEnd,  // func
  1797  				}}},
  1798  			},
  1799  			expectedErr: `not enough params for if block
  1800  	have ()
  1801  	want (i32)`,
  1802  		},
  1803  		{
  1804  			name: `if.wast - type-param-void-vs-nums`,
  1805  			// This should err because the stack has no values, but the if type use requires two:
  1806  			//	(module (func $type-param-void-vs-nums
  1807  			//	  (block (if (param i32 f64) (i32.const 1) (then (drop) (drop))))
  1808  			//	))
  1809  			module: &Module{
  1810  				TypeSection:     []*FunctionType{v_v, i32f64_v},
  1811  				FunctionSection: []Index{0},
  1812  				CodeSection: []*Code{{Body: []byte{
  1813  					OpcodeBlock, 0x40, // (block
  1814  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32 f64) (i32.const 1)
  1815  					OpcodeDrop, // (then (drop) (drop))
  1816  					OpcodeEnd,  // block
  1817  					OpcodeEnd,  // if
  1818  					OpcodeEnd,  // func
  1819  				}}},
  1820  			},
  1821  			expectedErr: `not enough params for if block
  1822  	have ()
  1823  	want (i32, f64)`,
  1824  		},
  1825  		{
  1826  			name: `if.wast - type-param-num-vs-num`,
  1827  			// This should err because the stack has a different values than required by the if type use:
  1828  			//	(module (func $type-param-num-vs-num
  1829  			//	  (block (f32.const 0) (if (param i32) (i32.const 1) (then (drop))))
  1830  			//	))
  1831  			module: &Module{
  1832  				TypeSection:     []*FunctionType{v_v, i32_v},
  1833  				FunctionSection: []Index{0},
  1834  				CodeSection: []*Code{{Body: []byte{
  1835  					OpcodeBlock, 0x40, // (block
  1836  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  1837  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param i32) (i32.const 1)
  1838  					OpcodeDrop, // (then (drop))
  1839  					OpcodeEnd,  // block
  1840  					OpcodeEnd,  // if
  1841  					OpcodeEnd,  // func
  1842  				}}},
  1843  			},
  1844  			expectedErr: "cannot use f32 in if block as param[0] type i32",
  1845  		},
  1846  		{
  1847  			name: `if.wast - type-param-num-vs-nums`,
  1848  			// This should err because the stack has one value, but the if type use requires two:
  1849  			//	(module (func $type-param-num-vs-nums
  1850  			//	  (block (f32.const 0) (if (param f32 i32) (i32.const 1) (then (drop) (drop))))
  1851  			//	))
  1852  			module: &Module{
  1853  				TypeSection:     []*FunctionType{v_v, f32i32_v},
  1854  				FunctionSection: []Index{0},
  1855  				CodeSection: []*Code{{Body: []byte{
  1856  					OpcodeBlock, 0x40, // (block
  1857  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  1858  					OpcodeI32Const, 1, OpcodeIf, 0x01, // (if (param f32 i32) (i32.const 1)
  1859  					OpcodeDrop, // (then (drop) (drop))
  1860  					OpcodeEnd,  // block
  1861  					OpcodeEnd,  // if
  1862  					OpcodeEnd,  // func
  1863  				}}},
  1864  			},
  1865  			expectedErr: `not enough params for if block
  1866  	have (f32)
  1867  	want (f32, i32)`,
  1868  		},
  1869  
  1870  		// test/core/loop.wast
  1871  		{
  1872  			name: `loop.wast - wrong signature for loop type use`,
  1873  			// This should err because the loop type use returns no values, but its block returns one:
  1874  			//  (module
  1875  			//    (type $sig (func))
  1876  			//    (func (loop (type $sig) (i32.const 0)))
  1877  			//  )
  1878  			module: &Module{
  1879  				TypeSection:     []*FunctionType{v_v},
  1880  				FunctionSection: []Index{0},
  1881  				CodeSection: []*Code{{Body: []byte{
  1882  					OpcodeLoop, 0, OpcodeI32Const, 0, // (loop (type $sig) (i32.const 0))
  1883  					OpcodeEnd, // loop
  1884  					OpcodeEnd, // func
  1885  				}}},
  1886  			},
  1887  			expectedErr: `too many results in loop block
  1888  	have (i32)
  1889  	want ()`,
  1890  		},
  1891  		{
  1892  			name: `loop.wast - type-value-nums-vs-void`,
  1893  			// This should err because the empty block type requires no values, but the loop returns two:
  1894  			//  (module (func $type-value-nums-vs-void
  1895  			//    (loop (i32.const 1) (i32.const 2))
  1896  			//  ))
  1897  			module: &Module{
  1898  				TypeSection:     []*FunctionType{v_v},
  1899  				FunctionSection: []Index{0},
  1900  				CodeSection: []*Code{{Body: []byte{
  1901  					OpcodeLoop, 0x40, OpcodeI32Const, 1, OpcodeI32Const, 2, // (loop (i32.const 1) (i32.const 2))
  1902  					OpcodeEnd, // loop
  1903  					OpcodeEnd, // func
  1904  				}}},
  1905  			},
  1906  			expectedErr: `too many results in loop block
  1907  	have (i32, i32)
  1908  	want ()`,
  1909  		},
  1910  		{
  1911  			name: `loop.wast - type-value-empty-vs-nums`,
  1912  			// This should err because the loop type use returns two values, but the block returns none:
  1913  			//	(module (func $type-value-empty-vs-nums (result i32 i32)
  1914  			//	  (loop (result i32 i32))
  1915  			//	))
  1916  			module: &Module{
  1917  				TypeSection:     []*FunctionType{v_i32i32},
  1918  				FunctionSection: []Index{0},
  1919  				CodeSection: []*Code{{Body: []byte{
  1920  					OpcodeLoop, 0x0, // (loop (result i32 i32)) - matches existing func type
  1921  					OpcodeEnd, // loop
  1922  					OpcodeEnd, // func
  1923  				}}},
  1924  			},
  1925  			expectedErr: `not enough results in loop block
  1926  	have ()
  1927  	want (i32, i32)`,
  1928  		},
  1929  		{
  1930  			name: `loop.wast - type-value-void-vs-nums`,
  1931  			// This should err because the loop type use returns two values, but the block returns none:
  1932  			//	(module (func $type-value-void-vs-nums (result i32 i32)
  1933  			//	  (loop (result i32 i32) (nop))
  1934  			//	))
  1935  			module: &Module{
  1936  				TypeSection:     []*FunctionType{v_i32i32},
  1937  				FunctionSection: []Index{0},
  1938  				CodeSection: []*Code{{Body: []byte{
  1939  					OpcodeLoop, 0x0, // (loop (result i32 i32) - matches existing func type
  1940  					OpcodeNop, // (nop)
  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-num-vs-nums`,
  1951  			// This should err because the loop type use returns two values, but the block returns one:
  1952  			//	(module (func $type-value-num-vs-nums (result i32 i32)
  1953  			//	  (loop (result i32 i32) (i32.const 0))
  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  					OpcodeI32Const, 0, // (i32.const 0)
  1961  					OpcodeEnd, // loop
  1962  					OpcodeEnd, // func
  1963  				}}},
  1964  			},
  1965  			expectedErr: `not enough results in loop block
  1966  	have (i32)
  1967  	want (i32, i32)`,
  1968  		},
  1969  		{
  1970  			name: `loop.wast - type-value-partial-vs-nums`,
  1971  			// This should err because the loop type use returns two values, but the block returns one:
  1972  			//	(module (func $type-value-partial-vs-nums (result i32 i32)
  1973  			//	  (i32.const 1) (loop (result i32 i32) (i32.const 2))
  1974  			//	))
  1975  			module: &Module{
  1976  				TypeSection:     []*FunctionType{v_i32i32},
  1977  				FunctionSection: []Index{0},
  1978  				CodeSection: []*Code{{Body: []byte{
  1979  					OpcodeI32Const, 1, // (i32.const 1) - NOTE: outside the loop!
  1980  					OpcodeLoop, 0x0, // (loop (result i32 i32) - matches existing func type
  1981  					OpcodeI32Const, 2, // (i32.const 2)
  1982  					OpcodeEnd, // loop
  1983  					OpcodeEnd, // func
  1984  				}}},
  1985  			},
  1986  			expectedErr: `not enough results in loop block
  1987  	have (i32)
  1988  	want (i32, i32)`,
  1989  		},
  1990  		{
  1991  			name: `loop.wast - type-value-nums-vs-num`,
  1992  			// This should err because the loop type use returns one value, but the block returns two:
  1993  			//	(module (func $type-value-nums-vs-num (result i32)
  1994  			//	  (loop (result i32) (i32.const 1) (i32.const 2))
  1995  			//	))
  1996  			module: &Module{
  1997  				TypeSection:     []*FunctionType{v_i32},
  1998  				FunctionSection: []Index{0},
  1999  				CodeSection: []*Code{{Body: []byte{
  2000  					OpcodeLoop, 0x0, // (loop (result i32) - matches existing func type
  2001  					OpcodeI32Const, 1, OpcodeI32Const, 2, // (i32.const 1) (i32.const 2))
  2002  					OpcodeEnd, // loop
  2003  					OpcodeEnd, // func
  2004  				}}},
  2005  			},
  2006  			expectedErr: `too many results in loop block
  2007  	have (i32, i32)
  2008  	want (i32)`,
  2009  		},
  2010  		{
  2011  			name: `loop.wast - type-param-void-vs-num`,
  2012  			// This should err because the loop type use requires one param, but the stack has none:
  2013  			//	(module (func $type-param-void-vs-num
  2014  			//	  (loop (param i32) (drop))
  2015  			//	))
  2016  			module: &Module{
  2017  				TypeSection:     []*FunctionType{v_v, i32_v},
  2018  				FunctionSection: []Index{0},
  2019  				CodeSection: []*Code{{Body: []byte{
  2020  					OpcodeLoop, 0x1, // (loop (param i32)
  2021  					OpcodeDrop, // (drop)
  2022  					OpcodeEnd,  // loop
  2023  					OpcodeEnd,  // func
  2024  				}}},
  2025  			},
  2026  			expectedErr: `not enough params for loop block
  2027  	have ()
  2028  	want (i32)`,
  2029  		},
  2030  		{
  2031  			name: `loop.wast - type-param-void-vs-nums`,
  2032  			// This should err because the loop type use requires two params, but the stack has none:
  2033  			//	(module (func $type-param-void-vs-nums
  2034  			//	  (loop (param i32 f64) (drop) (drop))
  2035  			//	))
  2036  			module: &Module{
  2037  				TypeSection:     []*FunctionType{v_v, i32f64_v},
  2038  				FunctionSection: []Index{0},
  2039  				CodeSection: []*Code{{Body: []byte{
  2040  					OpcodeLoop, 0x1, // (loop (param i32 f64)
  2041  					OpcodeDrop, // (drop)
  2042  					OpcodeDrop, // (drop)
  2043  					OpcodeEnd,  // loop
  2044  					OpcodeEnd,  // func
  2045  				}}},
  2046  			},
  2047  			expectedErr: `not enough params for loop block
  2048  	have ()
  2049  	want (i32, f64)`,
  2050  		},
  2051  		{
  2052  			name: `loop.wast - type-param-num-vs-num`,
  2053  			// This should err because the loop type use requires a different param type than what's on the stack:
  2054  			//	(module (func $type-param-num-vs-num
  2055  			//	  (f32.const 0) (loop (param i32) (drop))
  2056  			//	))
  2057  			module: &Module{
  2058  				TypeSection:     []*FunctionType{v_v, i32_v},
  2059  				FunctionSection: []Index{0},
  2060  				CodeSection: []*Code{{Body: []byte{
  2061  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  2062  					OpcodeLoop, 0x1, // (loop (param i32)
  2063  					OpcodeDrop, // (drop)
  2064  					OpcodeEnd,  // loop
  2065  					OpcodeEnd,  // func
  2066  				}}},
  2067  			},
  2068  			expectedErr: "cannot use f32 in loop block as param[0] type i32",
  2069  		},
  2070  		{
  2071  			name: `loop.wast - type-param-num-vs-num`,
  2072  			// This should err because the loop type use requires a more parameters than what's on the stack:
  2073  			//	(module (func $type-param-num-vs-nums
  2074  			//	  (f32.const 0) (loop (param f32 i32) (drop) (drop))
  2075  			//	))
  2076  			module: &Module{
  2077  				TypeSection:     []*FunctionType{v_v, f32i32_v},
  2078  				FunctionSection: []Index{0},
  2079  				CodeSection: []*Code{{Body: []byte{
  2080  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  2081  					OpcodeLoop, 0x1, // (loop (param f32 i32)
  2082  					OpcodeDrop, OpcodeDrop, // (drop) (drop)
  2083  					OpcodeEnd, // loop
  2084  					OpcodeEnd, // func
  2085  				}}},
  2086  			},
  2087  			expectedErr: `not enough params for loop block
  2088  	have (f32)
  2089  	want (f32, i32)`,
  2090  		},
  2091  		{
  2092  			name: `loop.wast - type-param-nested-void-vs-num`,
  2093  			// This should err because the loop type use requires a more parameters than what's on the stack:
  2094  			//	(module (func $type-param-nested-void-vs-num
  2095  			//	  (block (loop (param i32) (drop)))
  2096  			//	))
  2097  			module: &Module{
  2098  				TypeSection:     []*FunctionType{v_v, i32_v},
  2099  				FunctionSection: []Index{0},
  2100  				CodeSection: []*Code{{Body: []byte{
  2101  					OpcodeBlock, 0x40, // (block
  2102  					OpcodeLoop, 0x1, // (loop (param i32)
  2103  					OpcodeDrop, // (drop)
  2104  					OpcodeEnd,  // loop
  2105  					OpcodeEnd,  // block
  2106  					OpcodeEnd,  // func
  2107  				}}},
  2108  			},
  2109  			expectedErr: `not enough params for loop block
  2110  	have ()
  2111  	want (i32)`,
  2112  		},
  2113  		{
  2114  			name: `loop.wast - type-param-void-vs-nums`,
  2115  			// This should err because the loop type use requires a more parameters than what's on the stack:
  2116  			//	(module (func $type-param-void-vs-nums
  2117  			//	  (block (loop (param i32 f64) (drop) (drop)))
  2118  			//	))
  2119  			module: &Module{
  2120  				TypeSection:     []*FunctionType{v_v, i32f64_v},
  2121  				FunctionSection: []Index{0},
  2122  				CodeSection: []*Code{{Body: []byte{
  2123  					OpcodeBlock, 0x40, // (block
  2124  					OpcodeLoop, 0x1, // (loop (param i32 f64)
  2125  					OpcodeDrop, OpcodeDrop, // (drop) (drop)
  2126  					OpcodeEnd, // loop
  2127  					OpcodeEnd, // block
  2128  					OpcodeEnd, // func
  2129  				}}},
  2130  			},
  2131  			expectedErr: `not enough params for loop block
  2132  	have ()
  2133  	want (i32, f64)`,
  2134  		},
  2135  		{
  2136  			name: `loop.wast - type-param-void-vs-nums`,
  2137  			// This should err because the loop type use requires a different param type than what's on the stack:
  2138  			//	(module (func $type-param-num-vs-num
  2139  			//	  (block (f32.const 0) (loop (param i32) (drop)))
  2140  			//	))
  2141  			module: &Module{
  2142  				TypeSection:     []*FunctionType{v_v, i32_v},
  2143  				FunctionSection: []Index{0},
  2144  				CodeSection: []*Code{{Body: []byte{
  2145  					OpcodeBlock, 0x40, // (block
  2146  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  2147  					OpcodeLoop, 0x1, // (loop (param i32)
  2148  					OpcodeDrop, // (drop)
  2149  					OpcodeEnd,  // loop
  2150  					OpcodeEnd,  // block
  2151  					OpcodeEnd,  // func
  2152  				}}},
  2153  			},
  2154  			expectedErr: "cannot use f32 in loop block as param[0] type i32",
  2155  		},
  2156  		{
  2157  			name: `loop.wast - type-param-void-vs-nums`,
  2158  			// This should err because the loop type use requires a more parameters than what's on the stack:
  2159  			//	(module (func $type-param-num-vs-nums
  2160  			//	  (block (f32.const 0) (loop (param f32 i32) (drop) (drop)))
  2161  			//	))
  2162  			module: &Module{
  2163  				TypeSection:     []*FunctionType{v_v, f32i32_v},
  2164  				FunctionSection: []Index{0},
  2165  				CodeSection: []*Code{{Body: []byte{
  2166  					OpcodeBlock, 0x40, // (block
  2167  					OpcodeF32Const, 0, 0, 0, 0, // (f32.const 0)
  2168  					OpcodeLoop, 0x1, // (loop (param f32 i32)
  2169  					OpcodeDrop, OpcodeDrop, // (drop) (drop)
  2170  					OpcodeEnd, // loop
  2171  					OpcodeEnd, // block
  2172  					OpcodeEnd, // func
  2173  				}}},
  2174  			},
  2175  			expectedErr: `not enough params for loop block
  2176  	have (f32)
  2177  	want (f32, i32)`,
  2178  		},
  2179  	}
  2180  
  2181  	for _, tt := range tests {
  2182  		tc := tt
  2183  
  2184  		t.Run(tc.name, func(t *testing.T) {
  2185  			err := tc.module.validateFunction(api.CoreFeatureMultiValue, 0, []Index{0}, nil, nil, nil, nil)
  2186  			require.EqualError(t, err, tc.expectedErr)
  2187  		})
  2188  	}
  2189  }
  2190  
  2191  func TestModule_funcValidation_CallIndirect(t *testing.T) {
  2192  	t.Run("ok", func(t *testing.T) {
  2193  		m := &Module{
  2194  			TypeSection:     []*FunctionType{v_v},
  2195  			FunctionSection: []Index{0},
  2196  			CodeSection: []*Code{{Body: []byte{
  2197  				OpcodeI32Const, 1,
  2198  				OpcodeCallIndirect, 0, 0,
  2199  				OpcodeEnd,
  2200  			}}},
  2201  		}
  2202  		err := m.validateFunction(api.CoreFeatureReferenceTypes, 0, []Index{0}, nil, &Memory{}, []*Table{{Type: RefTypeFuncref}}, nil)
  2203  		require.NoError(t, err)
  2204  	})
  2205  	t.Run("non zero table index", func(t *testing.T) {
  2206  		m := &Module{
  2207  			TypeSection:     []*FunctionType{v_v},
  2208  			FunctionSection: []Index{0},
  2209  			CodeSection: []*Code{{Body: []byte{
  2210  				OpcodeI32Const, 1,
  2211  				OpcodeCallIndirect, 0, 100,
  2212  				OpcodeEnd,
  2213  			}}},
  2214  		}
  2215  		t.Run("disabled", func(t *testing.T) {
  2216  			err := m.validateFunction(api.CoreFeaturesV1, 0, []Index{0}, nil, &Memory{}, []*Table{{}, {}}, nil)
  2217  			require.EqualError(t, err, "table index must be zero but was 100: feature \"reference-types\" is disabled")
  2218  		})
  2219  		t.Run("enabled but out of range", func(t *testing.T) {
  2220  			err := m.validateFunction(api.CoreFeatureReferenceTypes, 0, []Index{0}, nil, &Memory{}, []*Table{{}, {}}, nil)
  2221  			require.EqualError(t, err, "unknown table index: 100")
  2222  		})
  2223  	})
  2224  	t.Run("non funcref table", func(t *testing.T) {
  2225  		m := &Module{
  2226  			TypeSection:     []*FunctionType{v_v},
  2227  			FunctionSection: []Index{0},
  2228  			CodeSection: []*Code{{Body: []byte{
  2229  				OpcodeI32Const, 1,
  2230  				OpcodeCallIndirect, 0, 0,
  2231  				OpcodeEnd,
  2232  			}}},
  2233  		}
  2234  		err := m.validateFunction(api.CoreFeatureReferenceTypes, 0, []Index{0}, nil, &Memory{}, []*Table{{Type: RefTypeExternref}}, nil)
  2235  		require.EqualError(t, err, "table is not funcref type but was externref for call_indirect")
  2236  	})
  2237  }
  2238  
  2239  func TestModule_funcValidation_RefTypes(t *testing.T) {
  2240  	tests := []struct {
  2241  		name                    string
  2242  		body                    []byte
  2243  		flag                    api.CoreFeatures
  2244  		declaredFunctionIndexes map[Index]struct{}
  2245  		expectedErr             string
  2246  	}{
  2247  		{
  2248  			name: "ref.null (funcref)",
  2249  			flag: api.CoreFeatureReferenceTypes,
  2250  			body: []byte{
  2251  				OpcodeRefNull, ValueTypeFuncref,
  2252  				OpcodeDrop, OpcodeEnd,
  2253  			},
  2254  		},
  2255  		{
  2256  			name: "ref.null (externref)",
  2257  			flag: api.CoreFeatureReferenceTypes,
  2258  			body: []byte{
  2259  				OpcodeRefNull, ValueTypeExternref,
  2260  				OpcodeDrop, OpcodeEnd,
  2261  			},
  2262  		},
  2263  		{
  2264  			name: "ref.null - disabled",
  2265  			flag: api.CoreFeaturesV1,
  2266  			body: []byte{
  2267  				OpcodeRefNull, ValueTypeFuncref,
  2268  				OpcodeDrop, OpcodeEnd,
  2269  			},
  2270  			expectedErr: "ref.null invalid as feature \"reference-types\" is disabled",
  2271  		},
  2272  		{
  2273  			name: "ref.is_null",
  2274  			flag: api.CoreFeatureReferenceTypes,
  2275  			body: []byte{
  2276  				OpcodeRefNull, ValueTypeFuncref,
  2277  				OpcodeRefIsNull,
  2278  				OpcodeDrop, OpcodeEnd,
  2279  			},
  2280  		},
  2281  		{
  2282  			name: "ref.is_null - disabled",
  2283  			flag: api.CoreFeaturesV1,
  2284  			body: []byte{
  2285  				OpcodeRefIsNull,
  2286  				OpcodeDrop, OpcodeEnd,
  2287  			},
  2288  			expectedErr: `ref.is_null invalid as feature "reference-types" is disabled`,
  2289  		},
  2290  		{
  2291  			name:                    "ref.func",
  2292  			flag:                    api.CoreFeatureReferenceTypes,
  2293  			declaredFunctionIndexes: map[uint32]struct{}{0: {}},
  2294  			body: []byte{
  2295  				OpcodeRefFunc, 0,
  2296  				OpcodeDrop, OpcodeEnd,
  2297  			},
  2298  		},
  2299  		{
  2300  			name:                    "ref.func - undeclared function index",
  2301  			flag:                    api.CoreFeatureReferenceTypes,
  2302  			declaredFunctionIndexes: map[uint32]struct{}{0: {}},
  2303  			body: []byte{
  2304  				OpcodeRefFunc, 100,
  2305  				OpcodeDrop, OpcodeEnd,
  2306  			},
  2307  			expectedErr: `undeclared function index 100 for ref.func`,
  2308  		},
  2309  		{
  2310  			name:                    "ref.func",
  2311  			flag:                    api.CoreFeaturesV1,
  2312  			declaredFunctionIndexes: map[uint32]struct{}{0: {}},
  2313  			body: []byte{
  2314  				OpcodeRefFunc, 0,
  2315  				OpcodeDrop, OpcodeEnd,
  2316  			},
  2317  			expectedErr: "ref.func invalid as feature \"reference-types\" is disabled",
  2318  		},
  2319  	}
  2320  
  2321  	for _, tt := range tests {
  2322  		tc := tt
  2323  		t.Run(tc.name, func(t *testing.T) {
  2324  			m := &Module{
  2325  				TypeSection:     []*FunctionType{v_v},
  2326  				FunctionSection: []Index{0},
  2327  				CodeSection:     []*Code{{Body: tc.body}},
  2328  			}
  2329  			err := m.validateFunction(tc.flag, 0, []Index{0}, nil, nil, nil, tc.declaredFunctionIndexes)
  2330  			if tc.expectedErr != "" {
  2331  				require.EqualError(t, err, tc.expectedErr)
  2332  			} else {
  2333  				require.NoError(t, err)
  2334  			}
  2335  		})
  2336  	}
  2337  }
  2338  
  2339  func TestModule_funcValidation_TableGrowSizeFill(t *testing.T) {
  2340  	tables := []*Table{{Type: RefTypeFuncref}, {Type: RefTypeExternref}}
  2341  	tests := []struct {
  2342  		name        string
  2343  		body        []byte
  2344  		flag        api.CoreFeatures
  2345  		expectedErr string
  2346  	}{
  2347  		{
  2348  			name: "table.grow (funcref)",
  2349  			body: []byte{
  2350  				OpcodeRefNull, RefTypeFuncref,
  2351  				OpcodeI32Const, 1, // number of elements
  2352  				OpcodeMiscPrefix, OpcodeMiscTableGrow,
  2353  				0, // Table Index.
  2354  				OpcodeDrop,
  2355  				OpcodeEnd,
  2356  			},
  2357  			flag: api.CoreFeatureReferenceTypes,
  2358  		},
  2359  		{
  2360  			name: "table.grow (funcref) - type mismatch",
  2361  			body: []byte{
  2362  				OpcodeRefNull, RefTypeFuncref,
  2363  				OpcodeI32Const, 1, // number of elements
  2364  				OpcodeMiscPrefix, OpcodeMiscTableGrow,
  2365  				1, // Table of externref type -> mismatch.
  2366  				OpcodeEnd,
  2367  			},
  2368  			flag:        api.CoreFeatureReferenceTypes,
  2369  			expectedErr: `cannot pop the operand for table.grow: type mismatch: expected externref, but was funcref`,
  2370  		},
  2371  		{
  2372  			name: "table.grow (externref)",
  2373  			body: []byte{
  2374  				OpcodeRefNull, RefTypeExternref,
  2375  				OpcodeI32Const, 1, // number of elements
  2376  				OpcodeMiscPrefix, OpcodeMiscTableGrow,
  2377  				1, // Table Index.
  2378  				OpcodeDrop,
  2379  				OpcodeEnd,
  2380  			},
  2381  			flag: api.CoreFeatureReferenceTypes,
  2382  		},
  2383  		{
  2384  			name: "table.grow (externref) type mismatch",
  2385  			body: []byte{
  2386  				OpcodeRefNull, RefTypeExternref,
  2387  				OpcodeI32Const, 1, // number of elements
  2388  				OpcodeMiscPrefix, OpcodeMiscTableGrow,
  2389  				0, // Table of funcref type -> mismatch.
  2390  				OpcodeEnd,
  2391  			},
  2392  			flag:        api.CoreFeatureReferenceTypes,
  2393  			expectedErr: `cannot pop the operand for table.grow: type mismatch: expected funcref, but was externref`,
  2394  		},
  2395  		{
  2396  			name: "table.grow - table not found",
  2397  			body: []byte{
  2398  				OpcodeRefNull, RefTypeFuncref,
  2399  				OpcodeI32Const, 1, // number of elements
  2400  				OpcodeMiscPrefix, OpcodeMiscTableGrow,
  2401  				10, // Table Index.
  2402  				OpcodeEnd,
  2403  			},
  2404  			flag:        api.CoreFeatureReferenceTypes,
  2405  			expectedErr: `table of index 10 not found`,
  2406  		},
  2407  		{
  2408  			name: "table.size - table not found",
  2409  			body: []byte{
  2410  				OpcodeMiscPrefix, OpcodeMiscTableSize,
  2411  				10, // Table Index.
  2412  				OpcodeEnd,
  2413  			},
  2414  			flag:        api.CoreFeatureReferenceTypes,
  2415  			expectedErr: `table of index 10 not found`,
  2416  		},
  2417  		{
  2418  			name: "table.size",
  2419  			body: []byte{
  2420  				OpcodeMiscPrefix, OpcodeMiscTableSize,
  2421  				1, // Table Index.
  2422  				OpcodeDrop,
  2423  				OpcodeEnd,
  2424  			},
  2425  			flag: api.CoreFeatureReferenceTypes,
  2426  		},
  2427  		{
  2428  			name: "table.fill (funcref)",
  2429  			body: []byte{
  2430  				OpcodeI32Const, 1, // offset
  2431  				OpcodeRefNull, RefTypeFuncref,
  2432  				OpcodeI32Const, 1, // number of elements
  2433  				OpcodeMiscPrefix, OpcodeMiscTableFill,
  2434  				0, // Table Index.
  2435  				OpcodeEnd,
  2436  			},
  2437  			flag: api.CoreFeatureReferenceTypes,
  2438  		},
  2439  		{
  2440  			name: "table.fill (funcref) - type mismatch",
  2441  			body: []byte{
  2442  				OpcodeI32Const, 1, // offset
  2443  				OpcodeRefNull, RefTypeFuncref,
  2444  				OpcodeI32Const, 1, // number of elements
  2445  				OpcodeMiscPrefix, OpcodeMiscTableFill,
  2446  				1, // Table of externref type -> mismatch.
  2447  				OpcodeEnd,
  2448  			},
  2449  			flag:        api.CoreFeatureReferenceTypes,
  2450  			expectedErr: `cannot pop the operand for table.fill: type mismatch: expected externref, but was funcref`,
  2451  		},
  2452  		{
  2453  			name: "table.fill (externref)",
  2454  			body: []byte{
  2455  				OpcodeI32Const, 1, // offset
  2456  				OpcodeRefNull, RefTypeExternref,
  2457  				OpcodeI32Const, 1, // number of elements
  2458  				OpcodeMiscPrefix, OpcodeMiscTableFill,
  2459  				1, // Table Index.
  2460  				OpcodeEnd,
  2461  			},
  2462  			flag: api.CoreFeatureReferenceTypes,
  2463  		},
  2464  		{
  2465  			name: "table.fill (externref) - type mismatch",
  2466  			body: []byte{
  2467  				OpcodeI32Const, 1, // offset
  2468  				OpcodeRefNull, RefTypeExternref,
  2469  				OpcodeI32Const, 1, // number of elements
  2470  				OpcodeMiscPrefix, OpcodeMiscTableFill,
  2471  				0, // Table of funcref type -> mismatch.
  2472  				OpcodeEnd,
  2473  			},
  2474  			flag:        api.CoreFeatureReferenceTypes,
  2475  			expectedErr: `cannot pop the operand for table.fill: type mismatch: expected funcref, but was externref`,
  2476  		},
  2477  		{
  2478  			name: "table.fill - table not found",
  2479  			body: []byte{
  2480  				OpcodeMiscPrefix, OpcodeMiscTableFill,
  2481  				10, // Table Index.
  2482  				OpcodeEnd,
  2483  			},
  2484  			flag:        api.CoreFeatureReferenceTypes,
  2485  			expectedErr: `table of index 10 not found`,
  2486  		},
  2487  	}
  2488  
  2489  	for _, tt := range tests {
  2490  		tc := tt
  2491  		t.Run(tc.name, func(t *testing.T) {
  2492  			m := &Module{
  2493  				TypeSection:     []*FunctionType{v_v},
  2494  				FunctionSection: []Index{0},
  2495  				CodeSection:     []*Code{{Body: tc.body}},
  2496  			}
  2497  			err := m.validateFunction(tc.flag, 0, []Index{0}, nil, nil, tables, nil)
  2498  			if tc.expectedErr != "" {
  2499  				require.EqualError(t, err, tc.expectedErr)
  2500  			} else {
  2501  				require.NoError(t, err)
  2502  			}
  2503  		})
  2504  	}
  2505  }
  2506  
  2507  func TestModule_funcValidation_TableGetSet(t *testing.T) {
  2508  	tables := []*Table{{Type: RefTypeFuncref}, {Type: RefTypeExternref}}
  2509  	tests := []struct {
  2510  		name        string
  2511  		body        []byte
  2512  		flag        api.CoreFeatures
  2513  		expectedErr string
  2514  	}{
  2515  		{
  2516  			name: "table.get (funcref)",
  2517  			body: []byte{
  2518  				OpcodeI32Const, 0,
  2519  				OpcodeTableGet, 0,
  2520  				OpcodeRefIsNull,
  2521  				OpcodeDrop,
  2522  				OpcodeEnd,
  2523  			},
  2524  			flag: api.CoreFeatureReferenceTypes,
  2525  		},
  2526  		{
  2527  			name: "table.get (externref)",
  2528  			body: []byte{
  2529  				OpcodeI32Const, 0,
  2530  				OpcodeTableGet, 1,
  2531  				OpcodeRefIsNull,
  2532  				OpcodeDrop,
  2533  				OpcodeEnd,
  2534  			},
  2535  			flag: api.CoreFeatureReferenceTypes,
  2536  		},
  2537  		{
  2538  			name: "table.get (disabled)",
  2539  			body: []byte{
  2540  				OpcodeI32Const, 0,
  2541  				OpcodeTableGet, 0,
  2542  				OpcodeDrop,
  2543  				OpcodeEnd,
  2544  			},
  2545  			flag:        api.CoreFeaturesV1,
  2546  			expectedErr: `table.get is invalid as feature "reference-types" is disabled`,
  2547  		},
  2548  		{
  2549  			name: "table.set (funcref)",
  2550  			body: []byte{
  2551  				OpcodeI32Const, 0,
  2552  				OpcodeRefNull, ValueTypeFuncref,
  2553  				OpcodeTableSet, 0,
  2554  				OpcodeEnd,
  2555  			},
  2556  			flag: api.CoreFeatureReferenceTypes,
  2557  		},
  2558  		{
  2559  			name: "table.set type mismatch (src=funcref, dst=externref)",
  2560  			body: []byte{
  2561  				OpcodeI32Const, 0,
  2562  				OpcodeRefNull, ValueTypeFuncref,
  2563  				OpcodeTableSet, 1,
  2564  				OpcodeEnd,
  2565  			},
  2566  			flag:        api.CoreFeatureReferenceTypes,
  2567  			expectedErr: `cannot pop the operand for table.set: type mismatch: expected externref, but was funcref`,
  2568  		},
  2569  		{
  2570  			name: "table.set (externref)",
  2571  			body: []byte{
  2572  				OpcodeI32Const, 0,
  2573  				OpcodeRefNull, ValueTypeExternref,
  2574  				OpcodeTableSet, 1,
  2575  				OpcodeEnd,
  2576  			},
  2577  			flag: api.CoreFeatureReferenceTypes,
  2578  		},
  2579  		{
  2580  			name: "table.set type mismatch (src=externref, dst=funcref)",
  2581  			body: []byte{
  2582  				OpcodeI32Const, 0,
  2583  				OpcodeRefNull, ValueTypeExternref,
  2584  				OpcodeTableSet, 0,
  2585  				OpcodeEnd,
  2586  			},
  2587  			flag:        api.CoreFeatureReferenceTypes,
  2588  			expectedErr: `cannot pop the operand for table.set: type mismatch: expected funcref, but was externref`,
  2589  		},
  2590  		{
  2591  			name: "table.set (disabled)",
  2592  			body: []byte{
  2593  				OpcodeTableSet, 1,
  2594  				OpcodeEnd,
  2595  			},
  2596  			flag:        api.CoreFeaturesV1,
  2597  			expectedErr: `table.set is invalid as feature "reference-types" is disabled`,
  2598  		},
  2599  	}
  2600  
  2601  	for _, tt := range tests {
  2602  		tc := tt
  2603  		t.Run(tc.name, func(t *testing.T) {
  2604  			m := &Module{
  2605  				TypeSection:     []*FunctionType{v_v},
  2606  				FunctionSection: []Index{0},
  2607  				CodeSection:     []*Code{{Body: tc.body}},
  2608  			}
  2609  			err := m.validateFunction(tc.flag, 0, []Index{0}, nil, nil, tables, nil)
  2610  			if tc.expectedErr != "" {
  2611  				require.EqualError(t, err, tc.expectedErr)
  2612  			} else {
  2613  				require.NoError(t, err)
  2614  			}
  2615  		})
  2616  	}
  2617  }
  2618  
  2619  func TestModule_funcValidation_Select_error(t *testing.T) {
  2620  	tests := []struct {
  2621  		name        string
  2622  		body        []byte
  2623  		flag        api.CoreFeatures
  2624  		expectedErr string
  2625  	}{
  2626  		{
  2627  			name: "typed_select (disabled)",
  2628  			body: []byte{
  2629  				OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0,
  2630  				OpcodeTypedSelect, 1, ValueTypeI32, // immediate vector's size must be one
  2631  				OpcodeDrop,
  2632  				OpcodeEnd,
  2633  			},
  2634  			flag:        api.CoreFeaturesV1,
  2635  			expectedErr: "typed_select is invalid as feature \"reference-types\" is disabled",
  2636  		},
  2637  		{
  2638  			name: "typed_select (too many immediate types)",
  2639  			body: []byte{
  2640  				OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0,
  2641  				OpcodeTypedSelect, 2, // immediate vector's size must be one
  2642  			},
  2643  			flag:        api.CoreFeatureReferenceTypes,
  2644  			expectedErr: `too many type immediates for typed_select`,
  2645  		},
  2646  		{
  2647  			name: "typed_select (immediate type not found)",
  2648  			body: []byte{
  2649  				OpcodeI32Const, 0, OpcodeI32Const, 0, OpcodeI32Const, 0,
  2650  				OpcodeTypedSelect, 1, 0,
  2651  				OpcodeEnd,
  2652  			},
  2653  			flag:        api.CoreFeatureReferenceTypes,
  2654  			expectedErr: `invalid type unknown for typed_select`,
  2655  		},
  2656  	}
  2657  
  2658  	for _, tt := range tests {
  2659  		tc := tt
  2660  		t.Run(tc.name, func(t *testing.T) {
  2661  			m := &Module{
  2662  				TypeSection:     []*FunctionType{v_v},
  2663  				FunctionSection: []Index{0},
  2664  				CodeSection:     []*Code{{Body: tc.body}},
  2665  			}
  2666  			err := m.validateFunction(tc.flag, 0, []Index{0}, nil, nil, nil, nil)
  2667  			require.EqualError(t, err, tc.expectedErr)
  2668  		})
  2669  	}
  2670  }
  2671  
  2672  func TestModule_funcValidation_SIMD(t *testing.T) {
  2673  	addV128Const := func(in []byte) []byte {
  2674  		return append(in, OpcodeVecPrefix,
  2675  			OpcodeVecV128Const,
  2676  			1, 1, 1, 1, 1, 1, 1, 1,
  2677  			1, 1, 1, 1, 1, 1, 1, 1)
  2678  	}
  2679  	vv2v := func(vec OpcodeVec) (ret []byte) {
  2680  		ret = addV128Const(ret)
  2681  		ret = addV128Const(ret)
  2682  		return append(ret,
  2683  			OpcodeVecPrefix,
  2684  			vec,
  2685  			OpcodeDrop,
  2686  			OpcodeEnd,
  2687  		)
  2688  	}
  2689  	vvv2v := func(vec OpcodeVec) (ret []byte) {
  2690  		ret = addV128Const(ret)
  2691  		ret = addV128Const(ret)
  2692  		ret = addV128Const(ret)
  2693  		return append(ret,
  2694  			OpcodeVecPrefix,
  2695  			vec,
  2696  			OpcodeDrop,
  2697  			OpcodeEnd,
  2698  		)
  2699  	}
  2700  
  2701  	v2v := func(vec OpcodeVec) (ret []byte) {
  2702  		ret = addV128Const(ret)
  2703  		return append(ret,
  2704  			OpcodeVecPrefix,
  2705  			vec,
  2706  			OpcodeDrop,
  2707  			OpcodeEnd,
  2708  		)
  2709  	}
  2710  
  2711  	vi2v := func(vec OpcodeVec) (ret []byte) {
  2712  		ret = addV128Const(ret)
  2713  		return append(ret,
  2714  			OpcodeI32Const, 1,
  2715  			OpcodeVecPrefix,
  2716  			vec,
  2717  			OpcodeDrop,
  2718  			OpcodeEnd,
  2719  		)
  2720  	}
  2721  
  2722  	load := func(vec OpcodeVec, offset, align uint32) (ret []byte) {
  2723  		ret = []byte{
  2724  			OpcodeI32Const, 1,
  2725  			OpcodeVecPrefix,
  2726  			vec,
  2727  		}
  2728  
  2729  		ret = append(ret, leb128.EncodeUint32(align)...)
  2730  		ret = append(ret, leb128.EncodeUint32(offset)...)
  2731  		ret = append(ret,
  2732  			OpcodeDrop,
  2733  			OpcodeEnd,
  2734  		)
  2735  		return
  2736  	}
  2737  
  2738  	loadLane := func(vec OpcodeVec, offset, align uint32, lane byte) (ret []byte) {
  2739  		ret = addV128Const([]byte{OpcodeI32Const, 1})
  2740  		ret = append(ret,
  2741  			OpcodeVecPrefix,
  2742  			vec,
  2743  		)
  2744  
  2745  		ret = append(ret, leb128.EncodeUint32(align)...)
  2746  		ret = append(ret, leb128.EncodeUint32(offset)...)
  2747  		ret = append(ret,
  2748  			lane,
  2749  			OpcodeDrop,
  2750  			OpcodeEnd,
  2751  		)
  2752  		return
  2753  	}
  2754  
  2755  	storeLane := func(vec OpcodeVec, offset, align uint32, lane byte) (ret []byte) {
  2756  		ret = addV128Const([]byte{OpcodeI32Const, 1})
  2757  		ret = append(ret,
  2758  			OpcodeVecPrefix,
  2759  			vec,
  2760  		)
  2761  		ret = append(ret, leb128.EncodeUint32(align)...)
  2762  		ret = append(ret, leb128.EncodeUint32(offset)...)
  2763  		ret = append(ret,
  2764  			lane,
  2765  			OpcodeEnd,
  2766  		)
  2767  		return
  2768  	}
  2769  
  2770  	extractLane := func(vec OpcodeVec, lane byte) (ret []byte) {
  2771  		ret = addV128Const(ret)
  2772  		ret = append(ret,
  2773  			OpcodeVecPrefix,
  2774  			vec,
  2775  			lane,
  2776  			OpcodeDrop,
  2777  			OpcodeEnd,
  2778  		)
  2779  		return
  2780  	}
  2781  
  2782  	replaceLane := func(vec OpcodeVec, lane byte) (ret []byte) {
  2783  		ret = addV128Const(ret)
  2784  
  2785  		switch vec {
  2786  		case OpcodeVecI8x16ReplaceLane, OpcodeVecI16x8ReplaceLane, OpcodeVecI32x4ReplaceLane:
  2787  			ret = append(ret, OpcodeI32Const, 0)
  2788  		case OpcodeVecI64x2ReplaceLane:
  2789  			ret = append(ret, OpcodeI64Const, 0)
  2790  		case OpcodeVecF32x4ReplaceLane:
  2791  			ret = append(ret, OpcodeF32Const, 0, 0, 0, 0)
  2792  		case OpcodeVecF64x2ReplaceLane:
  2793  			ret = append(ret, OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0)
  2794  		}
  2795  
  2796  		ret = append(ret,
  2797  			OpcodeVecPrefix,
  2798  			vec,
  2799  			lane,
  2800  			OpcodeDrop,
  2801  			OpcodeEnd,
  2802  		)
  2803  		return
  2804  	}
  2805  
  2806  	splat := func(vec OpcodeVec) (ret []byte) {
  2807  		switch vec {
  2808  		case OpcodeVecI8x16Splat, OpcodeVecI16x8Splat, OpcodeVecI32x4Splat:
  2809  			ret = append(ret, OpcodeI32Const, 0, 0, 0, 0)
  2810  		case OpcodeVecI64x2Splat:
  2811  			ret = append(ret, OpcodeI64Const, 0, 0, 0, 0, 0, 0, 0, 0)
  2812  		case OpcodeVecF32x4Splat:
  2813  			ret = append(ret, OpcodeF32Const, 0, 0, 0, 0)
  2814  		case OpcodeVecF64x2Splat:
  2815  			ret = append(ret, OpcodeF64Const, 0, 0, 0, 0, 0, 0, 0, 0)
  2816  		}
  2817  
  2818  		ret = append(ret,
  2819  			OpcodeVecPrefix,
  2820  			vec,
  2821  			OpcodeDrop,
  2822  			OpcodeEnd,
  2823  		)
  2824  		return
  2825  	}
  2826  
  2827  	tests := []struct {
  2828  		name        string
  2829  		body        []byte
  2830  		expectedErr string
  2831  	}{
  2832  		{
  2833  			name: "v128.const",
  2834  			body: []byte{
  2835  				OpcodeVecPrefix,
  2836  				OpcodeVecV128Const,
  2837  				1, 1, 1, 1, 1, 1, 1, 1,
  2838  				1, 1, 1, 1, 1, 1, 1, 1,
  2839  				OpcodeDrop,
  2840  				OpcodeEnd,
  2841  			},
  2842  		},
  2843  		{name: OpcodeVecI8x16AddName, body: vv2v(OpcodeVecI8x16Add)},
  2844  		{name: OpcodeVecI16x8AddName, body: vv2v(OpcodeVecI16x8Add)},
  2845  		{name: OpcodeVecI32x4AddName, body: vv2v(OpcodeVecI32x4Add)},
  2846  		{name: OpcodeVecI64x2AddName, body: vv2v(OpcodeVecI64x2Add)},
  2847  		{name: OpcodeVecI8x16SubName, body: vv2v(OpcodeVecI8x16Sub)},
  2848  		{name: OpcodeVecI16x8SubName, body: vv2v(OpcodeVecI16x8Sub)},
  2849  		{name: OpcodeVecI32x4SubName, body: vv2v(OpcodeVecI32x4Sub)},
  2850  		{name: OpcodeVecI64x2SubName, body: vv2v(OpcodeVecI64x2Sub)},
  2851  		{name: OpcodeVecV128AnyTrueName, body: v2v(OpcodeVecV128AnyTrue)},
  2852  		{name: OpcodeVecI8x16AllTrueName, body: v2v(OpcodeVecI8x16AllTrue)},
  2853  		{name: OpcodeVecI16x8AllTrueName, body: v2v(OpcodeVecI16x8AllTrue)},
  2854  		{name: OpcodeVecI32x4AllTrueName, body: v2v(OpcodeVecI32x4AllTrue)},
  2855  		{name: OpcodeVecI64x2AllTrueName, body: v2v(OpcodeVecI64x2AllTrue)},
  2856  		{name: OpcodeVecI8x16BitMaskName, body: v2v(OpcodeVecI8x16BitMask)},
  2857  		{name: OpcodeVecI16x8BitMaskName, body: v2v(OpcodeVecI16x8BitMask)},
  2858  		{name: OpcodeVecI32x4BitMaskName, body: v2v(OpcodeVecI32x4BitMask)},
  2859  		{name: OpcodeVecI64x2BitMaskName, body: v2v(OpcodeVecI64x2BitMask)},
  2860  		{name: OpcodeVecV128LoadName, body: load(OpcodeVecV128Load, 0, 0)},
  2861  		{name: OpcodeVecV128LoadName + "/align=4", body: load(OpcodeVecV128Load, 0, 4)},
  2862  		{name: OpcodeVecV128Load8x8SName, body: load(OpcodeVecV128Load8x8s, 1, 0)},
  2863  		{name: OpcodeVecV128Load8x8SName + "/align=1", body: load(OpcodeVecV128Load8x8s, 0, 1)},
  2864  		{name: OpcodeVecV128Load8x8UName, body: load(OpcodeVecV128Load8x8u, 0, 0)},
  2865  		{name: OpcodeVecV128Load8x8UName + "/align=1", body: load(OpcodeVecV128Load8x8u, 0, 1)},
  2866  		{name: OpcodeVecV128Load16x4SName, body: load(OpcodeVecV128Load16x4s, 1, 0)},
  2867  		{name: OpcodeVecV128Load16x4SName + "/align=2", body: load(OpcodeVecV128Load16x4s, 0, 2)},
  2868  		{name: OpcodeVecV128Load16x4UName, body: load(OpcodeVecV128Load16x4u, 0, 0)},
  2869  		{name: OpcodeVecV128Load16x4UName + "/align=2", body: load(OpcodeVecV128Load16x4u, 0, 2)},
  2870  		{name: OpcodeVecV128Load32x2SName, body: load(OpcodeVecV128Load32x2s, 1, 0)},
  2871  		{name: OpcodeVecV128Load32x2SName + "/align=3", body: load(OpcodeVecV128Load32x2s, 0, 3)},
  2872  		{name: OpcodeVecV128Load32x2UName, body: load(OpcodeVecV128Load32x2u, 0, 0)},
  2873  		{name: OpcodeVecV128Load32x2UName + "/align=3", body: load(OpcodeVecV128Load32x2u, 0, 3)},
  2874  		{name: OpcodeVecV128Load8SplatName, body: load(OpcodeVecV128Load8Splat, 2, 0)},
  2875  		{name: OpcodeVecV128Load16SplatName, body: load(OpcodeVecV128Load16Splat, 0, 1)},
  2876  		{name: OpcodeVecV128Load32SplatName, body: load(OpcodeVecV128Load32Splat, 3, 2)},
  2877  		{name: OpcodeVecV128Load64SplatName, body: load(OpcodeVecV128Load64Splat, 0, 3)},
  2878  		{name: OpcodeVecV128Load32zeroName, body: load(OpcodeVecV128Load32zero, 0, 2)},
  2879  		{name: OpcodeVecV128Load64zeroName, body: load(OpcodeVecV128Load64zero, 5, 3)},
  2880  		{name: OpcodeVecV128Load8LaneName, body: loadLane(OpcodeVecV128Load8Lane, 5, 0, 10)},
  2881  		{name: OpcodeVecV128Load16LaneName, body: loadLane(OpcodeVecV128Load16Lane, 100, 1, 7)},
  2882  		{name: OpcodeVecV128Load32LaneName, body: loadLane(OpcodeVecV128Load32Lane, 0, 2, 3)},
  2883  		{name: OpcodeVecV128Load64LaneName, body: loadLane(OpcodeVecV128Load64Lane, 0, 3, 1)},
  2884  		{
  2885  			name: OpcodeVecV128StoreName, body: []byte{
  2886  				OpcodeI32Const,
  2887  				1, 1, 1, 1,
  2888  				OpcodeVecPrefix,
  2889  				OpcodeVecV128Const,
  2890  				1, 1, 1, 1, 1, 1, 1, 1,
  2891  				1, 1, 1, 1, 1, 1, 1, 1,
  2892  				OpcodeVecPrefix,
  2893  				OpcodeVecV128Store,
  2894  				4,  // alignment
  2895  				10, // offset
  2896  				OpcodeEnd,
  2897  			},
  2898  		},
  2899  		{name: OpcodeVecV128Store8LaneName, body: storeLane(OpcodeVecV128Store8Lane, 0, 0, 0)},
  2900  		{name: OpcodeVecV128Store8LaneName + "/lane=15", body: storeLane(OpcodeVecV128Store8Lane, 100, 0, 15)},
  2901  		{name: OpcodeVecV128Store16LaneName, body: storeLane(OpcodeVecV128Store16Lane, 0, 0, 0)},
  2902  		{name: OpcodeVecV128Store16LaneName + "/lane=7/align=1", body: storeLane(OpcodeVecV128Store16Lane, 100, 1, 7)},
  2903  		{name: OpcodeVecV128Store32LaneName, body: storeLane(OpcodeVecV128Store32Lane, 0, 0, 0)},
  2904  		{name: OpcodeVecV128Store32LaneName + "/lane=3/align=2", body: storeLane(OpcodeVecV128Store32Lane, 100, 2, 3)},
  2905  		{name: OpcodeVecV128Store64LaneName, body: storeLane(OpcodeVecV128Store64Lane, 0, 0, 0)},
  2906  		{name: OpcodeVecV128Store64LaneName + "/lane=1/align=3", body: storeLane(OpcodeVecV128Store64Lane, 50, 3, 1)},
  2907  		{name: OpcodeVecI8x16ExtractLaneSName, body: extractLane(OpcodeVecI8x16ExtractLaneS, 0)},
  2908  		{name: OpcodeVecI8x16ExtractLaneSName + "/lane=15", body: extractLane(OpcodeVecI8x16ExtractLaneS, 15)},
  2909  		{name: OpcodeVecI8x16ExtractLaneUName, body: extractLane(OpcodeVecI8x16ExtractLaneU, 0)},
  2910  		{name: OpcodeVecI8x16ExtractLaneUName + "/lane=15", body: extractLane(OpcodeVecI8x16ExtractLaneU, 15)},
  2911  		{name: OpcodeVecI16x8ExtractLaneSName, body: extractLane(OpcodeVecI16x8ExtractLaneS, 0)},
  2912  		{name: OpcodeVecI16x8ExtractLaneSName + "/lane=7", body: extractLane(OpcodeVecI16x8ExtractLaneS, 7)},
  2913  		{name: OpcodeVecI16x8ExtractLaneUName, body: extractLane(OpcodeVecI16x8ExtractLaneU, 0)},
  2914  		{name: OpcodeVecI16x8ExtractLaneUName + "/lane=8", body: extractLane(OpcodeVecI16x8ExtractLaneU, 7)},
  2915  		{name: OpcodeVecI32x4ExtractLaneName, body: extractLane(OpcodeVecI32x4ExtractLane, 0)},
  2916  		{name: OpcodeVecI32x4ExtractLaneName + "/lane=3", body: extractLane(OpcodeVecI32x4ExtractLane, 3)},
  2917  		{name: OpcodeVecI64x2ExtractLaneName, body: extractLane(OpcodeVecI64x2ExtractLane, 0)},
  2918  		{name: OpcodeVecI64x2ExtractLaneName + "/lane=1", body: extractLane(OpcodeVecI64x2ExtractLane, 1)},
  2919  		{name: OpcodeVecF32x4ExtractLaneName, body: extractLane(OpcodeVecF32x4ExtractLane, 0)},
  2920  		{name: OpcodeVecF32x4ExtractLaneName + "/lane=3", body: extractLane(OpcodeVecF32x4ExtractLane, 3)},
  2921  		{name: OpcodeVecF64x2ExtractLaneName, body: extractLane(OpcodeVecF64x2ExtractLane, 0)},
  2922  		{name: OpcodeVecF64x2ExtractLaneName + "/lane=1", body: extractLane(OpcodeVecF64x2ExtractLane, 1)},
  2923  		{name: OpcodeVecI8x16ReplaceLaneName, body: replaceLane(OpcodeVecI8x16ReplaceLane, 0)},
  2924  		{name: OpcodeVecI8x16ReplaceLaneName + "/lane=15", body: replaceLane(OpcodeVecI8x16ReplaceLane, 15)},
  2925  		{name: OpcodeVecI16x8ReplaceLaneName, body: replaceLane(OpcodeVecI16x8ReplaceLane, 0)},
  2926  		{name: OpcodeVecI16x8ReplaceLaneName + "/lane=7", body: replaceLane(OpcodeVecI16x8ReplaceLane, 7)},
  2927  		{name: OpcodeVecI32x4ReplaceLaneName, body: replaceLane(OpcodeVecI32x4ReplaceLane, 0)},
  2928  		{name: OpcodeVecI32x4ReplaceLaneName + "/lane=3", body: replaceLane(OpcodeVecI32x4ReplaceLane, 3)},
  2929  		{name: OpcodeVecI64x2ReplaceLaneName, body: replaceLane(OpcodeVecI64x2ReplaceLane, 0)},
  2930  		{name: OpcodeVecI64x2ReplaceLaneName + "/lane=1", body: replaceLane(OpcodeVecI64x2ReplaceLane, 1)},
  2931  		{name: OpcodeVecF32x4ReplaceLaneName, body: replaceLane(OpcodeVecF32x4ReplaceLane, 0)},
  2932  		{name: OpcodeVecF32x4ReplaceLaneName + "/lane=3", body: replaceLane(OpcodeVecF32x4ReplaceLane, 3)},
  2933  		{name: OpcodeVecF64x2ReplaceLaneName, body: replaceLane(OpcodeVecF64x2ReplaceLane, 0)},
  2934  		{name: OpcodeVecF64x2ReplaceLaneName + "/lane=1", body: replaceLane(OpcodeVecF64x2ReplaceLane, 1)},
  2935  		{name: OpcodeVecI8x16SplatName, body: splat(OpcodeVecI8x16Splat)},
  2936  		{name: OpcodeVecI16x8SplatName, body: splat(OpcodeVecI16x8Splat)},
  2937  		{name: OpcodeVecI32x4SplatName, body: splat(OpcodeVecI32x4Splat)},
  2938  		{name: OpcodeVecI64x2SplatName, body: splat(OpcodeVecI64x2Splat)},
  2939  		{name: OpcodeVecF32x4SplatName, body: splat(OpcodeVecF32x4Splat)},
  2940  		{name: OpcodeVecF64x2SplatName, body: splat(OpcodeVecF64x2Splat)},
  2941  		{name: OpcodeVecI8x16SwizzleName, body: vv2v(OpcodeVecI8x16Swizzle)},
  2942  		{
  2943  			name: OpcodeVecV128i8x16ShuffleName, body: []byte{
  2944  				OpcodeVecPrefix,
  2945  				OpcodeVecV128Const,
  2946  				1, 1, 1, 1, 1, 1, 1, 1,
  2947  				1, 1, 1, 1, 1, 1, 1, 1,
  2948  				OpcodeVecPrefix,
  2949  				OpcodeVecV128Const,
  2950  				1, 1, 1, 1, 1, 1, 1, 1,
  2951  				1, 1, 1, 1, 1, 1, 1, 1,
  2952  				OpcodeVecPrefix,
  2953  				OpcodeVecV128i8x16Shuffle,
  2954  				1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
  2955  				OpcodeDrop,
  2956  				OpcodeEnd,
  2957  			},
  2958  		},
  2959  		{name: OpcodeVecV128NotName, body: v2v(OpcodeVecV128Not)},
  2960  		{name: OpcodeVecV128AndName, body: vv2v(OpcodeVecV128And)},
  2961  		{name: OpcodeVecV128AndNotName, body: vv2v(OpcodeVecV128AndNot)},
  2962  		{name: OpcodeVecV128OrName, body: vv2v(OpcodeVecV128Or)},
  2963  		{name: OpcodeVecV128XorName, body: vv2v(OpcodeVecV128Xor)},
  2964  		{name: OpcodeVecV128BitselectName, body: vvv2v(OpcodeVecV128Bitselect)},
  2965  		{name: OpcodeVecI8x16ShlName, body: vi2v(OpcodeVecI8x16Shl)},
  2966  		{name: OpcodeVecI8x16ShrSName, body: vi2v(OpcodeVecI8x16ShrS)},
  2967  		{name: OpcodeVecI8x16ShrUName, body: vi2v(OpcodeVecI8x16ShrU)},
  2968  		{name: OpcodeVecI16x8ShlName, body: vi2v(OpcodeVecI16x8Shl)},
  2969  		{name: OpcodeVecI16x8ShrSName, body: vi2v(OpcodeVecI16x8ShrS)},
  2970  		{name: OpcodeVecI16x8ShrUName, body: vi2v(OpcodeVecI16x8ShrU)},
  2971  		{name: OpcodeVecI32x4ShlName, body: vi2v(OpcodeVecI32x4Shl)},
  2972  		{name: OpcodeVecI32x4ShrSName, body: vi2v(OpcodeVecI32x4ShrS)},
  2973  		{name: OpcodeVecI32x4ShrUName, body: vi2v(OpcodeVecI32x4ShrU)},
  2974  		{name: OpcodeVecI64x2ShlName, body: vi2v(OpcodeVecI64x2Shl)},
  2975  		{name: OpcodeVecI64x2ShrSName, body: vi2v(OpcodeVecI64x2ShrS)},
  2976  		{name: OpcodeVecI64x2ShrUName, body: vi2v(OpcodeVecI64x2ShrU)},
  2977  		{name: OpcodeVecI8x16EqName, body: vv2v(OpcodeVecI8x16Eq)},
  2978  		{name: OpcodeVecI8x16NeName, body: vv2v(OpcodeVecI8x16Ne)},
  2979  		{name: OpcodeVecI8x16LtSName, body: vv2v(OpcodeVecI8x16LtS)},
  2980  		{name: OpcodeVecI8x16LtUName, body: vv2v(OpcodeVecI8x16LtU)},
  2981  		{name: OpcodeVecI8x16GtSName, body: vv2v(OpcodeVecI8x16GtS)},
  2982  		{name: OpcodeVecI8x16GtUName, body: vv2v(OpcodeVecI8x16GtU)},
  2983  		{name: OpcodeVecI8x16LeSName, body: vv2v(OpcodeVecI8x16LeS)},
  2984  		{name: OpcodeVecI8x16LeUName, body: vv2v(OpcodeVecI8x16LeU)},
  2985  		{name: OpcodeVecI8x16GeSName, body: vv2v(OpcodeVecI8x16GeS)},
  2986  		{name: OpcodeVecI8x16GeUName, body: vv2v(OpcodeVecI8x16GeU)},
  2987  		{name: OpcodeVecI16x8EqName, body: vv2v(OpcodeVecI16x8Eq)},
  2988  		{name: OpcodeVecI16x8NeName, body: vv2v(OpcodeVecI16x8Ne)},
  2989  		{name: OpcodeVecI16x8LtSName, body: vv2v(OpcodeVecI16x8LtS)},
  2990  		{name: OpcodeVecI16x8LtUName, body: vv2v(OpcodeVecI16x8LtU)},
  2991  		{name: OpcodeVecI16x8GtSName, body: vv2v(OpcodeVecI16x8GtS)},
  2992  		{name: OpcodeVecI16x8GtUName, body: vv2v(OpcodeVecI16x8GtU)},
  2993  		{name: OpcodeVecI16x8LeSName, body: vv2v(OpcodeVecI16x8LeS)},
  2994  		{name: OpcodeVecI16x8LeUName, body: vv2v(OpcodeVecI16x8LeU)},
  2995  		{name: OpcodeVecI16x8GeSName, body: vv2v(OpcodeVecI16x8GeS)},
  2996  		{name: OpcodeVecI16x8GeUName, body: vv2v(OpcodeVecI16x8GeU)},
  2997  		{name: OpcodeVecI32x4EqName, body: vv2v(OpcodeVecI32x4Eq)},
  2998  		{name: OpcodeVecI32x4NeName, body: vv2v(OpcodeVecI32x4Ne)},
  2999  		{name: OpcodeVecI32x4LtSName, body: vv2v(OpcodeVecI32x4LtS)},
  3000  		{name: OpcodeVecI32x4LtUName, body: vv2v(OpcodeVecI32x4LtU)},
  3001  		{name: OpcodeVecI32x4GtSName, body: vv2v(OpcodeVecI32x4GtS)},
  3002  		{name: OpcodeVecI32x4GtUName, body: vv2v(OpcodeVecI32x4GtU)},
  3003  		{name: OpcodeVecI32x4LeSName, body: vv2v(OpcodeVecI32x4LeS)},
  3004  		{name: OpcodeVecI32x4LeUName, body: vv2v(OpcodeVecI32x4LeU)},
  3005  		{name: OpcodeVecI32x4GeSName, body: vv2v(OpcodeVecI32x4GeS)},
  3006  		{name: OpcodeVecI32x4GeUName, body: vv2v(OpcodeVecI32x4GeU)},
  3007  		{name: OpcodeVecI64x2EqName, body: vv2v(OpcodeVecI64x2Eq)},
  3008  		{name: OpcodeVecI64x2NeName, body: vv2v(OpcodeVecI64x2Ne)},
  3009  		{name: OpcodeVecI64x2LtSName, body: vv2v(OpcodeVecI64x2LtS)},
  3010  		{name: OpcodeVecI64x2GtSName, body: vv2v(OpcodeVecI64x2GtS)},
  3011  		{name: OpcodeVecI64x2LeSName, body: vv2v(OpcodeVecI64x2LeS)},
  3012  		{name: OpcodeVecI64x2GeSName, body: vv2v(OpcodeVecI64x2GeS)},
  3013  		{name: OpcodeVecF32x4EqName, body: vv2v(OpcodeVecF32x4Eq)},
  3014  		{name: OpcodeVecF32x4NeName, body: vv2v(OpcodeVecF32x4Ne)},
  3015  		{name: OpcodeVecF32x4LtName, body: vv2v(OpcodeVecF32x4Lt)},
  3016  		{name: OpcodeVecF32x4GtName, body: vv2v(OpcodeVecF32x4Gt)},
  3017  		{name: OpcodeVecF32x4LeName, body: vv2v(OpcodeVecF32x4Le)},
  3018  		{name: OpcodeVecF32x4GeName, body: vv2v(OpcodeVecF32x4Ge)},
  3019  		{name: OpcodeVecF64x2EqName, body: vv2v(OpcodeVecF64x2Eq)},
  3020  		{name: OpcodeVecF64x2NeName, body: vv2v(OpcodeVecF64x2Ne)},
  3021  		{name: OpcodeVecF64x2LtName, body: vv2v(OpcodeVecF64x2Lt)},
  3022  		{name: OpcodeVecF64x2GtName, body: vv2v(OpcodeVecF64x2Gt)},
  3023  		{name: OpcodeVecF64x2LeName, body: vv2v(OpcodeVecF64x2Le)},
  3024  		{name: OpcodeVecF64x2GeName, body: vv2v(OpcodeVecF64x2Ge)},
  3025  		{name: OpcodeVecI8x16AddName, body: vv2v(OpcodeVecI8x16Add)},
  3026  		{name: OpcodeVecI8x16AddSatSName, body: vv2v(OpcodeVecI8x16AddSatS)},
  3027  		{name: OpcodeVecI8x16AddSatUName, body: vv2v(OpcodeVecI8x16AddSatU)},
  3028  		{name: OpcodeVecI8x16SubName, body: vv2v(OpcodeVecI8x16Sub)},
  3029  		{name: OpcodeVecI8x16SubSatSName, body: vv2v(OpcodeVecI8x16SubSatS)},
  3030  		{name: OpcodeVecI8x16SubSatUName, body: vv2v(OpcodeVecI8x16SubSatU)},
  3031  		{name: OpcodeVecI16x8AddName, body: vv2v(OpcodeVecI16x8Add)},
  3032  		{name: OpcodeVecI16x8AddSatSName, body: vv2v(OpcodeVecI16x8AddSatS)},
  3033  		{name: OpcodeVecI16x8AddSatUName, body: vv2v(OpcodeVecI16x8AddSatU)},
  3034  		{name: OpcodeVecI16x8SubName, body: vv2v(OpcodeVecI16x8Sub)},
  3035  		{name: OpcodeVecI16x8SubSatSName, body: vv2v(OpcodeVecI16x8SubSatS)},
  3036  		{name: OpcodeVecI16x8SubSatUName, body: vv2v(OpcodeVecI16x8SubSatU)},
  3037  		{name: OpcodeVecI16x8MulName, body: vv2v(OpcodeVecI16x8Mul)},
  3038  		{name: OpcodeVecI32x4AddName, body: vv2v(OpcodeVecI32x4Add)},
  3039  		{name: OpcodeVecI32x4SubName, body: vv2v(OpcodeVecI32x4Sub)},
  3040  		{name: OpcodeVecI32x4MulName, body: vv2v(OpcodeVecI32x4Mul)},
  3041  		{name: OpcodeVecI64x2AddName, body: vv2v(OpcodeVecI64x2Add)},
  3042  		{name: OpcodeVecI64x2SubName, body: vv2v(OpcodeVecI64x2Sub)},
  3043  		{name: OpcodeVecI64x2MulName, body: vv2v(OpcodeVecI64x2Mul)},
  3044  		{name: OpcodeVecF32x4AddName, body: vv2v(OpcodeVecF32x4Add)},
  3045  		{name: OpcodeVecF32x4SubName, body: vv2v(OpcodeVecF32x4Sub)},
  3046  		{name: OpcodeVecF32x4MulName, body: vv2v(OpcodeVecF32x4Mul)},
  3047  		{name: OpcodeVecF32x4DivName, body: vv2v(OpcodeVecF32x4Div)},
  3048  		{name: OpcodeVecF64x2AddName, body: vv2v(OpcodeVecF64x2Add)},
  3049  		{name: OpcodeVecF64x2SubName, body: vv2v(OpcodeVecF64x2Sub)},
  3050  		{name: OpcodeVecF64x2MulName, body: vv2v(OpcodeVecF64x2Mul)},
  3051  		{name: OpcodeVecF64x2DivName, body: vv2v(OpcodeVecF64x2Div)},
  3052  		{name: OpcodeVecI8x16NegName, body: v2v(OpcodeVecI8x16Neg)},
  3053  		{name: OpcodeVecI16x8NegName, body: v2v(OpcodeVecI16x8Neg)},
  3054  		{name: OpcodeVecI32x4NegName, body: v2v(OpcodeVecI32x4Neg)},
  3055  		{name: OpcodeVecI64x2NegName, body: v2v(OpcodeVecI64x2Neg)},
  3056  		{name: OpcodeVecF32x4NegName, body: v2v(OpcodeVecF32x4Neg)},
  3057  		{name: OpcodeVecF64x2NegName, body: v2v(OpcodeVecF64x2Neg)},
  3058  		{name: OpcodeVecF32x4SqrtName, body: v2v(OpcodeVecF32x4Sqrt)},
  3059  		{name: OpcodeVecF64x2SqrtName, body: v2v(OpcodeVecF64x2Sqrt)},
  3060  		{name: OpcodeVecI8x16MinSName, body: vv2v(OpcodeVecI8x16MinS)},
  3061  		{name: OpcodeVecI8x16MinUName, body: vv2v(OpcodeVecI8x16MinU)},
  3062  		{name: OpcodeVecI8x16MaxSName, body: vv2v(OpcodeVecI8x16MaxS)},
  3063  		{name: OpcodeVecI8x16MaxUName, body: vv2v(OpcodeVecI8x16MaxU)},
  3064  		{name: OpcodeVecI8x16AvgrUName, body: vv2v(OpcodeVecI8x16AvgrU)},
  3065  		{name: OpcodeVecI8x16AbsName, body: v2v(OpcodeVecI8x16Abs)},
  3066  		{name: OpcodeVecI8x16PopcntName, body: v2v(OpcodeVecI8x16Popcnt)},
  3067  		{name: OpcodeVecI16x8MinSName, body: vv2v(OpcodeVecI16x8MinS)},
  3068  		{name: OpcodeVecI16x8MinUName, body: vv2v(OpcodeVecI16x8MinU)},
  3069  		{name: OpcodeVecI16x8MaxSName, body: vv2v(OpcodeVecI16x8MaxS)},
  3070  		{name: OpcodeVecI16x8MaxUName, body: vv2v(OpcodeVecI16x8MaxU)},
  3071  		{name: OpcodeVecI16x8AvgrUName, body: vv2v(OpcodeVecI16x8AvgrU)},
  3072  		{name: OpcodeVecI16x8AbsName, body: v2v(OpcodeVecI16x8Abs)},
  3073  		{name: OpcodeVecI32x4MinSName, body: vv2v(OpcodeVecI32x4MinS)},
  3074  		{name: OpcodeVecI32x4MinUName, body: vv2v(OpcodeVecI32x4MinU)},
  3075  		{name: OpcodeVecI32x4MaxSName, body: vv2v(OpcodeVecI32x4MaxS)},
  3076  		{name: OpcodeVecI32x4MaxUName, body: vv2v(OpcodeVecI32x4MaxU)},
  3077  		{name: OpcodeVecI32x4AbsName, body: v2v(OpcodeVecI32x4Abs)},
  3078  		{name: OpcodeVecI64x2AbsName, body: v2v(OpcodeVecI64x2Abs)},
  3079  		{name: OpcodeVecF32x4AbsName, body: v2v(OpcodeVecF32x4Abs)},
  3080  		{name: OpcodeVecF64x2AbsName, body: v2v(OpcodeVecF64x2Abs)},
  3081  		{name: OpcodeVecF32x4MinName, body: vv2v(OpcodeVecF32x4Min)},
  3082  		{name: OpcodeVecF32x4MaxName, body: vv2v(OpcodeVecF32x4Max)},
  3083  		{name: OpcodeVecF64x2MinName, body: vv2v(OpcodeVecF64x2Min)},
  3084  		{name: OpcodeVecF64x2MaxName, body: vv2v(OpcodeVecF64x2Max)},
  3085  		{name: OpcodeVecF32x4CeilName, body: v2v(OpcodeVecF32x4Ceil)},
  3086  		{name: OpcodeVecF32x4FloorName, body: v2v(OpcodeVecF32x4Floor)},
  3087  		{name: OpcodeVecF32x4TruncName, body: v2v(OpcodeVecF32x4Trunc)},
  3088  		{name: OpcodeVecF32x4NearestName, body: v2v(OpcodeVecF32x4Nearest)},
  3089  		{name: OpcodeVecF64x2CeilName, body: v2v(OpcodeVecF64x2Ceil)},
  3090  		{name: OpcodeVecF64x2FloorName, body: v2v(OpcodeVecF64x2Floor)},
  3091  		{name: OpcodeVecF64x2TruncName, body: v2v(OpcodeVecF64x2Trunc)},
  3092  		{name: OpcodeVecF64x2NearestName, body: v2v(OpcodeVecF64x2Nearest)},
  3093  		{name: OpcodeVecF32x4MinName, body: vv2v(OpcodeVecF32x4Pmin)},
  3094  		{name: OpcodeVecF32x4MaxName, body: vv2v(OpcodeVecF32x4Pmax)},
  3095  		{name: OpcodeVecF64x2MinName, body: vv2v(OpcodeVecF64x2Pmin)},
  3096  		{name: OpcodeVecF64x2MaxName, body: vv2v(OpcodeVecF64x2Pmax)},
  3097  		{name: OpcodeVecI16x8ExtendLowI8x16SName, body: v2v(OpcodeVecI16x8ExtendLowI8x16S)},
  3098  		{name: OpcodeVecI16x8ExtendHighI8x16SName, body: v2v(OpcodeVecI16x8ExtendHighI8x16S)},
  3099  		{name: OpcodeVecI16x8ExtendLowI8x16UName, body: v2v(OpcodeVecI16x8ExtendLowI8x16U)},
  3100  		{name: OpcodeVecI16x8ExtendHighI8x16UName, body: v2v(OpcodeVecI16x8ExtendHighI8x16U)},
  3101  		{name: OpcodeVecI32x4ExtendLowI16x8SName, body: v2v(OpcodeVecI32x4ExtendLowI16x8S)},
  3102  		{name: OpcodeVecI32x4ExtendHighI16x8SName, body: v2v(OpcodeVecI32x4ExtendHighI16x8S)},
  3103  		{name: OpcodeVecI32x4ExtendLowI16x8UName, body: v2v(OpcodeVecI32x4ExtendLowI16x8U)},
  3104  		{name: OpcodeVecI32x4ExtendHighI16x8UName, body: v2v(OpcodeVecI32x4ExtendHighI16x8U)},
  3105  		{name: OpcodeVecI64x2ExtendLowI32x4SName, body: v2v(OpcodeVecI64x2ExtendLowI32x4S)},
  3106  		{name: OpcodeVecI64x2ExtendHighI32x4SName, body: v2v(OpcodeVecI64x2ExtendHighI32x4S)},
  3107  		{name: OpcodeVecI64x2ExtendLowI32x4UName, body: v2v(OpcodeVecI64x2ExtendLowI32x4U)},
  3108  		{name: OpcodeVecI64x2ExtendHighI32x4UName, body: v2v(OpcodeVecI64x2ExtendHighI32x4U)},
  3109  		{name: OpcodeVecI16x8Q15mulrSatSName, body: vv2v(OpcodeVecI16x8Q15mulrSatS)},
  3110  		{name: OpcodeVecI16x8ExtMulLowI8x16SName, body: vv2v(OpcodeVecI16x8ExtMulLowI8x16S)},
  3111  		{name: OpcodeVecI16x8ExtMulHighI8x16SName, body: vv2v(OpcodeVecI16x8ExtMulHighI8x16S)},
  3112  		{name: OpcodeVecI16x8ExtMulLowI8x16UName, body: vv2v(OpcodeVecI16x8ExtMulLowI8x16U)},
  3113  		{name: OpcodeVecI16x8ExtMulHighI8x16UName, body: vv2v(OpcodeVecI16x8ExtMulHighI8x16U)},
  3114  		{name: OpcodeVecI32x4ExtMulLowI16x8SName, body: vv2v(OpcodeVecI32x4ExtMulLowI16x8S)},
  3115  		{name: OpcodeVecI32x4ExtMulHighI16x8SName, body: vv2v(OpcodeVecI32x4ExtMulHighI16x8S)},
  3116  		{name: OpcodeVecI32x4ExtMulLowI16x8UName, body: vv2v(OpcodeVecI32x4ExtMulLowI16x8U)},
  3117  		{name: OpcodeVecI32x4ExtMulHighI16x8UName, body: vv2v(OpcodeVecI32x4ExtMulHighI16x8U)},
  3118  		{name: OpcodeVecI64x2ExtMulLowI32x4SName, body: vv2v(OpcodeVecI64x2ExtMulLowI32x4S)},
  3119  		{name: OpcodeVecI64x2ExtMulHighI32x4SName, body: vv2v(OpcodeVecI64x2ExtMulHighI32x4S)},
  3120  		{name: OpcodeVecI64x2ExtMulLowI32x4UName, body: vv2v(OpcodeVecI64x2ExtMulLowI32x4U)},
  3121  		{name: OpcodeVecI64x2ExtMulHighI32x4UName, body: vv2v(OpcodeVecI64x2ExtMulHighI32x4U)},
  3122  		{name: OpcodeVecI16x8ExtaddPairwiseI8x16SName, body: v2v(OpcodeVecI16x8ExtaddPairwiseI8x16S)},
  3123  		{name: OpcodeVecI16x8ExtaddPairwiseI8x16UName, body: v2v(OpcodeVecI16x8ExtaddPairwiseI8x16U)},
  3124  		{name: OpcodeVecI32x4ExtaddPairwiseI16x8SName, body: v2v(OpcodeVecI32x4ExtaddPairwiseI16x8S)},
  3125  		{name: OpcodeVecI32x4ExtaddPairwiseI16x8UName, body: v2v(OpcodeVecI32x4ExtaddPairwiseI16x8U)},
  3126  		{name: OpcodeVecF64x2PromoteLowF32x4ZeroName, body: v2v(OpcodeVecF64x2PromoteLowF32x4Zero)},
  3127  		{name: OpcodeVecF32x4DemoteF64x2ZeroName, body: v2v(OpcodeVecF32x4DemoteF64x2Zero)},
  3128  		{name: OpcodeVecF32x4ConvertI32x4SName, body: v2v(OpcodeVecF32x4ConvertI32x4S)},
  3129  		{name: OpcodeVecF32x4ConvertI32x4UName, body: v2v(OpcodeVecF32x4ConvertI32x4U)},
  3130  		{name: OpcodeVecF64x2ConvertLowI32x4SName, body: v2v(OpcodeVecF64x2ConvertLowI32x4S)},
  3131  		{name: OpcodeVecF64x2ConvertLowI32x4UName, body: v2v(OpcodeVecF64x2ConvertLowI32x4U)},
  3132  		{name: OpcodeVecI32x4DotI16x8SName, body: vv2v(OpcodeVecI32x4DotI16x8S)},
  3133  		{name: OpcodeVecI8x16NarrowI16x8SName, body: vv2v(OpcodeVecI8x16NarrowI16x8S)},
  3134  		{name: OpcodeVecI8x16NarrowI16x8UName, body: vv2v(OpcodeVecI8x16NarrowI16x8U)},
  3135  		{name: OpcodeVecI16x8NarrowI32x4SName, body: vv2v(OpcodeVecI16x8NarrowI32x4S)},
  3136  		{name: OpcodeVecI16x8NarrowI32x4UName, body: vv2v(OpcodeVecI16x8NarrowI32x4U)},
  3137  		{name: OpcodeVecI32x4TruncSatF32x4SName, body: v2v(OpcodeVecI32x4TruncSatF32x4S)},
  3138  		{name: OpcodeVecI32x4TruncSatF32x4UName, body: v2v(OpcodeVecI32x4TruncSatF32x4U)},
  3139  		{name: OpcodeVecI32x4TruncSatF64x2SZeroName, body: v2v(OpcodeVecI32x4TruncSatF64x2SZero)},
  3140  		{name: OpcodeVecI32x4TruncSatF64x2UZeroName, body: v2v(OpcodeVecI32x4TruncSatF64x2UZero)},
  3141  	}
  3142  
  3143  	for _, tt := range tests {
  3144  		tc := tt
  3145  		t.Run(tc.name, func(t *testing.T) {
  3146  			m := &Module{
  3147  				TypeSection:     []*FunctionType{v_v},
  3148  				FunctionSection: []Index{0},
  3149  				CodeSection:     []*Code{{Body: tc.body}},
  3150  			}
  3151  			err := m.validateFunction(api.CoreFeatureSIMD, 0, []Index{0}, nil, &Memory{}, nil, nil)
  3152  			require.NoError(t, err)
  3153  		})
  3154  	}
  3155  }
  3156  
  3157  func TestModule_funcValidation_SIMD_error(t *testing.T) {
  3158  	type testCase struct {
  3159  		name        string
  3160  		body        []byte
  3161  		flag        api.CoreFeatures
  3162  		expectedErr string
  3163  	}
  3164  
  3165  	tests := []testCase{
  3166  		{
  3167  			name: "simd disabled",
  3168  			body: []byte{
  3169  				OpcodeVecPrefix,
  3170  				OpcodeVecF32x4Abs,
  3171  			},
  3172  			flag:        api.CoreFeaturesV1,
  3173  			expectedErr: "f32x4.abs invalid as feature \"simd\" is disabled",
  3174  		},
  3175  		{
  3176  			name: "v128.const immediate",
  3177  			body: []byte{
  3178  				OpcodeVecPrefix,
  3179  				OpcodeVecV128Const,
  3180  				1, 1, 1, 1, 1, 1, 1, 1,
  3181  				1, 1, 1, 1, 1, 1, 1,
  3182  			},
  3183  			flag:        api.CoreFeatureSIMD,
  3184  			expectedErr: "cannot read constant vector value for v128.const",
  3185  		},
  3186  		{
  3187  			name: "i32x4.add operand",
  3188  			body: []byte{
  3189  				OpcodeVecPrefix,
  3190  				OpcodeVecV128Const,
  3191  				1, 1, 1, 1, 1, 1, 1, 1,
  3192  				1, 1, 1, 1, 1, 1, 1, 1,
  3193  				OpcodeVecPrefix,
  3194  				OpcodeVecI32x4Add,
  3195  				OpcodeDrop,
  3196  				OpcodeEnd,
  3197  			},
  3198  			flag:        api.CoreFeatureSIMD,
  3199  			expectedErr: "cannot pop the operand for i32x4.add: v128 missing",
  3200  		},
  3201  		{
  3202  			name: "i64x2.add operand",
  3203  			body: []byte{
  3204  				OpcodeVecPrefix,
  3205  				OpcodeVecV128Const,
  3206  				1, 1, 1, 1, 1, 1, 1, 1,
  3207  				1, 1, 1, 1, 1, 1, 1, 1,
  3208  				OpcodeVecPrefix,
  3209  				OpcodeVecI64x2Add,
  3210  				OpcodeDrop,
  3211  				OpcodeEnd,
  3212  			},
  3213  			flag:        api.CoreFeatureSIMD,
  3214  			expectedErr: "cannot pop the operand for i64x2.add: v128 missing",
  3215  		},
  3216  		{
  3217  			name: "shuffle lane index not found",
  3218  			flag: api.CoreFeatureSIMD,
  3219  			body: []byte{
  3220  				OpcodeVecPrefix,
  3221  				OpcodeVecV128i8x16Shuffle,
  3222  			},
  3223  			expectedErr: "16 lane indexes for v128.shuffle not found",
  3224  		},
  3225  		{
  3226  			name: "shuffle lane index not found",
  3227  			flag: api.CoreFeatureSIMD,
  3228  			body: []byte{
  3229  				OpcodeVecPrefix,
  3230  				OpcodeVecV128i8x16Shuffle,
  3231  				0xff, 0, 0, 0, 0, 0, 0, 0,
  3232  				0, 0, 0, 0, 0, 0, 0, 0,
  3233  			},
  3234  			expectedErr: "invalid lane index[0] 255 >= 32 for v128.shuffle",
  3235  		},
  3236  	}
  3237  
  3238  	addExtractOrReplaceLaneOutOfIndexCase := func(op OpcodeVec, lane, laneCeil byte) {
  3239  		n := VectorInstructionName(op)
  3240  		tests = append(tests, testCase{
  3241  			name: n + "/lane index out of range",
  3242  			flag: api.CoreFeatureSIMD,
  3243  			body: []byte{
  3244  				OpcodeVecPrefix, op, lane,
  3245  			},
  3246  			expectedErr: fmt.Sprintf("invalid lane index %d >= %d for %s", lane, laneCeil, n),
  3247  		})
  3248  	}
  3249  
  3250  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ExtractLaneS, 16, 16)
  3251  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ExtractLaneU, 20, 16)
  3252  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ExtractLaneS, 8, 8)
  3253  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ExtractLaneU, 8, 8)
  3254  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI32x4ExtractLane, 4, 4)
  3255  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF32x4ExtractLane, 4, 4)
  3256  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI64x2ExtractLane, 2, 2)
  3257  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF64x2ExtractLane, 2, 2)
  3258  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI8x16ReplaceLane, 16, 16)
  3259  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI16x8ReplaceLane, 8, 8)
  3260  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI32x4ReplaceLane, 4, 4)
  3261  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecI64x2ReplaceLane, 2, 2)
  3262  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF32x4ReplaceLane, 10, 4)
  3263  	addExtractOrReplaceLaneOutOfIndexCase(OpcodeVecF64x2ReplaceLane, 3, 2)
  3264  
  3265  	addStoreOrLoadLaneOutOfIndexCase := func(op OpcodeVec, lane, laneCeil byte) {
  3266  		n := VectorInstructionName(op)
  3267  		tests = append(tests, testCase{
  3268  			name: n + "/lane index out of range",
  3269  			flag: api.CoreFeatureSIMD,
  3270  			body: []byte{
  3271  				OpcodeVecPrefix, op,
  3272  				0, 0, // align and offset.
  3273  				lane,
  3274  			},
  3275  			expectedErr: fmt.Sprintf("invalid lane index %d >= %d for %s", lane, laneCeil, n),
  3276  		})
  3277  	}
  3278  
  3279  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load8Lane, 16, 16)
  3280  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load16Lane, 8, 8)
  3281  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load32Lane, 4, 4)
  3282  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Load64Lane, 2, 2)
  3283  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store8Lane, 16, 16)
  3284  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store16Lane, 8, 8)
  3285  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store32Lane, 4, 4)
  3286  	addStoreOrLoadLaneOutOfIndexCase(OpcodeVecV128Store64Lane, 2, 2)
  3287  
  3288  	for _, tt := range tests {
  3289  		tc := tt
  3290  		t.Run(tc.name, func(t *testing.T) {
  3291  			m := &Module{
  3292  				TypeSection:     []*FunctionType{v_v},
  3293  				FunctionSection: []Index{0},
  3294  				CodeSection:     []*Code{{Body: tc.body}},
  3295  			}
  3296  			err := m.validateFunction(tc.flag, 0, []Index{0}, nil, &Memory{}, nil, nil)
  3297  			require.EqualError(t, err, tc.expectedErr)
  3298  		})
  3299  	}
  3300  }
  3301  
  3302  func TestDecodeBlockType(t *testing.T) {
  3303  	t.Run("primitive", func(t *testing.T) {
  3304  		for _, tc := range []struct {
  3305  			name                 string
  3306  			in                   byte
  3307  			exp                  ValueType
  3308  			expResultNumInUint64 int
  3309  		}{
  3310  			{name: "nil", in: 0x40},
  3311  			{name: "i32", in: 0x7f, exp: ValueTypeI32, expResultNumInUint64: 1},
  3312  			{name: "i64", in: 0x7e, exp: ValueTypeI64, expResultNumInUint64: 1},
  3313  			{name: "f32", in: 0x7d, exp: ValueTypeF32, expResultNumInUint64: 1},
  3314  			{name: "f64", in: 0x7c, exp: ValueTypeF64, expResultNumInUint64: 1},
  3315  			{name: "v128", in: 0x7b, exp: ValueTypeV128, expResultNumInUint64: 2},
  3316  			{name: "funcref", in: 0x70, exp: ValueTypeFuncref, expResultNumInUint64: 1},
  3317  			{name: "externref", in: 0x6f, exp: ValueTypeExternref, expResultNumInUint64: 1},
  3318  		} {
  3319  			tc := tc
  3320  			t.Run(tc.name, func(t *testing.T) {
  3321  				actual, read, err := DecodeBlockType(nil, bytes.NewReader([]byte{tc.in}), api.CoreFeaturesV2)
  3322  				require.NoError(t, err)
  3323  				require.Equal(t, uint64(1), read)
  3324  				require.Equal(t, 0, len(actual.Params))
  3325  				require.Equal(t, tc.expResultNumInUint64, actual.ResultNumInUint64)
  3326  				require.Equal(t, 0, actual.ParamNumInUint64)
  3327  				if tc.exp == 0 {
  3328  					require.Equal(t, 0, len(actual.Results))
  3329  				} else {
  3330  					require.Equal(t, 1, len(actual.Results))
  3331  					require.Equal(t, tc.exp, actual.Results[0])
  3332  				}
  3333  			})
  3334  		}
  3335  	})
  3336  	t.Run("function type", func(t *testing.T) {
  3337  		types := []*FunctionType{
  3338  			{},
  3339  			{Params: []ValueType{ValueTypeI32}},
  3340  			{Results: []ValueType{ValueTypeI32}},
  3341  			{Params: []ValueType{ValueTypeF32, ValueTypeV128}, Results: []ValueType{ValueTypeI32}},
  3342  			{Params: []ValueType{ValueTypeF32, ValueTypeV128}, Results: []ValueType{ValueTypeI32, ValueTypeF32, ValueTypeV128}},
  3343  		}
  3344  		for index, expected := range types {
  3345  			actual, read, err := DecodeBlockType(types, bytes.NewReader([]byte{byte(index)}), api.CoreFeatureMultiValue)
  3346  			require.NoError(t, err)
  3347  			require.Equal(t, uint64(1), read)
  3348  			require.Equal(t, expected, actual)
  3349  		}
  3350  	})
  3351  }
  3352  
  3353  // TestFuncValidation_UnreachableBrTable_NotModifyTypes ensures that we do not modify the
  3354  // original function type during the function validation with the presence of unreachable br_table
  3355  // targeting the function return label.
  3356  func TestFuncValidation_UnreachableBrTable_NotModifyTypes(t *testing.T) {
  3357  	funcType := &FunctionType{Results: []ValueType{i32, i64}, Params: []ValueType{i32}}
  3358  	copiedFuncType := &FunctionType{
  3359  		Params:  make([]ValueType, len(funcType.Params)),
  3360  		Results: make([]ValueType, len(funcType.Results)),
  3361  	}
  3362  
  3363  	copy(copiedFuncType.Results, funcType.Results)
  3364  	copy(copiedFuncType.Params, funcType.Params)
  3365  
  3366  	for _, tc := range []struct {
  3367  		name string
  3368  		m    *Module
  3369  	}{
  3370  		{
  3371  			name: "on function return",
  3372  			m: &Module{
  3373  				TypeSection:     []*FunctionType{funcType},
  3374  				FunctionSection: []Index{0},
  3375  				CodeSection: []*Code{
  3376  					{Body: []byte{
  3377  						OpcodeUnreachable,
  3378  						// Having br_table in unreachable state.
  3379  						OpcodeI32Const, 1,
  3380  						// Setting the destination as labels of index 0 which
  3381  						// is the function return.
  3382  						OpcodeBrTable, 2, 0, 0, 0,
  3383  						OpcodeEnd,
  3384  					}},
  3385  				},
  3386  			},
  3387  		},
  3388  		{
  3389  			name: "on loop return",
  3390  			m: &Module{
  3391  				TypeSection:     []*FunctionType{funcType},
  3392  				FunctionSection: []Index{0},
  3393  				CodeSection: []*Code{
  3394  					{Body: []byte{
  3395  						OpcodeUnreachable,
  3396  						OpcodeLoop, 0, // indicates that loop has funcType as its block type
  3397  						OpcodeUnreachable,
  3398  						// Having br_table in unreachable state.
  3399  						OpcodeI32Const, 1,
  3400  						// Setting the destination as labels of index 0 which
  3401  						// is the loop return.
  3402  						OpcodeBrTable, 2, 0, 0, 0,
  3403  						OpcodeEnd, // End of loop
  3404  						OpcodeEnd,
  3405  					}},
  3406  				},
  3407  			},
  3408  		},
  3409  	} {
  3410  		tc := tc
  3411  		t.Run(tc.name, func(t *testing.T) {
  3412  			err := tc.m.validateFunction(api.CoreFeaturesV2, 0, nil, nil, nil, nil, nil)
  3413  			require.NoError(t, err)
  3414  
  3415  			// Ensures that funcType has remained intact.
  3416  			require.Equal(t, copiedFuncType, funcType)
  3417  		})
  3418  	}
  3419  }
  3420  
  3421  func TestModule_funcValidation_loopWithParams(t *testing.T) {
  3422  	tests := []struct {
  3423  		name   string
  3424  		body   []byte
  3425  		expErr string
  3426  	}{
  3427  		{
  3428  			name: "br",
  3429  			body: []byte{
  3430  				OpcodeI32Const, 1,
  3431  				OpcodeLoop, 1, // loop (param i32)
  3432  				OpcodeBr, 0,
  3433  				OpcodeEnd,
  3434  				OpcodeUnreachable,
  3435  				OpcodeEnd,
  3436  			},
  3437  		},
  3438  		{
  3439  			name: "br_if",
  3440  			body: []byte{
  3441  				OpcodeI32Const, 1,
  3442  				OpcodeLoop, 1, // loop (param i32)
  3443  				OpcodeI32Const, 1, // operand for br_if
  3444  				OpcodeBrIf, 0,
  3445  				OpcodeUnreachable,
  3446  				OpcodeEnd,
  3447  				OpcodeUnreachable,
  3448  				OpcodeEnd,
  3449  			},
  3450  		},
  3451  		{
  3452  			name: "br_table",
  3453  			body: []byte{
  3454  				OpcodeI32Const, 1,
  3455  				OpcodeLoop, 1, // loop (param i32)
  3456  				OpcodeI32Const, 4, // Operand for br_table.
  3457  				OpcodeBrTable, 2, 0, 0, 0, 0, // Jump into the loop header anyway.
  3458  				OpcodeEnd,
  3459  				OpcodeUnreachable,
  3460  				OpcodeEnd,
  3461  			},
  3462  		},
  3463  		{
  3464  			name: "br_table - nested",
  3465  			body: []byte{
  3466  				OpcodeI32Const, 1,
  3467  				OpcodeLoop, 1, // loop (param i32)
  3468  				OpcodeLoop, 1, // loop (param i32)
  3469  				OpcodeI32Const, 4, // Operand for br_table.
  3470  				OpcodeBrTable, 2, 0, 1, 0, // Jump into the loop header anyway.
  3471  				OpcodeEnd,
  3472  				OpcodeEnd,
  3473  				OpcodeUnreachable,
  3474  				OpcodeEnd,
  3475  			},
  3476  		},
  3477  		{
  3478  			name: "br / mismatch",
  3479  			body: []byte{
  3480  				OpcodeI32Const, 1,
  3481  				OpcodeLoop, 1, // loop (param i32)
  3482  				OpcodeDrop,
  3483  				OpcodeBr, 0, // trying to jump the loop head after dropping the value which causes the type mismatch.
  3484  				OpcodeEnd,
  3485  				OpcodeUnreachable,
  3486  				OpcodeEnd,
  3487  			},
  3488  			expErr: `not enough results in br block
  3489  	have ()
  3490  	want (i32)`,
  3491  		},
  3492  		{
  3493  			name: "br_if / mismatch",
  3494  			body: []byte{
  3495  				OpcodeI32Const, 1,
  3496  				OpcodeLoop, 1, // loop (param i32)
  3497  				// Use up the param for the br_if, therefore at the time of jumping, we don't have any param to the header.
  3498  				OpcodeBrIf, 0, // trying to jump the loop head after dropping the value which causes the type mismatch.
  3499  				OpcodeUnreachable,
  3500  				OpcodeEnd,
  3501  				OpcodeUnreachable,
  3502  				OpcodeEnd,
  3503  			},
  3504  			expErr: `not enough results in br_if block
  3505  	have ()
  3506  	want (i32)`,
  3507  		},
  3508  		{
  3509  			name: "br_table",
  3510  			body: []byte{
  3511  				OpcodeI32Const, 1,
  3512  				OpcodeLoop, 1, // loop (param i32)
  3513  				// Use up the param for the br_table, therefore at the time of jumping, we don't have any param to the header.
  3514  				OpcodeBrTable, 2, 0, 0, 0, // Jump into the loop header anyway.
  3515  				OpcodeEnd,
  3516  				OpcodeUnreachable,
  3517  				OpcodeEnd,
  3518  			},
  3519  			expErr: `not enough results in br_table block
  3520  	have ()
  3521  	want (i32)`,
  3522  		},
  3523  	}
  3524  
  3525  	for _, tt := range tests {
  3526  		tc := tt
  3527  		t.Run(tc.name, func(t *testing.T) {
  3528  			m := &Module{
  3529  				TypeSection: []*FunctionType{
  3530  					v_i32,
  3531  					i32_v,
  3532  				},
  3533  				FunctionSection: []Index{0},
  3534  				CodeSection:     []*Code{{Body: tc.body}},
  3535  			}
  3536  			err := m.validateFunction(api.CoreFeatureMultiValue, 0, []Index{0}, nil, nil, nil, nil)
  3537  			if tc.expErr != "" {
  3538  				require.EqualError(t, err, tc.expErr)
  3539  			} else {
  3540  				require.NoError(t, err)
  3541  			}
  3542  		})
  3543  	}
  3544  }