github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/integration_test/engine/adhoc_test.go (about)

     1  package adhoc
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	_ "embed"
     7  	"errors"
     8  	"fmt"
     9  	"math"
    10  	"runtime"
    11  	"strconv"
    12  	"strings"
    13  	"testing"
    14  	"time"
    15  	"unsafe"
    16  
    17  	wazero "github.com/wasilibs/wazerox"
    18  	"github.com/wasilibs/wazerox/api"
    19  	"github.com/wasilibs/wazerox/experimental"
    20  	"github.com/wasilibs/wazerox/experimental/logging"
    21  	"github.com/wasilibs/wazerox/experimental/opt"
    22  	"github.com/wasilibs/wazerox/experimental/table"
    23  	"github.com/wasilibs/wazerox/internal/leb128"
    24  	"github.com/wasilibs/wazerox/internal/platform"
    25  	"github.com/wasilibs/wazerox/internal/testing/binaryencoding"
    26  	"github.com/wasilibs/wazerox/internal/testing/proxy"
    27  	"github.com/wasilibs/wazerox/internal/testing/require"
    28  	"github.com/wasilibs/wazerox/internal/wasm"
    29  	"github.com/wasilibs/wazerox/internal/wasm/binary"
    30  	"github.com/wasilibs/wazerox/internal/wasmdebug"
    31  	"github.com/wasilibs/wazerox/internal/wasmruntime"
    32  	"github.com/wasilibs/wazerox/sys"
    33  )
    34  
    35  type testCase struct {
    36  	f          func(t *testing.T, r wazero.Runtime)
    37  	wazevoSkip bool
    38  }
    39  
    40  var tests = map[string]testCase{
    41  	"huge stack":                                                       {f: testHugeStack},
    42  	"unreachable":                                                      {f: testUnreachable},
    43  	"recursive entry":                                                  {f: testRecursiveEntry},
    44  	"host func memory":                                                 {f: testHostFuncMemory},
    45  	"host function with context parameter":                             {f: testHostFunctionContextParameter},
    46  	"host function with nested context":                                {f: testNestedGoContext},
    47  	"host function with numeric parameter":                             {f: testHostFunctionNumericParameter},
    48  	"close module with in-flight calls":                                {f: testCloseInFlight},
    49  	"multiple instantiation from same source":                          {f: testMultipleInstantiation},
    50  	"exported function that grows memory":                              {f: testMemOps},
    51  	"import functions with reference type in signature":                {f: testReftypeImports},
    52  	"overflow integer addition":                                        {f: testOverflow},
    53  	"un-signed extend global":                                          {f: testGlobalExtend},
    54  	"user-defined primitive in host func":                              {f: testUserDefinedPrimitiveHostFunc},
    55  	"ensures invocations terminate on module close":                    {f: testEnsureTerminationOnClose},
    56  	"call host function indirectly":                                    {f: callHostFunctionIndirect},
    57  	"lookup function":                                                  {f: testLookupFunction},
    58  	"memory grow in recursive call":                                    {f: testMemoryGrowInRecursiveCall},
    59  	"call":                                                             {f: testCall},
    60  	"module memory":                                                    {f: testModuleMemory},
    61  	"two indirection to host":                                          {f: testTwoIndirection},
    62  	"before listener globals":                                          {f: testBeforeListenerGlobals},
    63  	"before listener stack iterator":                                   {f: testBeforeListenerStackIterator},
    64  	"before listener stack iterator offsets":                           {f: testListenerStackIteratorOffset},
    65  	"many params many results / doubler":                               {f: testManyParamsResultsDoubler},
    66  	"many params many results / doubler / listener":                    {f: testManyParamsResultsDoublerListener},
    67  	"many params many results / call_many_consts":                      {f: testManyParamsResultsCallManyConsts},
    68  	"many params many results / call_many_consts / listener":           {f: testManyParamsResultsCallManyConstsListener},
    69  	"many params many results / swapper":                               {f: testManyParamsResultsSwapper},
    70  	"many params many results / swapper / listener":                    {f: testManyParamsResultsSwapperListener},
    71  	"many params many results / main":                                  {f: testManyParamsResultsMain},
    72  	"many params many results / main / listener":                       {f: testManyParamsResultsMainListener},
    73  	"many params many results / call_many_consts_and_pick_last_vector": {f: testManyParamsResultsCallManyConstsAndPickLastVector},
    74  	"many params many results / call_many_consts_and_pick_last_vector / listener": {f: testManyParamsResultsCallManyConstsAndPickLastVectorListener},
    75  }
    76  
    77  func TestEngineCompiler(t *testing.T) {
    78  	if !platform.CompilerSupported() {
    79  		t.Skip()
    80  	}
    81  	runAllTests(t, tests, wazero.NewRuntimeConfigCompiler().WithCloseOnContextDone(true), false)
    82  }
    83  
    84  func TestEngineInterpreter(t *testing.T) {
    85  	runAllTests(t, tests, wazero.NewRuntimeConfigInterpreter().WithCloseOnContextDone(true), false)
    86  }
    87  
    88  // testCtx is an arbitrary, non-default context. Non-nil also prevents linter errors.
    89  var testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary")
    90  
    91  const i32, i64, f32, f64, v128 = wasm.ValueTypeI32, wasm.ValueTypeI64, wasm.ValueTypeF32, wasm.ValueTypeF64, wasm.ValueTypeV128
    92  
    93  var memoryCapacityPages = uint32(2)
    94  
    95  func TestEngineWazevo(t *testing.T) {
    96  	if runtime.GOARCH != "arm64" {
    97  		t.Skip()
    98  	}
    99  	config := opt.NewRuntimeConfigOptimizingCompiler()
   100  	runAllTests(t, tests, config.WithCloseOnContextDone(true), true)
   101  }
   102  
   103  func runAllTests(t *testing.T, tests map[string]testCase, config wazero.RuntimeConfig, isWazevo bool) {
   104  	for name, tc := range tests {
   105  		name := name
   106  		tc := tc
   107  		if isWazevo && tc.wazevoSkip {
   108  			t.Logf("skipping %s because it is not supported by wazevo", name)
   109  			continue
   110  		}
   111  		t.Run(name, func(t *testing.T) {
   112  			t.Parallel()
   113  			r := wazero.NewRuntimeWithConfig(testCtx, config)
   114  			defer r.Close(testCtx)
   115  			tc.f(t, r)
   116  		})
   117  	}
   118  }
   119  
   120  var (
   121  	//go:embed testdata/unreachable.wasm
   122  	unreachableWasm []byte
   123  	//go:embed testdata/recursive.wasm
   124  	recursiveWasm []byte
   125  	//go:embed testdata/host_memory.wasm
   126  	hostMemoryWasm []byte
   127  	//go:embed testdata/hugestack.wasm
   128  	hugestackWasm []byte
   129  	//go:embed testdata/memory.wasm
   130  	memoryWasm []byte
   131  	//go:embed testdata/reftype_imports.wasm
   132  	reftypeImportsWasm []byte
   133  	//go:embed testdata/overflow.wasm
   134  	overflowWasm []byte
   135  	//go:embed testdata/global_extend.wasm
   136  	globalExtendWasm []byte
   137  	//go:embed testdata/infinite_loop.wasm
   138  	infiniteLoopWasm []byte
   139  )
   140  
   141  func testEnsureTerminationOnClose(t *testing.T, r wazero.Runtime) {
   142  	compiled, err := r.CompileModule(context.Background(), infiniteLoopWasm)
   143  	require.NoError(t, err)
   144  
   145  	newInfiniteLoopFn := func(t *testing.T) (m api.Module, infinite api.Function) {
   146  		var err error
   147  		m, err = r.InstantiateModule(context.Background(), compiled, wazero.NewModuleConfig().WithName(t.Name()))
   148  		require.NoError(t, err)
   149  		infinite = m.ExportedFunction("infinite_loop")
   150  		require.NotNil(t, infinite)
   151  		return
   152  	}
   153  
   154  	t.Run("context cancel", func(t *testing.T) {
   155  		_, infinite := newInfiniteLoopFn(t)
   156  		ctx, cancel := context.WithCancel(context.Background())
   157  		go func() {
   158  			time.Sleep(time.Second)
   159  			cancel()
   160  		}()
   161  		_, err = infinite.Call(ctx)
   162  		require.Error(t, err)
   163  		require.Contains(t, err.Error(), "module closed with context canceled")
   164  	})
   165  
   166  	t.Run("context cancel in advance", func(t *testing.T) {
   167  		_, infinite := newInfiniteLoopFn(t)
   168  		ctx, cancel := context.WithCancel(context.Background())
   169  		cancel()
   170  		_, err = infinite.Call(ctx)
   171  		require.Error(t, err)
   172  		require.Contains(t, err.Error(), "module closed with context canceled")
   173  	})
   174  
   175  	t.Run("context timeout", func(t *testing.T) {
   176  		_, infinite := newInfiniteLoopFn(t)
   177  		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   178  		defer cancel()
   179  		_, err = infinite.Call(ctx)
   180  		require.Error(t, err)
   181  		require.Contains(t, err.Error(), "module closed with context deadline exceeded")
   182  	})
   183  
   184  	t.Run("explicit close of module", func(t *testing.T) {
   185  		module, infinite := newInfiniteLoopFn(t)
   186  		go func() {
   187  			time.Sleep(time.Second)
   188  			require.NoError(t, module.CloseWithExitCode(context.Background(), 2))
   189  		}()
   190  		_, err = infinite.Call(context.Background())
   191  		require.Error(t, err)
   192  		require.Contains(t, err.Error(), "module closed with exit_code(2)")
   193  	})
   194  }
   195  
   196  func testUserDefinedPrimitiveHostFunc(t *testing.T, r wazero.Runtime) {
   197  	type u32 uint32
   198  	type u64 uint64
   199  	type f32 float32
   200  	type f64 float64
   201  
   202  	const fn = "fn"
   203  	hostCompiled, err := r.NewHostModuleBuilder("host").NewFunctionBuilder().
   204  		WithFunc(func(u1 u32, u2 u64, f1 f32, f2 f64) u64 {
   205  			return u64(u1) + u2 + u64(math.Float32bits(float32(f1))) + u64(math.Float64bits(float64(f2)))
   206  		}).Export(fn).Compile(testCtx)
   207  	require.NoError(t, err)
   208  
   209  	_, err = r.InstantiateModule(testCtx, hostCompiled, wazero.NewModuleConfig())
   210  	require.NoError(t, err)
   211  
   212  	proxyBin := proxy.NewModuleBinary("host", hostCompiled)
   213  
   214  	mod, err := r.Instantiate(testCtx, proxyBin)
   215  	require.NoError(t, err)
   216  
   217  	f := mod.ExportedFunction(fn)
   218  	require.NotNil(t, f)
   219  
   220  	const u1, u2, f1, f2 = 1, 2, float32(1234.123), 5431.123
   221  	res, err := f.Call(context.Background(), uint64(u1), uint64(u2), uint64(math.Float32bits(f1)), math.Float64bits(f2))
   222  	require.NoError(t, err)
   223  	require.Equal(t, res[0], uint64(u1)+uint64(u2)+uint64(math.Float32bits(f1))+math.Float64bits(f2))
   224  }
   225  
   226  func testReftypeImports(t *testing.T, r wazero.Runtime) {
   227  	type dog struct {
   228  		name string
   229  	}
   230  
   231  	hostObj := &dog{name: "hello"}
   232  	host, err := r.NewHostModuleBuilder("host").
   233  		NewFunctionBuilder().
   234  		WithFunc(func(ctx context.Context, externrefFromRefNull uintptr) uintptr {
   235  			require.Zero(t, externrefFromRefNull)
   236  			return uintptr(unsafe.Pointer(hostObj))
   237  		}).
   238  		Export("externref").
   239  		Instantiate(testCtx)
   240  	require.NoError(t, err)
   241  	defer func() {
   242  		require.NoError(t, host.Close(testCtx))
   243  	}()
   244  
   245  	module, err := r.Instantiate(testCtx, reftypeImportsWasm)
   246  	require.NoError(t, err)
   247  	defer func() {
   248  		require.NoError(t, module.Close(testCtx))
   249  	}()
   250  
   251  	actual, err := module.ExportedFunction("get_externref_by_host").Call(testCtx)
   252  	require.NoError(t, err)
   253  
   254  	// Verifies that the returned raw uintptr is the same as the one for the host object.
   255  	require.Equal(t, uintptr(unsafe.Pointer(hostObj)), uintptr(actual[0]))
   256  }
   257  
   258  func testHugeStack(t *testing.T, r wazero.Runtime) {
   259  	module, err := r.Instantiate(testCtx, hugestackWasm)
   260  	require.NoError(t, err)
   261  	defer func() {
   262  		require.NoError(t, module.Close(testCtx))
   263  	}()
   264  
   265  	fn := module.ExportedFunction("main")
   266  	require.NotNil(t, fn)
   267  
   268  	res, err := fn.Call(testCtx, 0, 0, 0, 0, 0, 0) // params ignored by wasm
   269  	require.NoError(t, err)
   270  
   271  	const resultNumInUint64 = 180
   272  	require.Equal(t, resultNumInUint64, len(res))
   273  	for i := uint64(1); i <= resultNumInUint64; i++ {
   274  		require.Equal(t, i, res[i-1])
   275  	}
   276  }
   277  
   278  // testOverflow ensures that adding one into the maximum integer results in the
   279  // minimum one. See #636.
   280  func testOverflow(t *testing.T, r wazero.Runtime) {
   281  	module, err := r.Instantiate(testCtx, overflowWasm)
   282  	require.NoError(t, err)
   283  	defer func() {
   284  		require.NoError(t, module.Close(testCtx))
   285  	}()
   286  
   287  	for _, name := range []string{"i32", "i64"} {
   288  		i32 := module.ExportedFunction(name)
   289  		require.NotNil(t, i32)
   290  
   291  		res, err := i32.Call(testCtx)
   292  		require.NoError(t, err)
   293  
   294  		require.Equal(t, uint64(1), res[0])
   295  	}
   296  }
   297  
   298  // testGlobalExtend ensures that un-signed extension of i32 globals must be zero extended. See #656.
   299  func testGlobalExtend(t *testing.T, r wazero.Runtime) {
   300  	module, err := r.Instantiate(testCtx, globalExtendWasm)
   301  	require.NoError(t, err)
   302  	defer func() {
   303  		require.NoError(t, module.Close(testCtx))
   304  	}()
   305  
   306  	extend := module.ExportedFunction("extend")
   307  	require.NotNil(t, extend)
   308  
   309  	res, err := extend.Call(testCtx)
   310  	require.NoError(t, err)
   311  
   312  	require.Equal(t, uint64(0xffff_ffff), res[0])
   313  }
   314  
   315  func testUnreachable(t *testing.T, r wazero.Runtime) {
   316  	callUnreachable := func() {
   317  		panic("panic in host function")
   318  	}
   319  
   320  	_, err := r.NewHostModuleBuilder("host").
   321  		NewFunctionBuilder().WithFunc(callUnreachable).Export("cause_unreachable").
   322  		Instantiate(testCtx)
   323  	require.NoError(t, err)
   324  
   325  	module, err := r.Instantiate(testCtx, unreachableWasm)
   326  	require.NoError(t, err)
   327  	defer func() {
   328  		require.NoError(t, module.Close(testCtx))
   329  	}()
   330  
   331  	_, err = module.ExportedFunction("main").Call(testCtx)
   332  	exp := `panic in host function (recovered by wazero)
   333  wasm stack trace:
   334  	host.cause_unreachable()
   335  	.two()
   336  	.one()
   337  	.main()`
   338  	require.Equal(t, exp, err.Error())
   339  }
   340  
   341  func testRecursiveEntry(t *testing.T, r wazero.Runtime) {
   342  	hostfunc := func(ctx context.Context, mod api.Module) {
   343  		_, err := mod.ExportedFunction("called_by_host_func").Call(testCtx)
   344  		require.NoError(t, err)
   345  	}
   346  
   347  	_, err := r.NewHostModuleBuilder("env").
   348  		NewFunctionBuilder().WithFunc(hostfunc).Export("host_func").
   349  		Instantiate(testCtx)
   350  	require.NoError(t, err)
   351  
   352  	module, err := r.Instantiate(testCtx, recursiveWasm)
   353  	require.NoError(t, err)
   354  	defer func() {
   355  		require.NoError(t, module.Close(testCtx))
   356  	}()
   357  
   358  	_, err = module.ExportedFunction("main").Call(testCtx, 1)
   359  	require.NoError(t, err)
   360  }
   361  
   362  // testHostFuncMemory ensures that host functions can see the callers' memory
   363  func testHostFuncMemory(t *testing.T, r wazero.Runtime) {
   364  	var memory *wasm.MemoryInstance
   365  	storeInt := func(ctx context.Context, m api.Module, offset uint32, val uint64) uint32 {
   366  		if !m.Memory().WriteUint64Le(offset, val) {
   367  			return 1
   368  		}
   369  		// sneak a reference to the memory, so we can check it later
   370  		memory = m.Memory().(*wasm.MemoryInstance)
   371  		return 0
   372  	}
   373  
   374  	host, err := r.NewHostModuleBuilder("host").
   375  		NewFunctionBuilder().WithFunc(storeInt).Export("store_int").
   376  		Instantiate(testCtx)
   377  	require.NoError(t, err)
   378  	defer func() {
   379  		require.NoError(t, host.Close(testCtx))
   380  	}()
   381  
   382  	module, err := r.Instantiate(testCtx, hostMemoryWasm)
   383  	require.NoError(t, err)
   384  	defer func() {
   385  		require.NoError(t, module.Close(testCtx))
   386  	}()
   387  
   388  	// Call store_int and ensure it didn't return an error code.
   389  	fn := module.ExportedFunction("store_int")
   390  	results, err := fn.Call(testCtx, 1, math.MaxUint64)
   391  	require.NoError(t, err)
   392  	require.Equal(t, uint64(0), results[0])
   393  
   394  	// Since offset=1 and val=math.MaxUint64, we expect to have written exactly 8 bytes, with all bits set, at index 1.
   395  	require.Equal(t, []byte{0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0}, memory.Buffer[0:10])
   396  }
   397  
   398  // testNestedGoContext ensures context is updated when a function calls another.
   399  func testNestedGoContext(t *testing.T, r wazero.Runtime) {
   400  	nestedCtx := context.WithValue(context.Background(), struct{}{}, "nested")
   401  
   402  	importedName := t.Name() + "-imported"
   403  	importingName := t.Name() + "-importing"
   404  
   405  	var importing api.Module
   406  
   407  	imported, err := r.NewHostModuleBuilder(importedName).
   408  		NewFunctionBuilder().
   409  		WithFunc(func(ctx context.Context, p uint32) uint32 {
   410  			// We expect the initial context, testCtx, to be overwritten by "outer" when it called this.
   411  			require.Equal(t, nestedCtx, ctx)
   412  			return p + 1
   413  		}).
   414  		Export("inner").
   415  		NewFunctionBuilder().
   416  		WithFunc(func(ctx context.Context, module api.Module, p uint32) uint32 {
   417  			require.Equal(t, testCtx, ctx)
   418  			results, err := module.ExportedFunction("inner").Call(nestedCtx, uint64(p))
   419  			require.NoError(t, err)
   420  			return uint32(results[0]) + 1
   421  		}).
   422  		Export("outer").
   423  		Instantiate(testCtx)
   424  	require.NoError(t, err)
   425  	defer func() {
   426  		require.NoError(t, imported.Close(testCtx))
   427  	}()
   428  
   429  	// Instantiate a module that uses Wasm code to call the host function.
   430  	importing, err = r.Instantiate(testCtx, callOuterInnerWasm(t, importedName, importingName))
   431  	require.NoError(t, err)
   432  	defer func() {
   433  		require.NoError(t, importing.Close(testCtx))
   434  	}()
   435  
   436  	input := uint64(math.MaxUint32 - 2) // We expect two calls where each increment by one.
   437  	results, err := importing.ExportedFunction("call->outer").Call(testCtx, input)
   438  	require.NoError(t, err)
   439  	require.Equal(t, uint64(math.MaxUint32), results[0])
   440  }
   441  
   442  // testHostFunctionContextParameter ensures arg0 is optionally a context.
   443  func testHostFunctionContextParameter(t *testing.T, r wazero.Runtime) {
   444  	importedName := t.Name() + "-imported"
   445  	importingName := t.Name() + "-importing"
   446  
   447  	var importing api.Module
   448  	fns := map[string]interface{}{
   449  		"ctx": func(ctx context.Context, p uint32) uint32 {
   450  			require.Equal(t, testCtx, ctx)
   451  			return p + 1
   452  		},
   453  		"ctx mod": func(ctx context.Context, module api.Module, p uint32) uint32 {
   454  			require.Equal(t, importing, module)
   455  			return p + 1
   456  		},
   457  	}
   458  
   459  	for test := range fns {
   460  		t.Run(test, func(t *testing.T) {
   461  			imported, err := r.NewHostModuleBuilder(importedName).
   462  				NewFunctionBuilder().WithFunc(fns[test]).Export("return_input").
   463  				Instantiate(testCtx)
   464  			require.NoError(t, err)
   465  			defer func() {
   466  				require.NoError(t, imported.Close(testCtx))
   467  			}()
   468  
   469  			// Instantiate a module that uses Wasm code to call the host function.
   470  			importing, err = r.Instantiate(testCtx,
   471  				callReturnImportWasm(t, importedName, importingName, i32))
   472  			require.NoError(t, err)
   473  			defer func() {
   474  				require.NoError(t, importing.Close(testCtx))
   475  			}()
   476  
   477  			results, err := importing.ExportedFunction("call_return_input").Call(testCtx, math.MaxUint32-1)
   478  			require.NoError(t, err)
   479  			require.Equal(t, uint64(math.MaxUint32), results[0])
   480  		})
   481  	}
   482  }
   483  
   484  // testHostFunctionNumericParameter ensures numeric parameters aren't corrupted
   485  func testHostFunctionNumericParameter(t *testing.T, r wazero.Runtime) {
   486  	importedName := t.Name() + "-imported"
   487  	importingName := t.Name() + "-importing"
   488  
   489  	fns := map[string]interface{}{
   490  		"i32": func(ctx context.Context, p uint32) uint32 {
   491  			return p + 1
   492  		},
   493  		"i64": func(ctx context.Context, p uint64) uint64 {
   494  			return p + 1
   495  		},
   496  		"f32": func(ctx context.Context, p float32) float32 {
   497  			return p + 1
   498  		},
   499  		"f64": func(ctx context.Context, p float64) float64 {
   500  			return p + 1
   501  		},
   502  	}
   503  
   504  	for _, test := range []struct {
   505  		name            string
   506  		vt              wasm.ValueType
   507  		input, expected uint64
   508  	}{
   509  		{
   510  			name:     "i32",
   511  			vt:       i32,
   512  			input:    math.MaxUint32 - 1,
   513  			expected: math.MaxUint32,
   514  		},
   515  		{
   516  			name:     "i64",
   517  			vt:       i64,
   518  			input:    math.MaxUint64 - 1,
   519  			expected: math.MaxUint64,
   520  		},
   521  		{
   522  			name:     "f32",
   523  			vt:       wasm.ValueTypeF32,
   524  			input:    api.EncodeF32(math.MaxFloat32 - 1),
   525  			expected: api.EncodeF32(math.MaxFloat32),
   526  		},
   527  		{
   528  			name:     "f64",
   529  			vt:       wasm.ValueTypeF64,
   530  			input:    api.EncodeF64(math.MaxFloat64 - 1),
   531  			expected: api.EncodeF64(math.MaxFloat64),
   532  		},
   533  	} {
   534  		t.Run(test.name, func(t *testing.T) {
   535  			imported, err := r.NewHostModuleBuilder(importedName).
   536  				NewFunctionBuilder().WithFunc(fns[test.name]).Export("return_input").
   537  				Instantiate(testCtx)
   538  			require.NoError(t, err)
   539  			defer func() {
   540  				require.NoError(t, imported.Close(testCtx))
   541  			}()
   542  
   543  			// Instantiate a module that uses Wasm code to call the host function.
   544  			importing, err := r.Instantiate(testCtx,
   545  				callReturnImportWasm(t, importedName, importingName, test.vt))
   546  			require.NoError(t, err)
   547  			defer func() {
   548  				require.NoError(t, importing.Close(testCtx))
   549  			}()
   550  
   551  			results, err := importing.ExportedFunction("call_return_input").Call(testCtx, test.input)
   552  			require.NoError(t, err)
   553  			require.Equal(t, test.expected, results[0])
   554  		})
   555  	}
   556  }
   557  
   558  func callHostFunctionIndirect(t *testing.T, r wazero.Runtime) {
   559  	// With the following call graph,
   560  	//  originWasmModule -- call --> importingWasmModule -- call --> hostModule
   561  	// this ensures that hostModule's hostFn only has access importingWasmModule, not originWasmModule.
   562  
   563  	const hostModule, importingWasmModule, originWasmModule = "host", "importing", "origin"
   564  	const hostFn, importingWasmModuleFn, originModuleFn = "host_fn", "call_host_func", "origin"
   565  	importingModule := &wasm.Module{
   566  		TypeSection:     []wasm.FunctionType{{Params: []wasm.ValueType{}, Results: []wasm.ValueType{}}},
   567  		ImportSection:   []wasm.Import{{Module: hostModule, Name: hostFn, Type: wasm.ExternTypeFunc, DescFunc: 0}},
   568  		FunctionSection: []wasm.Index{0},
   569  		ExportSection:   []wasm.Export{{Name: importingWasmModuleFn, Type: wasm.ExternTypeFunc, Index: 1}},
   570  		CodeSection:     []wasm.Code{{Body: []byte{wasm.OpcodeCall, 0, wasm.OpcodeEnd}}},
   571  		NameSection:     &wasm.NameSection{ModuleName: importingWasmModule},
   572  	}
   573  
   574  	originModule := &wasm.Module{
   575  		TypeSection:     []wasm.FunctionType{{Params: []wasm.ValueType{}, Results: []wasm.ValueType{}}},
   576  		ImportSection:   []wasm.Import{{Module: importingWasmModule, Name: importingWasmModuleFn, Type: wasm.ExternTypeFunc, DescFunc: 0}},
   577  		FunctionSection: []wasm.Index{0},
   578  		ExportSection:   []wasm.Export{{Name: "origin", Type: wasm.ExternTypeFunc, Index: 1}},
   579  		CodeSection:     []wasm.Code{{Body: []byte{wasm.OpcodeCall, 0, wasm.OpcodeEnd}}},
   580  		NameSection:     &wasm.NameSection{ModuleName: originWasmModule},
   581  	}
   582  
   583  	require.NoError(t, importingModule.Validate(api.CoreFeaturesV2))
   584  	require.NoError(t, originModule.Validate(api.CoreFeaturesV2))
   585  	importingModuleBytes := binaryencoding.EncodeModule(importingModule)
   586  	originModuleBytes := binaryencoding.EncodeModule(originModule)
   587  
   588  	var originInst, importingInst api.Module
   589  	_, err := r.NewHostModuleBuilder(hostModule).
   590  		NewFunctionBuilder().
   591  		WithFunc(func(ctx context.Context, mod api.Module) {
   592  			// Module must be the caller (importing module), not the origin.
   593  			require.Equal(t, mod, importingInst)
   594  			require.NotEqual(t, mod, originInst)
   595  			// Name must be the caller, not origin.
   596  			require.Equal(t, importingWasmModule, mod.Name())
   597  		}).
   598  		Export(hostFn).
   599  		Instantiate(testCtx)
   600  	require.NoError(t, err)
   601  
   602  	importingInst, err = r.Instantiate(testCtx, importingModuleBytes)
   603  	require.NoError(t, err)
   604  	originInst, err = r.Instantiate(testCtx, originModuleBytes)
   605  	require.NoError(t, err)
   606  
   607  	originFn := originInst.ExportedFunction(originModuleFn)
   608  	require.NotNil(t, originFn)
   609  
   610  	_, err = originFn.Call(testCtx)
   611  	require.NoError(t, err)
   612  }
   613  
   614  func callReturnImportWasm(t *testing.T, importedModule, importingModule string, vt wasm.ValueType) []byte {
   615  	// test an imported function by re-exporting it
   616  	module := &wasm.Module{
   617  		TypeSection: []wasm.FunctionType{{Params: []wasm.ValueType{vt}, Results: []wasm.ValueType{vt}}},
   618  		// (import "%[2]s" "return_input" (func $return_input (param i32) (result i32)))
   619  		ImportSection: []wasm.Import{
   620  			{Module: importedModule, Name: "return_input", Type: wasm.ExternTypeFunc, DescFunc: 0},
   621  		},
   622  		FunctionSection: []wasm.Index{0},
   623  		ExportSection: []wasm.Export{
   624  			// (export "return_input" (func $return_input))
   625  			{Name: "return_input", Type: wasm.ExternTypeFunc, Index: 0},
   626  			// (export "call_return_input" (func $call_return_input))
   627  			{Name: "call_return_input", Type: wasm.ExternTypeFunc, Index: 1},
   628  		},
   629  		// (func $call_return_input (param i32) (result i32) local.get 0 call $return_input)
   630  		CodeSection: []wasm.Code{
   631  			{Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeCall, 0, wasm.OpcodeEnd}},
   632  		},
   633  		NameSection: &wasm.NameSection{
   634  			ModuleName: importingModule,
   635  			FunctionNames: wasm.NameMap{
   636  				{Index: 0, Name: "return_input"},
   637  				{Index: 1, Name: "call_return_input"},
   638  			},
   639  		},
   640  	}
   641  	require.NoError(t, module.Validate(api.CoreFeaturesV2))
   642  	return binaryencoding.EncodeModule(module)
   643  }
   644  
   645  func callOuterInnerWasm(t *testing.T, importedModule, importingModule string) []byte {
   646  	module := &wasm.Module{
   647  		TypeSection: []wasm.FunctionType{{Params: []wasm.ValueType{i32}, Results: []wasm.ValueType{i32}}},
   648  		// (import "%[2]s" "outer" (func $outer (param i32) (result i32)))
   649  		// (import "%[2]s" "inner" (func $inner (param i32) (result i32)))
   650  		ImportSection: []wasm.Import{
   651  			{Module: importedModule, Name: "outer", Type: wasm.ExternTypeFunc, DescFunc: 0},
   652  			{Module: importedModule, Name: "inner", Type: wasm.ExternTypeFunc, DescFunc: 0},
   653  		},
   654  		FunctionSection: []wasm.Index{0, 0},
   655  		ExportSection: []wasm.Export{
   656  			// (export "call->outer" (func $call_outer))
   657  			{Name: "call->outer", Type: wasm.ExternTypeFunc, Index: 2},
   658  			// 	(export "inner" (func $call_inner))
   659  			{Name: "inner", Type: wasm.ExternTypeFunc, Index: 3},
   660  		},
   661  		CodeSection: []wasm.Code{
   662  			// (func $call_outer (param i32) (result i32) local.get 0 call $outer)
   663  			{Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeCall, 0, wasm.OpcodeEnd}},
   664  			// (func $call_inner (param i32) (result i32) local.get 0 call $inner)
   665  			{Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeCall, 1, wasm.OpcodeEnd}},
   666  		},
   667  		NameSection: &wasm.NameSection{
   668  			ModuleName: importingModule,
   669  			FunctionNames: wasm.NameMap{
   670  				{Index: 0, Name: "outer"},
   671  				{Index: 1, Name: "inner"},
   672  				{Index: 2, Name: "call_outer"},
   673  				{Index: 3, Name: "call_inner"},
   674  			},
   675  		},
   676  	}
   677  	require.NoError(t, module.Validate(api.CoreFeaturesV2))
   678  	return binaryencoding.EncodeModule(module)
   679  }
   680  
   681  func testCloseInFlight(t *testing.T, r wazero.Runtime) {
   682  	tests := []struct {
   683  		name, function                        string
   684  		closeImporting, closeImported         uint32
   685  		closeImportingCode, closeImportedCode bool
   686  	}{
   687  		{ // e.g. WASI proc_exit or AssemblyScript abort handler.
   688  			name:           "importing",
   689  			function:       "call_return_input",
   690  			closeImporting: 1,
   691  		},
   692  		// TODO: A module that re-exports a function (ex "return_input") can call it after it is closed!
   693  		{ // e.g. A function that stops the runtime.
   694  			name:           "both",
   695  			function:       "call_return_input",
   696  			closeImporting: 1,
   697  			closeImported:  2,
   698  		},
   699  		{ // e.g. WASI proc_exit or AssemblyScript abort handler.
   700  			name:              "importing",
   701  			function:          "call_return_input",
   702  			closeImporting:    1,
   703  			closeImportedCode: true,
   704  		},
   705  		{ // e.g. WASI proc_exit or AssemblyScript abort handler.
   706  			name:               "importing",
   707  			function:           "call_return_input",
   708  			closeImporting:     1,
   709  			closeImportedCode:  true,
   710  			closeImportingCode: true,
   711  		},
   712  		// TODO: A module that re-exports a function (ex "return_input") can call it after it is closed!
   713  		{ // e.g. A function that stops the runtime.
   714  			name:               "both",
   715  			function:           "call_return_input",
   716  			closeImporting:     1,
   717  			closeImported:      2,
   718  			closeImportingCode: true,
   719  		},
   720  	}
   721  	for _, tt := range tests {
   722  		tc := tt
   723  
   724  		t.Run(tc.name, func(t *testing.T) {
   725  			var importingCode, importedCode wazero.CompiledModule
   726  			var imported, importing api.Module
   727  			var err error
   728  			closeAndReturn := func(ctx context.Context, x uint32) uint32 {
   729  				if tc.closeImporting != 0 {
   730  					require.NoError(t, importing.CloseWithExitCode(ctx, tc.closeImporting))
   731  				}
   732  				if tc.closeImported != 0 {
   733  					require.NoError(t, imported.CloseWithExitCode(ctx, tc.closeImported))
   734  				}
   735  				if tc.closeImportedCode {
   736  					err = importedCode.Close(testCtx)
   737  					require.NoError(t, err)
   738  				}
   739  				if tc.closeImportingCode {
   740  					err = importingCode.Close(testCtx)
   741  					require.NoError(t, err)
   742  				}
   743  				return x
   744  			}
   745  
   746  			// Create the host module, which exports the function that closes the importing module.
   747  			importedCode, err = r.NewHostModuleBuilder(t.Name() + "-imported").
   748  				NewFunctionBuilder().WithFunc(closeAndReturn).Export("return_input").
   749  				Compile(testCtx)
   750  			require.NoError(t, err)
   751  
   752  			imported, err = r.InstantiateModule(testCtx, importedCode, wazero.NewModuleConfig())
   753  			require.NoError(t, err)
   754  			defer func() {
   755  				require.NoError(t, imported.Close(testCtx))
   756  			}()
   757  
   758  			// Import that module.
   759  			bin := callReturnImportWasm(t, imported.Name(), t.Name()+"-importing", i32)
   760  			importingCode, err = r.CompileModule(testCtx, bin)
   761  			require.NoError(t, err)
   762  
   763  			importing, err = r.InstantiateModule(testCtx, importingCode, wazero.NewModuleConfig())
   764  			require.NoError(t, err)
   765  			defer func() {
   766  				require.NoError(t, importing.Close(testCtx))
   767  			}()
   768  
   769  			var expectedErr error
   770  			if tc.closeImported != 0 && tc.closeImporting != 0 {
   771  				// When both modules are closed, importing is the better one to choose in the error message.
   772  				expectedErr = sys.NewExitError(tc.closeImporting)
   773  			} else if tc.closeImported != 0 {
   774  				expectedErr = sys.NewExitError(tc.closeImported)
   775  			} else if tc.closeImporting != 0 {
   776  				expectedErr = sys.NewExitError(tc.closeImporting)
   777  			} else {
   778  				t.Fatal("invalid test case")
   779  			}
   780  
   781  			// Functions that return after being closed should have an exit error.
   782  			_, err = importing.ExportedFunction(tc.function).Call(testCtx, 5)
   783  			require.Equal(t, expectedErr, err)
   784  		})
   785  	}
   786  }
   787  
   788  func testMemOps(t *testing.T, r wazero.Runtime) {
   789  	// Instantiate a module that manages its memory
   790  	mod, err := r.Instantiate(testCtx, memoryWasm)
   791  	require.NoError(t, err)
   792  	defer func() {
   793  		require.NoError(t, mod.Close(testCtx))
   794  	}()
   795  
   796  	// Check the export worked
   797  	require.Equal(t, mod.Memory(), mod.ExportedMemory("memory"))
   798  	memory := mod.Memory()
   799  
   800  	sizeFn, storeFn, growFn := mod.ExportedFunction("size"), mod.ExportedFunction("store"), mod.ExportedFunction("grow")
   801  
   802  	// Check the size command worked
   803  	results, err := sizeFn.Call(testCtx)
   804  	require.NoError(t, err)
   805  	require.Zero(t, results[0])
   806  	require.Zero(t, memory.Size())
   807  
   808  	// Any offset should be out of bounds error even when it is less than memory capacity(=memoryCapacityPages).
   809  	_, err = storeFn.Call(testCtx, wasm.MemoryPagesToBytesNum(memoryCapacityPages)-8)
   810  	require.Error(t, err) // Out of bounds error.
   811  
   812  	// Try to grow the memory by one page
   813  	results, err = growFn.Call(testCtx, 1)
   814  	require.NoError(t, err)
   815  	require.Zero(t, results[0]) // should succeed and return the old size in pages.
   816  
   817  	// Any offset larger than the current size should be out of bounds error even when it is less than memory capacity.
   818  	_, err = storeFn.Call(testCtx, wasm.MemoryPagesToBytesNum(memoryCapacityPages)-8)
   819  	require.Error(t, err) // Out of bounds error.
   820  
   821  	// Check the size command works!
   822  	results, err = sizeFn.Call(testCtx)
   823  	require.NoError(t, err)
   824  	require.Equal(t, uint64(1), results[0])        // 1 page
   825  	require.Equal(t, uint32(65536), memory.Size()) // 64KB
   826  
   827  	// Grow again so that the memory size matches memory capacity.
   828  	results, err = growFn.Call(testCtx, 1)
   829  	require.NoError(t, err)
   830  	require.Equal(t, uint64(1), results[0])
   831  
   832  	// Verify the size matches cap.
   833  	results, err = sizeFn.Call(testCtx)
   834  	require.NoError(t, err)
   835  	require.Equal(t, uint64(memoryCapacityPages), results[0])
   836  
   837  	// Now the store instruction at the memory capcity bound should succeed.
   838  	_, err = storeFn.Call(testCtx, wasm.MemoryPagesToBytesNum(memoryCapacityPages)-8) // i64.store needs 8 bytes from offset.
   839  	require.NoError(t, err)
   840  }
   841  
   842  func testMultipleInstantiation(t *testing.T, r wazero.Runtime) {
   843  	bin := binaryencoding.EncodeModule(&wasm.Module{
   844  		TypeSection:     []wasm.FunctionType{{}},
   845  		FunctionSection: []wasm.Index{0},
   846  		MemorySection:   &wasm.Memory{Min: 1, Cap: 1, Max: 1, IsMaxEncoded: true},
   847  		CodeSection: []wasm.Code{{
   848  			Body: []byte{
   849  				wasm.OpcodeI32Const, 1, // i32.const 1    ;; memory offset
   850  				wasm.OpcodeI64Const, 0xe8, 0x7, // i64.const 1000 ;; expected value
   851  				wasm.OpcodeI64Store, 0x3, 0x0, // i64.store
   852  				wasm.OpcodeEnd,
   853  			},
   854  		}},
   855  		ExportSection: []wasm.Export{{Name: "store"}},
   856  	})
   857  	compiled, err := r.CompileModule(testCtx, bin)
   858  	require.NoError(t, err)
   859  	defer func() {
   860  		require.NoError(t, compiled.Close(testCtx))
   861  	}()
   862  
   863  	// Instantiate multiple modules with the same source (*CompiledModule).
   864  	for i := 0; i < 100; i++ {
   865  		module, err := r.InstantiateModule(testCtx, compiled, wazero.NewModuleConfig().WithName(strconv.Itoa(i)))
   866  		require.NoError(t, err)
   867  
   868  		// Ensure that compilation cache doesn't cause race on memory instance.
   869  		before, ok := module.Memory().ReadUint64Le(1)
   870  		require.True(t, ok)
   871  		// Value must be zero as the memory must not be affected by the previously instantiated modules.
   872  		require.Zero(t, before)
   873  
   874  		f := module.ExportedFunction("store")
   875  		require.NotNil(t, f)
   876  
   877  		_, err = f.Call(testCtx)
   878  		require.NoError(t, err)
   879  
   880  		// After the call, the value must be set properly.
   881  		after, ok := module.Memory().ReadUint64Le(1)
   882  		require.True(t, ok)
   883  		require.Equal(t, uint64(1000), after)
   884  
   885  		require.NoError(t, module.Close(testCtx))
   886  	}
   887  }
   888  
   889  func testLookupFunction(t *testing.T, r wazero.Runtime) {
   890  	bin := binaryencoding.EncodeModule(&wasm.Module{
   891  		TypeSection:     []wasm.FunctionType{{Results: []wasm.ValueType{i32}}},
   892  		FunctionSection: []wasm.Index{0, 0, 0},
   893  		CodeSection: []wasm.Code{
   894  			{Body: []byte{wasm.OpcodeI32Const, 1, wasm.OpcodeEnd}},
   895  			{Body: []byte{wasm.OpcodeI32Const, 2, wasm.OpcodeEnd}},
   896  			{Body: []byte{wasm.OpcodeI32Const, 3, wasm.OpcodeEnd}},
   897  		},
   898  		TableSection: []wasm.Table{{Min: 10, Type: wasm.RefTypeFuncref}},
   899  		ElementSection: []wasm.ElementSegment{
   900  			{
   901  				OffsetExpr: wasm.ConstantExpression{
   902  					Opcode: wasm.OpcodeI32Const,
   903  					Data:   []byte{0},
   904  				},
   905  				TableIndex: 0,
   906  				Init:       []wasm.Index{2, 0},
   907  			},
   908  		},
   909  	})
   910  
   911  	inst, err := r.Instantiate(testCtx, bin)
   912  	require.NoError(t, err)
   913  
   914  	t.Run("null reference", func(t *testing.T) {
   915  		err = require.CapturePanic(func() {
   916  			table.LookupFunction(inst, 0, 3, nil, []wasm.ValueType{i32})
   917  		})
   918  		require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err)
   919  	})
   920  
   921  	t.Run("out of range", func(t *testing.T) {
   922  		err = require.CapturePanic(func() {
   923  			table.LookupFunction(inst, 0, 1000, nil, []wasm.ValueType{i32})
   924  		})
   925  		require.Equal(t, wasmruntime.ErrRuntimeInvalidTableAccess, err)
   926  	})
   927  
   928  	t.Run("type mismatch", func(t *testing.T) {
   929  		err = require.CapturePanic(func() {
   930  			table.LookupFunction(inst, 0, 0, []wasm.ValueType{i32}, nil)
   931  		})
   932  		require.Equal(t, wasmruntime.ErrRuntimeIndirectCallTypeMismatch, err)
   933  	})
   934  	t.Run("ok", func(t *testing.T) {
   935  		f2 := table.LookupFunction(inst, 0, 0, nil, []wasm.ValueType{i32})
   936  		res, err := f2.Call(testCtx)
   937  		require.NoError(t, err)
   938  		require.Equal(t, uint64(3), res[0])
   939  
   940  		f0 := table.LookupFunction(inst, 0, 1, nil, []wasm.ValueType{i32})
   941  		res, err = f0.Call(testCtx)
   942  		require.NoError(t, err)
   943  		require.Equal(t, uint64(1), res[0])
   944  	})
   945  }
   946  
   947  func testMemoryGrowInRecursiveCall(t *testing.T, r wazero.Runtime) {
   948  	const hostModuleName = "env"
   949  	const hostFnName = "grow_memory"
   950  	var growFn api.Function
   951  	hostCompiled, err := r.NewHostModuleBuilder(hostModuleName).NewFunctionBuilder().
   952  		WithFunc(func() {
   953  			// Does the recursive call into Wasm, which grows memory.
   954  			_, err := growFn.Call(testCtx)
   955  			require.NoError(t, err)
   956  		}).Export(hostFnName).Compile(testCtx)
   957  	require.NoError(t, err)
   958  
   959  	_, err = r.InstantiateModule(testCtx, hostCompiled, wazero.NewModuleConfig())
   960  	require.NoError(t, err)
   961  
   962  	bin := binaryencoding.EncodeModule(&wasm.Module{
   963  		ImportFunctionCount: 1,
   964  		TypeSection:         []wasm.FunctionType{{Params: []wasm.ValueType{}, Results: []wasm.ValueType{}}},
   965  		FunctionSection:     []wasm.Index{0, 0},
   966  		CodeSection: []wasm.Code{
   967  			{
   968  				Body: []byte{
   969  					// Calls the imported host function, which in turn calls the next in-Wasm function recursively.
   970  					wasm.OpcodeCall, 0,
   971  					// Access the memory and this should succeed as we already had memory grown at this point.
   972  					wasm.OpcodeI32Const, 0,
   973  					wasm.OpcodeI32Load, 0x2, 0x0,
   974  					wasm.OpcodeDrop,
   975  					wasm.OpcodeEnd,
   976  				},
   977  			},
   978  			{
   979  				// Grows memory by 1 page.
   980  				Body: []byte{wasm.OpcodeI32Const, 1, wasm.OpcodeMemoryGrow, 0, wasm.OpcodeDrop, wasm.OpcodeEnd},
   981  			},
   982  		},
   983  		MemorySection:   &wasm.Memory{Max: 1000},
   984  		ImportSection:   []wasm.Import{{Module: hostModuleName, Name: hostFnName, DescFunc: 0}},
   985  		ImportPerModule: map[string][]*wasm.Import{hostModuleName: {{Module: hostModuleName, Name: hostFnName, DescFunc: 0}}},
   986  		ExportSection: []wasm.Export{
   987  			{Name: "main", Type: wasm.ExternTypeFunc, Index: 1},
   988  			{Name: "grow_memory", Type: wasm.ExternTypeFunc, Index: 2},
   989  		},
   990  	})
   991  
   992  	inst, err := r.Instantiate(testCtx, bin)
   993  	require.NoError(t, err)
   994  
   995  	growFn = inst.ExportedFunction("grow_memory")
   996  	require.NotNil(t, growFn)
   997  	main := inst.ExportedFunction("main")
   998  	require.NotNil(t, main)
   999  
  1000  	_, err = main.Call(testCtx)
  1001  	require.NoError(t, err)
  1002  }
  1003  
  1004  func testCall(t *testing.T, r wazero.Runtime) {
  1005  	// Define a basic function which defines two parameters and two results.
  1006  	// This is used to test results when incorrect arity is used.
  1007  	bin := binaryencoding.EncodeModule(&wasm.Module{
  1008  		TypeSection: []wasm.FunctionType{
  1009  			{
  1010  				Params:            []wasm.ValueType{i64, i64},
  1011  				Results:           []wasm.ValueType{i64, i64},
  1012  				ParamNumInUint64:  2,
  1013  				ResultNumInUint64: 2,
  1014  			},
  1015  		},
  1016  		FunctionSection: []wasm.Index{0},
  1017  		CodeSection: []wasm.Code{
  1018  			{Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeLocalGet, 1, wasm.OpcodeEnd}},
  1019  		},
  1020  		ExportSection: []wasm.Export{{Name: "func", Type: wasm.ExternTypeFunc, Index: 0}},
  1021  	})
  1022  
  1023  	inst, err := r.Instantiate(testCtx, bin)
  1024  	require.NoError(t, err)
  1025  
  1026  	// Ensure the base case doesn't fail: A single parameter should work as that matches the function signature.
  1027  	f := inst.ExportedFunction("func")
  1028  	require.NotNil(t, f)
  1029  
  1030  	t.Run("call with stack", func(t *testing.T) {
  1031  		stack := []uint64{1, 2}
  1032  		err = f.CallWithStack(testCtx, stack)
  1033  		require.NoError(t, err)
  1034  		require.Equal(t, []uint64{1, 2}, stack)
  1035  
  1036  		t.Run("errs when not enough parameters", func(t *testing.T) {
  1037  			err = f.CallWithStack(testCtx, nil)
  1038  			require.EqualError(t, err, "need 2 params, but stack size is 0")
  1039  		})
  1040  	})
  1041  
  1042  	t.Run("errs when not enough parameters", func(t *testing.T) {
  1043  		_, err = f.Call(testCtx)
  1044  		require.EqualError(t, err, "expected 2 params, but passed 0")
  1045  	})
  1046  
  1047  	t.Run("errs when too many parameters", func(t *testing.T) {
  1048  		_, err = f.Call(testCtx, 1, 2, 3)
  1049  		require.EqualError(t, err, "expected 2 params, but passed 3")
  1050  	})
  1051  }
  1052  
  1053  // RunTestModuleEngineMemory shows that the byte slice returned from api.Memory Read is not a copy, rather a re-slice
  1054  // of the underlying memory. This allows both host and Wasm to see each other's writes, unless one side changes the
  1055  // capacity of the slice.
  1056  //
  1057  // Known cases that change the slice capacity:
  1058  // * Host code calls append on a byte slice returned by api.Memory Read
  1059  // * Wasm code calls wasm.OpcodeMemoryGrowName and this changes the capacity (by default, it will).
  1060  func testModuleMemory(t *testing.T, r wazero.Runtime) {
  1061  	wasmPhrase := "Well, that'll be the day when you say goodbye."
  1062  	wasmPhraseSize := uint32(len(wasmPhrase))
  1063  
  1064  	one := uint32(1)
  1065  
  1066  	bin := binaryencoding.EncodeModule(&wasm.Module{
  1067  		TypeSection:     []wasm.FunctionType{{Params: []api.ValueType{api.ValueTypeI32}, ParamNumInUint64: 1}, {}},
  1068  		FunctionSection: []wasm.Index{0, 1},
  1069  		MemorySection:   &wasm.Memory{Min: 1, Cap: 1, Max: 2},
  1070  		DataSection: []wasm.DataSegment{
  1071  			{
  1072  				Passive: true,
  1073  				Init:    []byte(wasmPhrase),
  1074  			},
  1075  		},
  1076  		DataCountSection: &one,
  1077  		CodeSection: []wasm.Code{
  1078  			{Body: []byte{ // "grow"
  1079  				wasm.OpcodeLocalGet, 0, // how many pages to grow (param)
  1080  				wasm.OpcodeMemoryGrow, 0, // memory index zero
  1081  				wasm.OpcodeDrop, // drop the previous page count (or -1 if grow failed)
  1082  				wasm.OpcodeEnd,
  1083  			}},
  1084  			{Body: []byte{ // "init"
  1085  				wasm.OpcodeI32Const, 0, // target offset
  1086  				wasm.OpcodeI32Const, 0, // source offset
  1087  				wasm.OpcodeI32Const, byte(wasmPhraseSize), // len
  1088  				wasm.OpcodeMiscPrefix, wasm.OpcodeMiscMemoryInit, 0, 0, // segment 0, memory 0
  1089  				wasm.OpcodeEnd,
  1090  			}},
  1091  		},
  1092  		ExportSection: []wasm.Export{
  1093  			{Name: "grow", Type: wasm.ExternTypeFunc, Index: 0},
  1094  			{Name: "init", Type: wasm.ExternTypeFunc, Index: 1},
  1095  		},
  1096  	})
  1097  
  1098  	inst, err := r.Instantiate(testCtx, bin)
  1099  	require.NoError(t, err)
  1100  
  1101  	memory := inst.Memory()
  1102  
  1103  	buf, ok := memory.Read(0, wasmPhraseSize)
  1104  	require.True(t, ok)
  1105  	require.Equal(t, make([]byte, wasmPhraseSize), buf)
  1106  
  1107  	// Initialize the memory using Wasm. This copies the test phrase.
  1108  	initCallEngine := inst.ExportedFunction("init")
  1109  	_, err = initCallEngine.Call(testCtx)
  1110  	require.NoError(t, err)
  1111  
  1112  	// We expect the same []byte read earlier to now include the phrase in wasm.
  1113  	require.Equal(t, wasmPhrase, string(buf))
  1114  
  1115  	hostPhrase := "Goodbye, cruel world. I'm off to join the circus." // Intentionally slightly longer.
  1116  	hostPhraseSize := uint32(len(hostPhrase))
  1117  
  1118  	// Copy over the buffer, which should stop at the current length.
  1119  	copy(buf, hostPhrase)
  1120  	require.Equal(t, "Goodbye, cruel world. I'm off to join the circ", string(buf))
  1121  
  1122  	// The underlying memory should be updated. This proves that Memory.Read returns a re-slice, not a copy, and that
  1123  	// programs can rely on this (for example, to update shared state in Wasm and view that in Go and visa versa).
  1124  	buf2, ok := memory.Read(0, wasmPhraseSize)
  1125  	require.True(t, ok)
  1126  	require.Equal(t, buf, buf2)
  1127  
  1128  	// Now, append to the buffer we got from Wasm. As this changes capacity, it should result in a new byte slice.
  1129  	buf = append(buf, 'u', 's', '.')
  1130  	require.Equal(t, hostPhrase, string(buf))
  1131  
  1132  	// To prove the above, we re-read the memory and should not see the appended bytes (rather zeros instead).
  1133  	buf2, ok = memory.Read(0, hostPhraseSize)
  1134  	require.True(t, ok)
  1135  	hostPhraseTruncated := "Goodbye, cruel world. I'm off to join the circ" + string([]byte{0, 0, 0})
  1136  	require.Equal(t, hostPhraseTruncated, string(buf2))
  1137  
  1138  	// Now, we need to prove the other direction, that when Wasm changes the capacity, the host's buffer is unaffected.
  1139  	growCallEngine := inst.ExportedFunction("grow")
  1140  	_, err = growCallEngine.Call(testCtx, 1)
  1141  	require.NoError(t, err)
  1142  
  1143  	// The host buffer should still contain the same bytes as before grow
  1144  	require.Equal(t, hostPhraseTruncated, string(buf2))
  1145  
  1146  	// Re-initialize the memory in wasm, which overwrites the region.
  1147  	initCallEngine2 := inst.ExportedFunction("init")
  1148  	_, err = initCallEngine2.Call(testCtx)
  1149  	require.NoError(t, err)
  1150  
  1151  	// The host was not affected because it is a different slice due to "memory.grow" affecting the underlying memory.
  1152  	require.Equal(t, hostPhraseTruncated, string(buf2))
  1153  }
  1154  
  1155  func testTwoIndirection(t *testing.T, r wazero.Runtime) {
  1156  	var buf bytes.Buffer
  1157  	ctx := context.WithValue(testCtx, experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
  1158  	_, err := r.NewHostModuleBuilder("host").NewFunctionBuilder().WithFunc(func(d uint32) uint32 {
  1159  		if d == math.MaxUint32 {
  1160  			panic(errors.New("host-function panic"))
  1161  		}
  1162  		return 1 / d // panics if d ==0.
  1163  	}).Export("div").Instantiate(ctx)
  1164  	require.NoError(t, err)
  1165  
  1166  	ft := wasm.FunctionType{Params: []wasm.ValueType{i32}, Results: []wasm.ValueType{i32}}
  1167  	hostImporter := binaryencoding.EncodeModule(&wasm.Module{
  1168  		ImportSection:   []wasm.Import{{Module: "host", Name: "div", DescFunc: 0}},
  1169  		TypeSection:     []wasm.FunctionType{ft},
  1170  		FunctionSection: []wasm.Index{0},
  1171  		CodeSection: []wasm.Code{
  1172  			// Calling imported host function ^.
  1173  			{Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeCall, 0, wasm.OpcodeEnd}},
  1174  		},
  1175  		ExportSection: []wasm.Export{{Name: "call_host_div", Type: wasm.ExternTypeFunc, Index: 1}},
  1176  		NameSection: &wasm.NameSection{
  1177  			ModuleName:    "host_importer",
  1178  			FunctionNames: wasm.NameMap{{Index: wasm.Index(1), Name: "call_host_div"}},
  1179  		},
  1180  	})
  1181  
  1182  	_, err = r.Instantiate(ctx, hostImporter)
  1183  	require.NoError(t, err)
  1184  
  1185  	main := binaryencoding.EncodeModule(&wasm.Module{
  1186  		ImportFunctionCount: 1,
  1187  		TypeSection:         []wasm.FunctionType{ft},
  1188  		ImportSection:       []wasm.Import{{Module: "host_importer", Name: "call_host_div", DescFunc: 0}},
  1189  		FunctionSection:     []wasm.Index{0},
  1190  		CodeSection:         []wasm.Code{{Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeCall, 0, wasm.OpcodeEnd}}},
  1191  		ExportSection:       []wasm.Export{{Name: "main", Type: wasm.ExternTypeFunc, Index: 1}},
  1192  		NameSection:         &wasm.NameSection{ModuleName: "main", FunctionNames: wasm.NameMap{{Index: wasm.Index(1), Name: "main"}}},
  1193  	})
  1194  
  1195  	inst, err := r.Instantiate(ctx, main)
  1196  	require.NoError(t, err)
  1197  
  1198  	t.Run("ok", func(t *testing.T) {
  1199  		mainFn := inst.ExportedFunction("main")
  1200  		require.NotNil(t, mainFn)
  1201  
  1202  		result1, err := mainFn.Call(testCtx, 1)
  1203  		require.NoError(t, err)
  1204  
  1205  		result2, err := mainFn.Call(testCtx, 2)
  1206  		require.NoError(t, err)
  1207  
  1208  		require.Equal(t, uint64(1), result1[0])
  1209  		require.Equal(t, uint64(0), result2[0])
  1210  	})
  1211  
  1212  	t.Run("errors", func(t *testing.T) {
  1213  		for _, tc := range []struct {
  1214  			name   string
  1215  			input  uint64
  1216  			expErr string
  1217  		}{
  1218  			{name: "host panic", input: math.MaxUint32, expErr: `host-function panic (recovered by wazero)
  1219  wasm stack trace:
  1220  	host.div(i32) i32
  1221  	host_importer.call_host_div(i32) i32
  1222  	main.main(i32) i32`},
  1223  			{name: "go runtime panic", input: 0, expErr: `runtime error: integer divide by zero (recovered by wazero)
  1224  wasm stack trace:
  1225  	host.div(i32) i32
  1226  	host_importer.call_host_div(i32) i32
  1227  	main.main(i32) i32`},
  1228  		} {
  1229  			tc := tc
  1230  			t.Run(tc.name, func(t *testing.T) {
  1231  				mainFn := inst.ExportedFunction("main")
  1232  				require.NotNil(t, mainFn)
  1233  
  1234  				_, err := mainFn.Call(testCtx, tc.input)
  1235  				require.Error(t, err)
  1236  				errStr := err.Error()
  1237  				// If this faces a Go runtime error, the error includes the Go stack trace which makes the test unstable,
  1238  				// so we trim them here.
  1239  				if index := strings.Index(errStr, wasmdebug.GoRuntimeErrorTracePrefix); index > -1 {
  1240  					errStr = strings.TrimSpace(errStr[:index])
  1241  				}
  1242  				require.Equal(t, errStr, tc.expErr)
  1243  			})
  1244  		}
  1245  	})
  1246  
  1247  	require.Equal(t, `
  1248  --> main.main(1)
  1249  	--> host_importer.call_host_div(1)
  1250  		==> host.div(1)
  1251  		<== 1
  1252  	<-- 1
  1253  <-- 1
  1254  --> main.main(2)
  1255  	--> host_importer.call_host_div(2)
  1256  		==> host.div(2)
  1257  		<== 0
  1258  	<-- 0
  1259  <-- 0
  1260  --> main.main(-1)
  1261  	--> host_importer.call_host_div(-1)
  1262  		==> host.div(-1)
  1263  --> main.main(0)
  1264  	--> host_importer.call_host_div(0)
  1265  		==> host.div(0)
  1266  `, "\n"+buf.String())
  1267  }
  1268  
  1269  func testBeforeListenerGlobals(t *testing.T, r wazero.Runtime) {
  1270  	type globals struct {
  1271  		values []uint64
  1272  		types  []api.ValueType
  1273  	}
  1274  
  1275  	expectedGlobals := []globals{
  1276  		{values: []uint64{100, 200}, types: []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}},
  1277  		{values: []uint64{42, 11}, types: []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}},
  1278  	}
  1279  
  1280  	fnListener := &fnListener{
  1281  		beforeFn: func(ctx context.Context, mod api.Module, def api.FunctionDefinition, params []uint64, si experimental.StackIterator) {
  1282  			require.True(t, len(expectedGlobals) > 0)
  1283  
  1284  			imod := mod.(experimental.InternalModule)
  1285  			expected := expectedGlobals[0]
  1286  
  1287  			require.Equal(t, len(expected.values), imod.NumGlobal())
  1288  			for i := 0; i < imod.NumGlobal(); i++ {
  1289  				global := imod.Global(i)
  1290  				require.Equal(t, expected.types[i], global.Type())
  1291  				require.Equal(t, expected.values[i], global.Get())
  1292  			}
  1293  
  1294  			expectedGlobals = expectedGlobals[1:]
  1295  		},
  1296  	}
  1297  
  1298  	buf := binaryencoding.EncodeModule(&wasm.Module{
  1299  		TypeSection:     []wasm.FunctionType{{}},
  1300  		FunctionSection: []wasm.Index{0, 0},
  1301  		GlobalSection: []wasm.Global{
  1302  			{
  1303  				Type: wasm.GlobalType{ValType: wasm.ValueTypeI32, Mutable: true},
  1304  				Init: wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeInt32(100)},
  1305  			},
  1306  			{
  1307  				Type: wasm.GlobalType{ValType: wasm.ValueTypeI32, Mutable: true},
  1308  				Init: wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeInt32(200)},
  1309  			},
  1310  		},
  1311  		CodeSection: []wasm.Code{
  1312  			{
  1313  				Body: []byte{
  1314  					wasm.OpcodeI32Const, 42,
  1315  					wasm.OpcodeGlobalSet, 0, // store 42 in global 0
  1316  					wasm.OpcodeI32Const, 11,
  1317  					wasm.OpcodeGlobalSet, 1, // store 11 in global 1
  1318  					wasm.OpcodeCall, 1, // call f2
  1319  					wasm.OpcodeEnd,
  1320  				},
  1321  			},
  1322  			{Body: []byte{wasm.OpcodeEnd}},
  1323  		},
  1324  		ExportSection: []wasm.Export{{Name: "f", Type: wasm.ExternTypeFunc, Index: 0}},
  1325  	})
  1326  
  1327  	ctx := context.WithValue(testCtx, experimental.FunctionListenerFactoryKey{}, fnListener)
  1328  	inst, err := r.Instantiate(ctx, buf)
  1329  	require.NoError(t, err)
  1330  
  1331  	f := inst.ExportedFunction("f")
  1332  	require.NotNil(t, f)
  1333  
  1334  	_, err = f.Call(ctx)
  1335  	require.NoError(t, err)
  1336  	require.True(t, len(expectedGlobals) == 0)
  1337  }
  1338  
  1339  // testBeforeListenerStackIterator tests that the StackIterator provided by the Engine to the Before hook
  1340  // of the listener is properly able to walk the stack.
  1341  func testBeforeListenerStackIterator(t *testing.T, r wazero.Runtime) {
  1342  	type stackEntry struct {
  1343  		debugName string
  1344  	}
  1345  
  1346  	expectedCallstacks := [][]stackEntry{
  1347  		{ // when calling f1
  1348  			{debugName: "whatever.f1"},
  1349  		},
  1350  		{ // when calling f2
  1351  			{debugName: "whatever.f2"},
  1352  			{debugName: "whatever.f1"},
  1353  		},
  1354  		{ // when calling
  1355  			{debugName: "whatever.f3"},
  1356  			{debugName: "whatever.f2"},
  1357  			{debugName: "whatever.f1"},
  1358  		},
  1359  		{ // when calling f4
  1360  			{debugName: "host.f4"},
  1361  			{debugName: "whatever.f3"},
  1362  			{debugName: "whatever.f2"},
  1363  			{debugName: "whatever.f1"},
  1364  		},
  1365  	}
  1366  
  1367  	fnListener := &fnListener{
  1368  		beforeFn: func(ctx context.Context, mod api.Module, def api.FunctionDefinition, params []uint64, si experimental.StackIterator) {
  1369  			require.True(t, len(expectedCallstacks) > 0)
  1370  			expectedCallstack := expectedCallstacks[0]
  1371  			for si.Next() {
  1372  				require.True(t, len(expectedCallstack) > 0)
  1373  				require.Equal(t, expectedCallstack[0].debugName, si.Function().Definition().DebugName())
  1374  				expectedCallstack = expectedCallstack[1:]
  1375  			}
  1376  			require.Equal(t, 0, len(expectedCallstack))
  1377  			expectedCallstacks = expectedCallstacks[1:]
  1378  		},
  1379  	}
  1380  
  1381  	ctx := context.WithValue(testCtx, experimental.FunctionListenerFactoryKey{}, fnListener)
  1382  	_, err := r.NewHostModuleBuilder("host").NewFunctionBuilder().WithFunc(func(x int32) int32 {
  1383  		return x + 100
  1384  	}).Export("f4").Instantiate(ctx)
  1385  	require.NoError(t, err)
  1386  
  1387  	m := binaryencoding.EncodeModule(&wasm.Module{
  1388  		TypeSection: []wasm.FunctionType{
  1389  			// f1 type
  1390  			{
  1391  				Params:  []api.ValueType{api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32},
  1392  				Results: []api.ValueType{},
  1393  			},
  1394  			// f2 type
  1395  			{
  1396  				Params:  []api.ValueType{},
  1397  				Results: []api.ValueType{api.ValueTypeI32},
  1398  			},
  1399  			// f3 type
  1400  			{
  1401  				Params:  []api.ValueType{api.ValueTypeI32},
  1402  				Results: []api.ValueType{api.ValueTypeI32},
  1403  			},
  1404  			// f4 type
  1405  			{
  1406  				Params:  []api.ValueType{api.ValueTypeI32},
  1407  				Results: []api.ValueType{api.ValueTypeI32},
  1408  			},
  1409  		},
  1410  		ImportFunctionCount: 1,
  1411  		ImportSection:       []wasm.Import{{Name: "f4", Module: "host", DescFunc: 3}},
  1412  		FunctionSection:     []wasm.Index{0, 1, 2},
  1413  		NameSection: &wasm.NameSection{
  1414  			ModuleName: "whatever",
  1415  			FunctionNames: wasm.NameMap{
  1416  				{Index: wasm.Index(1), Name: "f1"},
  1417  				{Index: wasm.Index(2), Name: "f2"},
  1418  				{Index: wasm.Index(3), Name: "f3"},
  1419  				{Index: wasm.Index(0), Name: "f4"},
  1420  			},
  1421  		},
  1422  		CodeSection: []wasm.Code{
  1423  			{ // f1
  1424  				Body: []byte{
  1425  					wasm.OpcodeCall,
  1426  					2, // call f2
  1427  					wasm.OpcodeDrop,
  1428  					wasm.OpcodeEnd,
  1429  				},
  1430  			},
  1431  			{ // f2
  1432  				LocalTypes: []wasm.ValueType{wasm.ValueTypeI32},
  1433  				Body: []byte{
  1434  					wasm.OpcodeI32Const, 42, // local for f2
  1435  					wasm.OpcodeLocalSet, 0,
  1436  					wasm.OpcodeI32Const, 5, // argument of f3
  1437  					wasm.OpcodeCall,
  1438  					3, // call f3
  1439  					wasm.OpcodeEnd,
  1440  				},
  1441  			},
  1442  			{ // f3
  1443  				Body: []byte{
  1444  					wasm.OpcodeI32Const, 6,
  1445  					wasm.OpcodeCall,
  1446  					0, // call host function
  1447  					wasm.OpcodeEnd,
  1448  				},
  1449  			},
  1450  		},
  1451  		ExportSection: []wasm.Export{{Name: "f1", Type: wasm.ExternTypeFunc, Index: 1}},
  1452  	})
  1453  
  1454  	inst, err := r.Instantiate(ctx, m)
  1455  	require.NoError(t, err)
  1456  
  1457  	f1 := inst.ExportedFunction("f1")
  1458  	require.NotNil(t, f1)
  1459  
  1460  	_, err = f1.Call(ctx, 2, 3, 4)
  1461  	require.NoError(t, err)
  1462  	require.Equal(t, 0, len(expectedCallstacks))
  1463  }
  1464  
  1465  func testListenerStackIteratorOffset(t *testing.T, r wazero.Runtime) {
  1466  	type frame struct {
  1467  		function api.FunctionDefinition
  1468  		offset   uint64
  1469  	}
  1470  
  1471  	var tape [][]frame
  1472  	fnListener := &fnListener{
  1473  		beforeFn: func(ctx context.Context, mod api.Module, def api.FunctionDefinition, params []uint64, si experimental.StackIterator) {
  1474  			var stack []frame
  1475  			for si.Next() {
  1476  				fn := si.Function()
  1477  				pc := si.ProgramCounter()
  1478  				stack = append(stack, frame{fn.Definition(), fn.SourceOffsetForPC(pc)})
  1479  			}
  1480  			tape = append(tape, stack)
  1481  		},
  1482  	}
  1483  	ctx := context.WithValue(testCtx, experimental.FunctionListenerFactoryKey{}, fnListener)
  1484  
  1485  	// Minimal DWARF info section to make debug/dwarf.New() happy.
  1486  	// Necessary to make the compiler emit source offset maps.
  1487  	minimalDWARFInfo := []byte{
  1488  		0x7, 0x0, 0x0, 0x0, // length (len(info) - 4)
  1489  		0x3, 0x0, // version (between 3 and 5 makes it easier)
  1490  		0x0, 0x0, 0x0, 0x0, // abbrev offset
  1491  		0x0, // asize
  1492  	}
  1493  
  1494  	encoded := binaryencoding.EncodeModule(&wasm.Module{
  1495  		TypeSection: []wasm.FunctionType{
  1496  			// f1 type
  1497  			{Params: []api.ValueType{api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32}},
  1498  			// f2 type
  1499  			{Results: []api.ValueType{api.ValueTypeI32}},
  1500  			// f3 type
  1501  			{Params: []api.ValueType{api.ValueTypeI32}, Results: []api.ValueType{api.ValueTypeI32}},
  1502  		},
  1503  		FunctionSection: []wasm.Index{0, 1, 2},
  1504  		NameSection: &wasm.NameSection{
  1505  			ModuleName: "whatever",
  1506  			FunctionNames: wasm.NameMap{
  1507  				{Index: wasm.Index(0), Name: "f1"},
  1508  				{Index: wasm.Index(1), Name: "f2"},
  1509  				{Index: wasm.Index(2), Name: "f3"},
  1510  			},
  1511  		},
  1512  		CodeSection: []wasm.Code{
  1513  			{ // f1
  1514  				Body: []byte{
  1515  					wasm.OpcodeI32Const, 42,
  1516  					wasm.OpcodeLocalSet, 0,
  1517  					wasm.OpcodeI32Const, 11,
  1518  					wasm.OpcodeLocalSet, 1,
  1519  					wasm.OpcodeCall, 1, // call f2
  1520  					wasm.OpcodeDrop,
  1521  					wasm.OpcodeEnd,
  1522  				},
  1523  			},
  1524  			{
  1525  				Body: []byte{
  1526  					wasm.OpcodeI32Const, 6,
  1527  					wasm.OpcodeCall, 2, // call f3
  1528  					wasm.OpcodeEnd,
  1529  				},
  1530  			},
  1531  			{Body: []byte{wasm.OpcodeI32Const, 15, wasm.OpcodeEnd}},
  1532  		},
  1533  		ExportSection: []wasm.Export{
  1534  			{Name: "f1", Type: wasm.ExternTypeFunc, Index: 0},
  1535  			{Name: "f2", Type: wasm.ExternTypeFunc, Index: 1},
  1536  			{Name: "f3", Type: wasm.ExternTypeFunc, Index: 2},
  1537  		},
  1538  		CustomSections: []*wasm.CustomSection{{Name: ".debug_info", Data: minimalDWARFInfo}},
  1539  	})
  1540  	decoded, err := binary.DecodeModule(encoded, api.CoreFeaturesV2, 0, false, true, true)
  1541  	require.NoError(t, err)
  1542  
  1543  	f1offset := decoded.CodeSection[0].BodyOffsetInCodeSection
  1544  	f2offset := decoded.CodeSection[1].BodyOffsetInCodeSection
  1545  	f3offset := decoded.CodeSection[2].BodyOffsetInCodeSection
  1546  
  1547  	inst, err := r.Instantiate(ctx, encoded)
  1548  	require.NoError(t, err)
  1549  
  1550  	f1Fn := inst.ExportedFunction("f1")
  1551  	require.NotNil(t, f1Fn)
  1552  
  1553  	_, err = f1Fn.Call(ctx, 2, 3, 4)
  1554  	require.NoError(t, err)
  1555  
  1556  	module, ok := inst.(*wasm.ModuleInstance)
  1557  	require.True(t, ok)
  1558  
  1559  	defs := module.ExportedFunctionDefinitions()
  1560  	f1 := defs["f1"]
  1561  	f2 := defs["f2"]
  1562  	f3 := defs["f3"]
  1563  	t.Logf("f1 offset: %#x", f1offset)
  1564  	t.Logf("f2 offset: %#x", f2offset)
  1565  	t.Logf("f3 offset: %#x", f3offset)
  1566  
  1567  	expectedStacks := [][]frame{
  1568  		{
  1569  			{f1, f1offset + 0},
  1570  		},
  1571  		{
  1572  			{f2, f2offset + 0},
  1573  			{f1, f1offset + 8}, // index of call opcode in f1's code
  1574  		},
  1575  		{
  1576  			{f3, f3offset},     // host functions don't have a wasm code offset
  1577  			{f2, f2offset + 2}, // index of call opcode in f2's code
  1578  			{f1, f1offset + 8}, // index of call opcode in f1's code
  1579  		},
  1580  	}
  1581  
  1582  	for si, stack := range tape {
  1583  		t.Log("Recorded stack", si, ":")
  1584  		require.True(t, len(expectedStacks) > 0, "more recorded stacks than expected stacks")
  1585  		expectedStack := expectedStacks[0]
  1586  		expectedStacks = expectedStacks[1:]
  1587  		for fi, frame := range stack {
  1588  			t.Logf("\t%d -> %s :: %#x", fi, frame.function.Name(), frame.offset)
  1589  			require.True(t, len(expectedStack) > 0, "more frames in stack than expected")
  1590  			expectedFrame := expectedStack[0]
  1591  			expectedStack = expectedStack[1:]
  1592  			require.Equal(t, expectedFrame, frame)
  1593  		}
  1594  		require.Zero(t, len(expectedStack), "expected more frames in stack")
  1595  	}
  1596  	require.Zero(t, len(expectedStacks), "expected more stacks")
  1597  }
  1598  
  1599  // fnListener implements both experimental.FunctionListenerFactory and experimental.FunctionListener for testing.
  1600  type fnListener struct {
  1601  	beforeFn func(context.Context, api.Module, api.FunctionDefinition, []uint64, experimental.StackIterator)
  1602  	afterFn  func(context.Context, api.Module, api.FunctionDefinition, []uint64)
  1603  	abortFn  func(context.Context, api.Module, api.FunctionDefinition, any)
  1604  }
  1605  
  1606  // NewFunctionListener implements experimental.FunctionListenerFactory.
  1607  func (f *fnListener) NewFunctionListener(api.FunctionDefinition) experimental.FunctionListener {
  1608  	return f
  1609  }
  1610  
  1611  // Before implements experimental.FunctionListener.
  1612  func (f *fnListener) Before(ctx context.Context, mod api.Module, def api.FunctionDefinition, params []uint64, stackIterator experimental.StackIterator) {
  1613  	if f.beforeFn != nil {
  1614  		f.beforeFn(ctx, mod, def, params, stackIterator)
  1615  	}
  1616  }
  1617  
  1618  // After implements experimental.FunctionListener.
  1619  func (f *fnListener) After(ctx context.Context, mod api.Module, def api.FunctionDefinition, results []uint64) {
  1620  	if f.afterFn != nil {
  1621  		f.afterFn(ctx, mod, def, results)
  1622  	}
  1623  }
  1624  
  1625  // Abort implements experimental.FunctionListener.
  1626  func (f *fnListener) Abort(ctx context.Context, mod api.Module, def api.FunctionDefinition, err error) {
  1627  	if f.abortFn != nil {
  1628  		f.abortFn(ctx, mod, def, err)
  1629  	}
  1630  }
  1631  
  1632  func manyParamsResultsMod() (bin []byte, params []uint64) {
  1633  	mainType := wasm.FunctionType{}
  1634  	swapperType := wasm.FunctionType{}
  1635  	doublerType := wasm.FunctionType{}
  1636  	manyConstsType := wasm.FunctionType{}
  1637  	callManyConstsType := wasm.FunctionType{}
  1638  	pickLastVectorType := wasm.FunctionType{Results: []wasm.ValueType{v128}}
  1639  	callManyConstsAndPickLastVectorType := wasm.FunctionType{Results: []wasm.ValueType{v128}}
  1640  	for i := 0; i < 20; i++ {
  1641  		swapperType.Params = append(swapperType.Params, i32, i64, f32, f64, v128)
  1642  		swapperType.Results = append(swapperType.Results, v128, f64, f32, i64, i32)
  1643  		mainType.Params = append(mainType.Params, i32, i64, f32, f64, v128)
  1644  		mainType.Results = append(mainType.Results, v128, f64, f32, i64, i32)
  1645  		doublerType.Params = append(doublerType.Results, v128, f64, f32, i64, i32)
  1646  		doublerType.Results = append(doublerType.Results, v128, f64, f32, i64, i32)
  1647  		manyConstsType.Results = append(manyConstsType.Results, i32, i64, f32, f64, v128)
  1648  		callManyConstsType.Results = append(callManyConstsType.Results, i32, i64, f32, f64, v128)
  1649  		pickLastVectorType.Params = append(pickLastVectorType.Params, i32, i64, f32, f64, v128)
  1650  	}
  1651  
  1652  	var mainBody []byte
  1653  	for i := 0; i < 100; i++ {
  1654  		mainBody = append(mainBody, wasm.OpcodeLocalGet)
  1655  		mainBody = append(mainBody, leb128.EncodeUint32(uint32(i))...)
  1656  	}
  1657  	mainBody = append(mainBody, wasm.OpcodeCall, 1) // Call swapper.
  1658  	mainBody = append(mainBody, wasm.OpcodeCall, 2) // Call doubler.
  1659  	mainBody = append(mainBody, wasm.OpcodeEnd)
  1660  
  1661  	var swapperBody []byte
  1662  	for i := 0; i < 100; i++ {
  1663  		swapperBody = append(swapperBody, wasm.OpcodeLocalGet)
  1664  		swapperBody = append(swapperBody, leb128.EncodeUint32(uint32(99-i))...)
  1665  	}
  1666  	swapperBody = append(swapperBody, wasm.OpcodeEnd)
  1667  
  1668  	var doublerBody []byte
  1669  	for i := 0; i < 100; i += 5 {
  1670  		// Returns v128 as-is.
  1671  		doublerBody = append(doublerBody, wasm.OpcodeLocalGet)
  1672  		doublerBody = append(doublerBody, leb128.EncodeUint32(uint32(i))...)
  1673  		// Double f64.
  1674  		doublerBody = append(doublerBody, wasm.OpcodeLocalGet)
  1675  		doublerBody = append(doublerBody, leb128.EncodeUint32(uint32(i+1))...)
  1676  		doublerBody = append(doublerBody, wasm.OpcodeLocalGet)
  1677  		doublerBody = append(doublerBody, leb128.EncodeUint32(uint32(i+1))...)
  1678  		doublerBody = append(doublerBody, wasm.OpcodeF64Add)
  1679  		// Double f32.
  1680  		doublerBody = append(doublerBody, wasm.OpcodeLocalGet)
  1681  		doublerBody = append(doublerBody, leb128.EncodeUint32(uint32(i+2))...)
  1682  		doublerBody = append(doublerBody, wasm.OpcodeLocalGet)
  1683  		doublerBody = append(doublerBody, leb128.EncodeUint32(uint32(i+2))...)
  1684  		doublerBody = append(doublerBody, wasm.OpcodeF32Add)
  1685  		// Double i64.
  1686  		doublerBody = append(doublerBody, wasm.OpcodeLocalGet)
  1687  		doublerBody = append(doublerBody, leb128.EncodeUint32(uint32(i+3))...)
  1688  		doublerBody = append(doublerBody, wasm.OpcodeLocalGet)
  1689  		doublerBody = append(doublerBody, leb128.EncodeUint32(uint32(i+3))...)
  1690  		doublerBody = append(doublerBody, wasm.OpcodeI64Add)
  1691  		// Double i32.
  1692  		doublerBody = append(doublerBody, wasm.OpcodeLocalGet)
  1693  		doublerBody = append(doublerBody, leb128.EncodeUint32(uint32(i+4))...)
  1694  		doublerBody = append(doublerBody, wasm.OpcodeLocalGet)
  1695  		doublerBody = append(doublerBody, leb128.EncodeUint32(uint32(i+4))...)
  1696  		doublerBody = append(doublerBody, wasm.OpcodeI32Add)
  1697  	}
  1698  	doublerBody = append(doublerBody, wasm.OpcodeEnd)
  1699  
  1700  	var manyConstsBody []byte
  1701  	for i := 0; i < 100; i += 5 {
  1702  		ib := byte(i)
  1703  		manyConstsBody = append(manyConstsBody, wasm.OpcodeI32Const)
  1704  		manyConstsBody = append(manyConstsBody, leb128.EncodeInt32(int32(i))...)
  1705  		manyConstsBody = append(manyConstsBody, wasm.OpcodeI64Const)
  1706  		manyConstsBody = append(manyConstsBody, leb128.EncodeInt64(int64(i))...)
  1707  		manyConstsBody = append(manyConstsBody, wasm.OpcodeF32Const)
  1708  		manyConstsBody = append(manyConstsBody, ib, ib, ib, ib)
  1709  		manyConstsBody = append(manyConstsBody, wasm.OpcodeF64Const)
  1710  		manyConstsBody = append(manyConstsBody, ib, ib, ib, ib, ib, ib, ib, ib)
  1711  		manyConstsBody = append(manyConstsBody, wasm.OpcodeVecPrefix, wasm.OpcodeVecV128Const)
  1712  		manyConstsBody = append(manyConstsBody, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib, ib)
  1713  	}
  1714  	manyConstsBody = append(manyConstsBody, wasm.OpcodeEnd)
  1715  
  1716  	var callManyConstsBody []byte
  1717  	callManyConstsBody = append(callManyConstsBody, wasm.OpcodeCall, 5, wasm.OpcodeEnd)
  1718  
  1719  	var pickLastVector []byte
  1720  	pickLastVector = append(pickLastVector, wasm.OpcodeLocalGet, 99, wasm.OpcodeEnd)
  1721  
  1722  	var callManyConstsAndPickLastVector []byte
  1723  	callManyConstsAndPickLastVector = append(callManyConstsAndPickLastVector, wasm.OpcodeCall, 5, wasm.OpcodeCall, 6, wasm.OpcodeEnd)
  1724  
  1725  	nameSection := wasm.NameSection{}
  1726  	nameSection.FunctionNames = []wasm.NameAssoc{
  1727  		{Index: 0, Name: "main"},
  1728  		{Index: 1, Name: "swapper"},
  1729  		{Index: 2, Name: "doubler"},
  1730  		{Index: 3, Name: "call_many_consts"},
  1731  		{Index: 4, Name: "call_many_consts_and_pick_last_vector"},
  1732  		{Index: 5, Name: "many_consts"},
  1733  		{Index: 6, Name: "pick_last_vector"},
  1734  	}
  1735  
  1736  	typeSection := []wasm.FunctionType{mainType, swapperType, doublerType, callManyConstsType, callManyConstsAndPickLastVectorType, manyConstsType, pickLastVectorType}
  1737  
  1738  	for i, typ := range typeSection {
  1739  		paramNames := wasm.NameMapAssoc{Index: wasm.Index(i)}
  1740  		for paramIndex, paramType := range typ.Params {
  1741  			name := fmt.Sprintf("[%d:%s]", paramIndex, wasm.ValueTypeName(paramType))
  1742  			paramNames.NameMap = append(paramNames.NameMap, wasm.NameAssoc{Index: wasm.Index(paramIndex), Name: name})
  1743  		}
  1744  		nameSection.LocalNames = append(nameSection.LocalNames, paramNames)
  1745  	}
  1746  
  1747  	bin = binaryencoding.EncodeModule(&wasm.Module{
  1748  		TypeSection: typeSection,
  1749  		ExportSection: []wasm.Export{
  1750  			{Name: "main", Type: wasm.ExternTypeFunc, Index: 0},
  1751  			{Name: "swapper", Type: wasm.ExternTypeFunc, Index: 1},
  1752  			{Name: "doubler", Type: wasm.ExternTypeFunc, Index: 2},
  1753  			{Name: "call_many_consts", Type: wasm.ExternTypeFunc, Index: 3},
  1754  			{Name: "call_many_consts_and_pick_last_vector", Type: wasm.ExternTypeFunc, Index: 4},
  1755  		},
  1756  		FunctionSection: []wasm.Index{0, 1, 2, 3, 4, 5, 6},
  1757  		CodeSection: []wasm.Code{
  1758  			{Body: mainBody},
  1759  			{Body: swapperBody},
  1760  			{Body: doublerBody},
  1761  			{Body: callManyConstsBody},
  1762  			{Body: callManyConstsAndPickLastVector},
  1763  			{Body: manyConstsBody},
  1764  			{Body: pickLastVector},
  1765  		},
  1766  		NameSection: &nameSection,
  1767  	})
  1768  
  1769  	for i := 0; i < 100; i += 5 {
  1770  		params = append(params, uint64(i))
  1771  		params = append(params, uint64(i+1))
  1772  		params = append(params, uint64(i+2))
  1773  		params = append(params, uint64(i+3))
  1774  		// Vector needs two values.
  1775  		params = append(params, uint64(i+3))
  1776  		params = append(params, uint64(i+3))
  1777  	}
  1778  	return
  1779  }
  1780  
  1781  func testManyParamsResultsCallManyConsts(t *testing.T, r wazero.Runtime) {
  1782  	ctx := context.Background()
  1783  
  1784  	bin, _ := manyParamsResultsMod()
  1785  	mod, err := r.Instantiate(ctx, bin)
  1786  	require.NoError(t, err)
  1787  
  1788  	main := mod.ExportedFunction("call_many_consts")
  1789  	require.NotNil(t, main)
  1790  
  1791  	results, err := main.Call(ctx)
  1792  	require.NoError(t, err)
  1793  
  1794  	exp := []uint64{
  1795  		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5050505, 0x505050505050505, 0x505050505050505,
  1796  		0x505050505050505, 0xa, 0xa, 0xa0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a,
  1797  		0xf, 0xf, 0xf0f0f0f, 0xf0f0f0f0f0f0f0f, 0xf0f0f0f0f0f0f0f, 0xf0f0f0f0f0f0f0f, 0x14, 0x14, 0x14141414,
  1798  		0x1414141414141414, 0x1414141414141414, 0x1414141414141414, 0x19, 0x19, 0x19191919, 0x1919191919191919,
  1799  		0x1919191919191919, 0x1919191919191919, 0x1e, 0x1e, 0x1e1e1e1e, 0x1e1e1e1e1e1e1e1e, 0x1e1e1e1e1e1e1e1e,
  1800  		0x1e1e1e1e1e1e1e1e, 0x23, 0x23, 0x23232323, 0x2323232323232323, 0x2323232323232323, 0x2323232323232323,
  1801  		0x28, 0x28, 0x28282828, 0x2828282828282828, 0x2828282828282828, 0x2828282828282828, 0x2d, 0x2d, 0x2d2d2d2d,
  1802  		0x2d2d2d2d2d2d2d2d, 0x2d2d2d2d2d2d2d2d, 0x2d2d2d2d2d2d2d2d, 0x32, 0x32, 0x32323232, 0x3232323232323232,
  1803  		0x3232323232323232, 0x3232323232323232, 0x37, 0x37, 0x37373737, 0x3737373737373737, 0x3737373737373737,
  1804  		0x3737373737373737, 0x3c, 0x3c, 0x3c3c3c3c, 0x3c3c3c3c3c3c3c3c, 0x3c3c3c3c3c3c3c3c, 0x3c3c3c3c3c3c3c3c,
  1805  		0x41, 0x41, 0x41414141, 0x4141414141414141, 0x4141414141414141, 0x4141414141414141, 0x46, 0x46, 0x46464646,
  1806  		0x4646464646464646, 0x4646464646464646, 0x4646464646464646, 0x4b, 0x4b, 0x4b4b4b4b, 0x4b4b4b4b4b4b4b4b,
  1807  		0x4b4b4b4b4b4b4b4b, 0x4b4b4b4b4b4b4b4b, 0x50, 0x50, 0x50505050, 0x5050505050505050, 0x5050505050505050,
  1808  		0x5050505050505050, 0x55, 0x55, 0x55555555, 0x5555555555555555, 0x5555555555555555, 0x5555555555555555,
  1809  		0x5a, 0x5a, 0x5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5f, 0x5f, 0x5f5f5f5f,
  1810  		0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f,
  1811  	}
  1812  	require.Equal(t, exp, results)
  1813  }
  1814  
  1815  func testManyParamsResultsCallManyConstsListener(t *testing.T, r wazero.Runtime) {
  1816  	var buf bytes.Buffer
  1817  	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
  1818  
  1819  	bin, _ := manyParamsResultsMod()
  1820  	mod, err := r.Instantiate(ctx, bin)
  1821  	require.NoError(t, err)
  1822  
  1823  	main := mod.ExportedFunction("call_many_consts")
  1824  	require.NotNil(t, main)
  1825  
  1826  	results, err := main.Call(ctx)
  1827  	require.NoError(t, err)
  1828  
  1829  	fmt.Println(buf.String())
  1830  	require.Equal(t, `
  1831  --> .call_many_consts()
  1832  	--> .many_consts()
  1833  	<-- (0,0,0,0,00000000000000000000000000000000,0,5,7e-45,4.16077606e-316,05050505050505050505050505050505,84215045,361700864190383365,1.4e-44,5e-323,000000000a0a0a0a0a0a0a0a0a0a0a0a,168430090,723401728380766730,6.6463464e-33,7.4e-323,000000000000000f000000000f0f0f0f,252645135,1085102592571150095,7.0533445e-30,3.815736827118017e-236,00000000000000140000000000000014,20,336860180,7.47605e-27,5.964208835435795e-212,14141414141414140000000000000019,25,25,7.914983e-24,9.01285756841504e-188,19191919191919191919191919191919,421075225,30,4.2e-44,2.496465636e-315,1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e,505290270,2170205185142300190,4.9e-44,1.73e-322,00000000232323232323232323232323,589505315,2531906049332683555,8.843688e-18,2e-322,00000000000000280000000028282828,673720360,2893606913523066920,9.334581e-15,3.0654356309538037e-115,000000000000002d000000000000002d,45,757935405,9.8439425e-12,4.4759381595361623e-91,2d2d2d2d2d2d2d2d0000000000000032,50,50,1.0372377e-08,6.749300603603778e-67,32323232323232323232323232323232,842150450,55,7.7e-44,4.576853666e-315,37373737373737373737373737373737,926365495,3978709506094217015,8.4e-44,2.96e-322,000000003c3c3c3c3c3c3c3c3c3c3c3c,1010580540,4340410370284600380,0.01148897,3.2e-322,00000000000000410000000041414141,1094795585,4702111234474983745,12.078431,2.2616345098039214e+06,00000000000000460000000000000046,70,1179010630,12689.568,3.5295369653413445e+30,4646464646464646000000000000004b,75,75,1.3323083e+07,5.2285141982483265e+54,4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b,1263225675,80,1.12e-43,6.657241696e-315,50505050505050505050505050505050)
  1834  <-- (0,0,0,0,00000000000000000000000000000000,0,5,7e-45,4.16077606e-316,05050505050505050505050505050505,84215045,361700864190383365,1.4e-44,5e-323,000000000a0a0a0a0a0a0a0a0a0a0a0a,168430090,723401728380766730,6.6463464e-33,7.4e-323,000000000000000f000000000f0f0f0f,252645135,1085102592571150095,7.0533445e-30,3.815736827118017e-236,00000000000000140000000000000014,20,336860180,7.47605e-27,5.964208835435795e-212,14141414141414140000000000000019,25,25,7.914983e-24,9.01285756841504e-188,19191919191919191919191919191919,421075225,30,4.2e-44,2.496465636e-315,1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e,505290270,2170205185142300190,4.9e-44,1.73e-322,00000000232323232323232323232323,589505315,2531906049332683555,8.843688e-18,2e-322,00000000000000280000000028282828,673720360,2893606913523066920,9.334581e-15,3.0654356309538037e-115,000000000000002d000000000000002d,45,757935405,9.8439425e-12,4.4759381595361623e-91,2d2d2d2d2d2d2d2d0000000000000032,50,50,1.0372377e-08,6.749300603603778e-67,32323232323232323232323232323232,842150450,55,7.7e-44,4.576853666e-315,37373737373737373737373737373737,926365495,3978709506094217015,8.4e-44,2.96e-322,000000003c3c3c3c3c3c3c3c3c3c3c3c,1010580540,4340410370284600380,0.01148897,3.2e-322,00000000000000410000000041414141,1094795585,4702111234474983745,12.078431,2.2616345098039214e+06,00000000000000460000000000000046,70,1179010630,12689.568,3.5295369653413445e+30,4646464646464646000000000000004b,75,75,1.3323083e+07,5.2285141982483265e+54,4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b,1263225675,80,1.12e-43,6.657241696e-315,50505050505050505050505050505050)
  1835  `, "\n"+buf.String())
  1836  
  1837  	exp := []uint64{
  1838  		0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5050505, 0x505050505050505, 0x505050505050505,
  1839  		0x505050505050505, 0xa, 0xa, 0xa0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a, 0xa0a0a0a0a0a0a0a,
  1840  		0xf, 0xf, 0xf0f0f0f, 0xf0f0f0f0f0f0f0f, 0xf0f0f0f0f0f0f0f, 0xf0f0f0f0f0f0f0f, 0x14, 0x14, 0x14141414,
  1841  		0x1414141414141414, 0x1414141414141414, 0x1414141414141414, 0x19, 0x19, 0x19191919, 0x1919191919191919,
  1842  		0x1919191919191919, 0x1919191919191919, 0x1e, 0x1e, 0x1e1e1e1e, 0x1e1e1e1e1e1e1e1e, 0x1e1e1e1e1e1e1e1e,
  1843  		0x1e1e1e1e1e1e1e1e, 0x23, 0x23, 0x23232323, 0x2323232323232323, 0x2323232323232323, 0x2323232323232323,
  1844  		0x28, 0x28, 0x28282828, 0x2828282828282828, 0x2828282828282828, 0x2828282828282828, 0x2d, 0x2d, 0x2d2d2d2d,
  1845  		0x2d2d2d2d2d2d2d2d, 0x2d2d2d2d2d2d2d2d, 0x2d2d2d2d2d2d2d2d, 0x32, 0x32, 0x32323232, 0x3232323232323232,
  1846  		0x3232323232323232, 0x3232323232323232, 0x37, 0x37, 0x37373737, 0x3737373737373737, 0x3737373737373737,
  1847  		0x3737373737373737, 0x3c, 0x3c, 0x3c3c3c3c, 0x3c3c3c3c3c3c3c3c, 0x3c3c3c3c3c3c3c3c, 0x3c3c3c3c3c3c3c3c,
  1848  		0x41, 0x41, 0x41414141, 0x4141414141414141, 0x4141414141414141, 0x4141414141414141, 0x46, 0x46, 0x46464646,
  1849  		0x4646464646464646, 0x4646464646464646, 0x4646464646464646, 0x4b, 0x4b, 0x4b4b4b4b, 0x4b4b4b4b4b4b4b4b,
  1850  		0x4b4b4b4b4b4b4b4b, 0x4b4b4b4b4b4b4b4b, 0x50, 0x50, 0x50505050, 0x5050505050505050, 0x5050505050505050,
  1851  		0x5050505050505050, 0x55, 0x55, 0x55555555, 0x5555555555555555, 0x5555555555555555, 0x5555555555555555,
  1852  		0x5a, 0x5a, 0x5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5a5a5a5a5a5a5a5a, 0x5f, 0x5f, 0x5f5f5f5f,
  1853  		0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f,
  1854  	}
  1855  	require.Equal(t, exp, results)
  1856  }
  1857  
  1858  func testManyParamsResultsDoubler(t *testing.T, r wazero.Runtime) {
  1859  	ctx := context.Background()
  1860  
  1861  	bin, params := manyParamsResultsMod()
  1862  	mod, err := r.Instantiate(ctx, bin)
  1863  	require.NoError(t, err)
  1864  
  1865  	main := mod.ExportedFunction("doubler")
  1866  	require.NotNil(t, main)
  1867  
  1868  	results, err := main.Call(ctx, params...)
  1869  	require.NoError(t, err)
  1870  
  1871  	exp := []uint64{
  1872  		0x0, 0x1, 0x4, 0x6, 0x6, 0x6, 0x5, 0x6, 0xe, 0x10, 0x10, 0x10, 0xa,
  1873  		0xb, 0x18, 0x1a, 0x1a, 0x1a, 0xf, 0x10, 0x22, 0x24, 0x24, 0x24, 0x14,
  1874  		0x15, 0x2c, 0x2e, 0x2e, 0x2e, 0x19, 0x1a, 0x36, 0x38, 0x38, 0x38, 0x1e,
  1875  		0x1f, 0x40, 0x42, 0x42, 0x42, 0x23, 0x24, 0x4a, 0x4c, 0x4c, 0x4c, 0x28,
  1876  		0x29, 0x54, 0x56, 0x56, 0x56, 0x2d, 0x2e, 0x5e, 0x60, 0x60, 0x60, 0x32,
  1877  		0x33, 0x68, 0x6a, 0x6a, 0x6a, 0x37, 0x38, 0x72, 0x74, 0x74, 0x74, 0x3c,
  1878  		0x3d, 0x7c, 0x7e, 0x7e, 0x7e, 0x41, 0x42, 0x86, 0x88, 0x88, 0x88, 0x46,
  1879  		0x47, 0x90, 0x92, 0x92, 0x92, 0x4b, 0x4c, 0x9a, 0x9c, 0x9c, 0x9c, 0x50,
  1880  		0x51, 0xa4, 0xa6, 0xa6, 0xa6, 0x55, 0x56, 0xae, 0xb0, 0xb0, 0xb0, 0x5a,
  1881  		0x5b, 0xb8, 0xba, 0xba, 0xba, 0x5f, 0x60, 0xc2, 0xc4, 0xc4, 0xc4,
  1882  	}
  1883  	require.Equal(t, exp, results)
  1884  }
  1885  
  1886  func testManyParamsResultsDoublerListener(t *testing.T, r wazero.Runtime) {
  1887  	var buf bytes.Buffer
  1888  	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
  1889  
  1890  	bin, params := manyParamsResultsMod()
  1891  	mod, err := r.Instantiate(ctx, bin)
  1892  	require.NoError(t, err)
  1893  
  1894  	main := mod.ExportedFunction("doubler")
  1895  	require.NotNil(t, main)
  1896  
  1897  	results, err := main.Call(ctx, params...)
  1898  	require.NoError(t, err)
  1899  
  1900  	fmt.Println(buf.String())
  1901  	require.Equal(t, `
  1902  --> .doubler([0:v128]=00000000000000000000000000000001,[1:f64]=5e-324,[2:f32]=3e-45,[3:i64]=3,[4:i32]=3,[5:v128]=00000000000000030000000000000005,[6:f64]=2.5e-323,[7:f32]=8e-45,[8:i64]=7,[9:i32]=8,[10:v128]=00000000000000080000000000000008,[11:f64]=4e-323,[12:f32]=1.4e-44,[13:i64]=11,[14:i32]=12,[15:v128]=000000000000000d000000000000000d,[16:f64]=6.4e-323,[17:f32]=1.8e-44,[18:i64]=15,[19:i32]=16,[20:v128]=00000000000000110000000000000012,[21:f64]=9e-323,[22:f32]=2.5e-44,[23:i64]=18,[24:i32]=20,[25:v128]=00000000000000150000000000000016,[26:f64]=1.1e-322,[27:f32]=3.2e-44,[28:i64]=23,[29:i32]=23,[30:v128]=0000000000000019000000000000001a,[31:f64]=1.3e-322,[32:f32]=3.8e-44,[33:i64]=28,[34:i32]=28,[35:v128]=000000000000001c000000000000001e,[36:f64]=1.5e-322,[37:f32]=4.3e-44,[38:i64]=32,[39:i32]=33,[40:v128]=00000000000000210000000000000021,[41:f64]=1.63e-322,[42:f32]=4.9e-44,[43:i64]=36,[44:i32]=37,[45:v128]=00000000000000260000000000000026,[46:f64]=1.9e-322,[47:f32]=5.3e-44,[48:i64]=40,[49:i32]=41,[50:v128]=000000000000002a000000000000002b,[51:f64]=2.1e-322,[52:f32]=6e-44,[53:i64]=43,[54:i32]=45,[55:v128]=000000000000002e000000000000002f,[56:f64]=2.3e-322,[57:f32]=6.7e-44,[58:i64]=48,[59:i32]=48,[60:v128]=00000000000000320000000000000033,[61:f64]=2.5e-322,[62:f32]=7.3e-44,[63:i64]=53,[64:i32]=53,[65:v128]=00000000000000350000000000000037,[66:f64]=2.7e-322,[67:f32]=7.8e-44,[68:i64]=57,[69:i32]=58,[70:v128]=000000000000003a000000000000003a,[71:f64]=2.87e-322,[72:f32]=8.4e-44,[73:i64]=61,[74:i32]=62,[75:v128]=000000000000003f000000000000003f,[76:f64]=3.1e-322,[77:f32]=8.8e-44,[78:i64]=65,[79:i32]=66,[80:v128]=00000000000000430000000000000044,[81:f64]=3.36e-322,[82:f32]=9.5e-44,[83:i64]=68,[84:i32]=70,[85:v128]=00000000000000470000000000000048,[86:f64]=3.56e-322,[87:f32]=1.02e-43,[88:i64]=73,[89:i32]=73,[90:v128]=000000000000004b000000000000004c,[91:f64]=3.75e-322,[92:f32]=1.08e-43,[93:i64]=78,[94:i32]=78,[95:v128]=000000000000004e0000000000000050,[96:f64]=3.95e-322,[97:f32]=1.14e-43,[98:i64]=82,[99:i32]=83)
  1903  <-- (00000000000000000000000000000001,5e-324,6e-45,6,6,00000000000000060000000000000005,2.5e-323,8e-45,14,16,00000000000000100000000000000010,8e-323,1.4e-44,11,24,000000000000001a000000000000001a,1.3e-322,3.6e-44,15,16,00000000000000220000000000000024,1.8e-322,5e-44,36,20,0000000000000015000000000000002c,2.17e-322,6.4e-44,46,46,0000000000000019000000000000001a,1.3e-322,7.6e-44,56,56,0000000000000038000000000000001e,1.5e-322,4.3e-44,64,66,00000000000000420000000000000042,3.26e-322,4.9e-44,36,74,000000000000004c000000000000004c,3.75e-322,1.06e-43,40,41,00000000000000540000000000000056,4.25e-322,1.2e-43,86,45,000000000000002e000000000000005e,4.64e-322,1.35e-43,96,96,00000000000000320000000000000033,2.5e-322,1.46e-43,106,106,000000000000006a0000000000000037,2.7e-322,7.8e-44,114,116,00000000000000740000000000000074,5.73e-322,8.4e-44,61,124,000000000000007e000000000000007e,6.23e-322,1.77e-43,65,66,00000000000000860000000000000088,6.7e-322,1.9e-43,136,70,00000000000000470000000000000090,7.1e-322,2.05e-43,146,146,000000000000004b000000000000004c,3.75e-322,2.16e-43,156,156,000000000000009c0000000000000050,3.95e-322,1.14e-43,164,166)
  1904  `, "\n"+buf.String())
  1905  
  1906  	exp := []uint64{
  1907  		0x0, 0x1, 0x4, 0x6, 0x6, 0x6, 0x5, 0x6, 0xe, 0x10, 0x10, 0x10, 0xa,
  1908  		0xb, 0x18, 0x1a, 0x1a, 0x1a, 0xf, 0x10, 0x22, 0x24, 0x24, 0x24, 0x14,
  1909  		0x15, 0x2c, 0x2e, 0x2e, 0x2e, 0x19, 0x1a, 0x36, 0x38, 0x38, 0x38, 0x1e,
  1910  		0x1f, 0x40, 0x42, 0x42, 0x42, 0x23, 0x24, 0x4a, 0x4c, 0x4c, 0x4c, 0x28,
  1911  		0x29, 0x54, 0x56, 0x56, 0x56, 0x2d, 0x2e, 0x5e, 0x60, 0x60, 0x60, 0x32,
  1912  		0x33, 0x68, 0x6a, 0x6a, 0x6a, 0x37, 0x38, 0x72, 0x74, 0x74, 0x74, 0x3c,
  1913  		0x3d, 0x7c, 0x7e, 0x7e, 0x7e, 0x41, 0x42, 0x86, 0x88, 0x88, 0x88, 0x46,
  1914  		0x47, 0x90, 0x92, 0x92, 0x92, 0x4b, 0x4c, 0x9a, 0x9c, 0x9c, 0x9c, 0x50,
  1915  		0x51, 0xa4, 0xa6, 0xa6, 0xa6, 0x55, 0x56, 0xae, 0xb0, 0xb0, 0xb0, 0x5a,
  1916  		0x5b, 0xb8, 0xba, 0xba, 0xba, 0x5f, 0x60, 0xc2, 0xc4, 0xc4, 0xc4,
  1917  	}
  1918  	require.Equal(t, exp, results)
  1919  }
  1920  
  1921  func testManyParamsResultsSwapper(t *testing.T, r wazero.Runtime) {
  1922  	ctx := context.Background()
  1923  
  1924  	bin, params := manyParamsResultsMod()
  1925  	mod, err := r.Instantiate(ctx, bin)
  1926  	require.NoError(t, err)
  1927  
  1928  	main := mod.ExportedFunction("swapper")
  1929  	require.NotNil(t, main)
  1930  
  1931  	results, err := main.Call(ctx, params...)
  1932  	require.NoError(t, err)
  1933  
  1934  	exp := []uint64{
  1935  		0x62, 0x62, 0x62, 0x61, 0x60, 0x5f, 0x5d, 0x5d, 0x5d, 0x5c, 0x5b, 0x5a, 0x58, 0x58, 0x58, 0x57,
  1936  		0x56, 0x55, 0x53, 0x53, 0x53, 0x52, 0x51, 0x50, 0x4e, 0x4e, 0x4e, 0x4d, 0x4c, 0x4b, 0x49, 0x49,
  1937  		0x49, 0x48, 0x47, 0x46, 0x44, 0x44, 0x44, 0x43, 0x42, 0x41, 0x3f, 0x3f, 0x3f, 0x3e, 0x3d, 0x3c,
  1938  		0x3a, 0x3a, 0x3a, 0x39, 0x38, 0x37, 0x35, 0x35, 0x35, 0x34, 0x33, 0x32, 0x30, 0x30, 0x30, 0x2f,
  1939  		0x2e, 0x2d, 0x2b, 0x2b, 0x2b, 0x2a, 0x29, 0x28, 0x26, 0x26, 0x26, 0x25, 0x24, 0x23, 0x21, 0x21,
  1940  		0x21, 0x20, 0x1f, 0x1e, 0x1c, 0x1c, 0x1c, 0x1b, 0x1a, 0x19, 0x17, 0x17, 0x17, 0x16, 0x15, 0x14,
  1941  		0x12, 0x12, 0x12, 0x11, 0x10, 0xf, 0xd, 0xd, 0xd, 0xc, 0xb, 0xa, 0x8, 0x8, 0x8, 0x7, 0x6, 0x5,
  1942  		0x3, 0x3, 0x3, 0x2, 0x1, 0x0,
  1943  	}
  1944  	require.Equal(t, exp, results)
  1945  }
  1946  
  1947  func testManyParamsResultsSwapperListener(t *testing.T, r wazero.Runtime) {
  1948  	var buf bytes.Buffer
  1949  	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
  1950  
  1951  	bin, params := manyParamsResultsMod()
  1952  	mod, err := r.Instantiate(ctx, bin)
  1953  	require.NoError(t, err)
  1954  
  1955  	main := mod.ExportedFunction("swapper")
  1956  	require.NotNil(t, main)
  1957  
  1958  	results, err := main.Call(ctx, params...)
  1959  	require.NoError(t, err)
  1960  
  1961  	fmt.Println(buf.String())
  1962  	require.Equal(t, `
  1963  --> .swapper([0:i32]=0,[1:i64]=1,[2:f32]=3e-45,[3:f64]=1.5e-323,[4:v128]=00000000000000030000000000000003,[5:i32]=3,[6:i64]=5,[7:f32]=8e-45,[8:f64]=3.5e-323,[9:v128]=00000000000000080000000000000008,[10:i32]=8,[11:i64]=8,[12:f32]=1.4e-44,[13:f64]=5.4e-323,[14:v128]=000000000000000c000000000000000d,[15:i32]=13,[16:i64]=13,[17:f32]=1.8e-44,[18:f64]=7.4e-323,[19:v128]=00000000000000100000000000000011,[20:i32]=17,[21:i64]=18,[22:f32]=2.5e-44,[23:f64]=9e-323,[24:v128]=00000000000000140000000000000015,[25:i32]=21,[26:i64]=22,[27:f32]=3.2e-44,[28:f64]=1.14e-322,[29:v128]=00000000000000170000000000000019,[30:i32]=25,[31:i64]=26,[32:f32]=3.8e-44,[33:f64]=1.4e-322,[34:v128]=000000000000001c000000000000001c,[35:i32]=28,[36:i64]=30,[37:f32]=4.3e-44,[38:f64]=1.6e-322,[39:v128]=00000000000000210000000000000021,[40:i32]=33,[41:i64]=33,[42:f32]=4.9e-44,[43:f64]=1.8e-322,[44:v128]=00000000000000250000000000000026,[45:i32]=38,[46:i64]=38,[47:f32]=5.3e-44,[48:f64]=2e-322,[49:v128]=0000000000000029000000000000002a,[50:i32]=42,[51:i64]=43,[52:f32]=6e-44,[53:f64]=2.1e-322,[54:v128]=000000000000002d000000000000002e,[55:i32]=46,[56:i64]=47,[57:f32]=6.7e-44,[58:f64]=2.37e-322,[59:v128]=00000000000000300000000000000032,[60:i32]=50,[61:i64]=51,[62:f32]=7.3e-44,[63:f64]=2.6e-322,[64:v128]=00000000000000350000000000000035,[65:i32]=53,[66:i64]=55,[67:f32]=7.8e-44,[68:f64]=2.8e-322,[69:v128]=000000000000003a000000000000003a,[70:i32]=58,[71:i64]=58,[72:f32]=8.4e-44,[73:f64]=3e-322,[74:v128]=000000000000003e000000000000003f,[75:i32]=63,[76:i64]=63,[77:f32]=8.8e-44,[78:f64]=3.2e-322,[79:v128]=00000000000000420000000000000043,[80:i32]=67,[81:i64]=68,[82:f32]=9.5e-44,[83:f64]=3.36e-322,[84:v128]=00000000000000460000000000000047,[85:i32]=71,[86:i64]=72,[87:f32]=1.02e-43,[88:f64]=3.6e-322,[89:v128]=0000000000000049000000000000004b,[90:i32]=75,[91:i64]=76,[92:f32]=1.08e-43,[93:f64]=3.85e-322,[94:v128]=000000000000004e000000000000004e,[95:i32]=78,[96:i64]=80,[97:f32]=1.14e-43,[98:f64]=4.05e-322,[99:v128]=00000000000000530000000000000053)
  1964  <-- (00000000000000620000000000000062,4.84e-322,1.37e-43,97,96,000000000000005f000000000000005d,4.6e-322,1.3e-43,93,92,000000000000005b000000000000005a,4.45e-322,1.23e-43,88,88,00000000000000570000000000000056,4.25e-322,1.19e-43,83,83,00000000000000530000000000000052,4.05e-322,1.14e-43,80,78,000000000000004e000000000000004e,3.85e-322,1.08e-43,76,75,00000000000000490000000000000049,3.6e-322,1.02e-43,72,71,00000000000000460000000000000044,3.36e-322,9.5e-44,68,67,00000000000000420000000000000041,3.2e-322,8.8e-44,63,63,000000000000003e000000000000003d,3e-322,8.4e-44,58,58,000000000000003a0000000000000039,2.8e-322,7.8e-44,55,53,00000000000000350000000000000035,2.6e-322,7.3e-44,51,50,00000000000000300000000000000030,2.37e-322,6.7e-44,47,46,000000000000002d000000000000002b,2.1e-322,6e-44,43,42,00000000000000290000000000000028,2e-322,5.3e-44,38,38,00000000000000250000000000000024,1.8e-322,4.9e-44,33,33,00000000000000210000000000000020,1.6e-322,4.3e-44,30,28,000000000000001c000000000000001c,1.4e-322,3.8e-44,26,25,00000000000000170000000000000017,1.14e-322,3.2e-44,22,21,00000000000000140000000000000012,9e-323,2.5e-44,18,17)
  1965  `, "\n"+buf.String())
  1966  
  1967  	exp := []uint64{
  1968  		0x62, 0x62, 0x62, 0x61, 0x60, 0x5f, 0x5d, 0x5d, 0x5d, 0x5c, 0x5b, 0x5a, 0x58, 0x58, 0x58, 0x57,
  1969  		0x56, 0x55, 0x53, 0x53, 0x53, 0x52, 0x51, 0x50, 0x4e, 0x4e, 0x4e, 0x4d, 0x4c, 0x4b, 0x49, 0x49,
  1970  		0x49, 0x48, 0x47, 0x46, 0x44, 0x44, 0x44, 0x43, 0x42, 0x41, 0x3f, 0x3f, 0x3f, 0x3e, 0x3d, 0x3c,
  1971  		0x3a, 0x3a, 0x3a, 0x39, 0x38, 0x37, 0x35, 0x35, 0x35, 0x34, 0x33, 0x32, 0x30, 0x30, 0x30, 0x2f,
  1972  		0x2e, 0x2d, 0x2b, 0x2b, 0x2b, 0x2a, 0x29, 0x28, 0x26, 0x26, 0x26, 0x25, 0x24, 0x23, 0x21, 0x21,
  1973  		0x21, 0x20, 0x1f, 0x1e, 0x1c, 0x1c, 0x1c, 0x1b, 0x1a, 0x19, 0x17, 0x17, 0x17, 0x16, 0x15, 0x14,
  1974  		0x12, 0x12, 0x12, 0x11, 0x10, 0xf, 0xd, 0xd, 0xd, 0xc, 0xb, 0xa, 0x8, 0x8, 0x8, 0x7, 0x6, 0x5,
  1975  		0x3, 0x3, 0x3, 0x2, 0x1, 0x0,
  1976  	}
  1977  	require.Equal(t, exp, results)
  1978  }
  1979  
  1980  func testManyParamsResultsMain(t *testing.T, r wazero.Runtime) {
  1981  	ctx := context.Background()
  1982  
  1983  	bin, params := manyParamsResultsMod()
  1984  	mod, err := r.Instantiate(ctx, bin)
  1985  	require.NoError(t, err)
  1986  
  1987  	main := mod.ExportedFunction("main")
  1988  	require.NotNil(t, main)
  1989  
  1990  	results, err := main.Call(ctx, params...)
  1991  	require.NoError(t, err)
  1992  
  1993  	exp := []uint64{
  1994  		98, 98, 196, 194, 192, 190, 93, 93, 186, 184, 182, 180, 88, 88, 176, 174, 172, 170, 83, 83, 166, 164, 162,
  1995  		160, 78, 78, 156, 154, 152, 150, 73, 73, 146, 144, 142, 140, 68, 68, 136, 134, 132, 130, 63, 63, 126, 124,
  1996  		122, 120, 58, 58, 116, 114, 112, 110, 53, 53, 106, 104, 102, 100, 48, 48, 96, 94, 92, 90, 43, 43, 86, 84,
  1997  		82, 80, 38, 38, 76, 74, 72, 70, 33, 33, 66, 64, 62, 60, 28, 28, 56, 54, 52, 50, 23, 23, 46, 44, 42, 40, 18,
  1998  		18, 36, 34, 32, 30, 13, 13, 26, 24, 22, 20, 8, 8, 16, 14, 12, 10, 3, 3, 6, 4, 2, 0,
  1999  	}
  2000  	require.Equal(t, exp, results)
  2001  }
  2002  
  2003  func testManyParamsResultsMainListener(t *testing.T, r wazero.Runtime) {
  2004  	var buf bytes.Buffer
  2005  	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
  2006  
  2007  	bin, params := manyParamsResultsMod()
  2008  	mod, err := r.Instantiate(ctx, bin)
  2009  	require.NoError(t, err)
  2010  
  2011  	main := mod.ExportedFunction("main")
  2012  	require.NotNil(t, main)
  2013  
  2014  	results, err := main.Call(ctx, params...)
  2015  	require.NoError(t, err)
  2016  
  2017  	fmt.Println(buf.String())
  2018  	require.Equal(t, `
  2019  --> .main([0:i32]=0,[1:i64]=1,[2:f32]=3e-45,[3:f64]=1.5e-323,[4:v128]=00000000000000030000000000000003,[5:i32]=3,[6:i64]=5,[7:f32]=8e-45,[8:f64]=3.5e-323,[9:v128]=00000000000000080000000000000008,[10:i32]=8,[11:i64]=8,[12:f32]=1.4e-44,[13:f64]=5.4e-323,[14:v128]=000000000000000c000000000000000d,[15:i32]=13,[16:i64]=13,[17:f32]=1.8e-44,[18:f64]=7.4e-323,[19:v128]=00000000000000100000000000000011,[20:i32]=17,[21:i64]=18,[22:f32]=2.5e-44,[23:f64]=9e-323,[24:v128]=00000000000000140000000000000015,[25:i32]=21,[26:i64]=22,[27:f32]=3.2e-44,[28:f64]=1.14e-322,[29:v128]=00000000000000170000000000000019,[30:i32]=25,[31:i64]=26,[32:f32]=3.8e-44,[33:f64]=1.4e-322,[34:v128]=000000000000001c000000000000001c,[35:i32]=28,[36:i64]=30,[37:f32]=4.3e-44,[38:f64]=1.6e-322,[39:v128]=00000000000000210000000000000021,[40:i32]=33,[41:i64]=33,[42:f32]=4.9e-44,[43:f64]=1.8e-322,[44:v128]=00000000000000250000000000000026,[45:i32]=38,[46:i64]=38,[47:f32]=5.3e-44,[48:f64]=2e-322,[49:v128]=0000000000000029000000000000002a,[50:i32]=42,[51:i64]=43,[52:f32]=6e-44,[53:f64]=2.1e-322,[54:v128]=000000000000002d000000000000002e,[55:i32]=46,[56:i64]=47,[57:f32]=6.7e-44,[58:f64]=2.37e-322,[59:v128]=00000000000000300000000000000032,[60:i32]=50,[61:i64]=51,[62:f32]=7.3e-44,[63:f64]=2.6e-322,[64:v128]=00000000000000350000000000000035,[65:i32]=53,[66:i64]=55,[67:f32]=7.8e-44,[68:f64]=2.8e-322,[69:v128]=000000000000003a000000000000003a,[70:i32]=58,[71:i64]=58,[72:f32]=8.4e-44,[73:f64]=3e-322,[74:v128]=000000000000003e000000000000003f,[75:i32]=63,[76:i64]=63,[77:f32]=8.8e-44,[78:f64]=3.2e-322,[79:v128]=00000000000000420000000000000043,[80:i32]=67,[81:i64]=68,[82:f32]=9.5e-44,[83:f64]=3.36e-322,[84:v128]=00000000000000460000000000000047,[85:i32]=71,[86:i64]=72,[87:f32]=1.02e-43,[88:f64]=3.6e-322,[89:v128]=0000000000000049000000000000004b,[90:i32]=75,[91:i64]=76,[92:f32]=1.08e-43,[93:f64]=3.85e-322,[94:v128]=000000000000004e000000000000004e,[95:i32]=78,[96:i64]=80,[97:f32]=1.14e-43,[98:f64]=4.05e-322,[99:v128]=00000000000000530000000000000053)
  2020  	--> .swapper([0:i32]=0,[1:i64]=1,[2:f32]=3e-45,[3:f64]=1.5e-323,[4:v128]=00000000000000030000000000000003,[5:i32]=3,[6:i64]=5,[7:f32]=8e-45,[8:f64]=3.5e-323,[9:v128]=00000000000000080000000000000008,[10:i32]=8,[11:i64]=8,[12:f32]=1.4e-44,[13:f64]=5.4e-323,[14:v128]=000000000000000c000000000000000d,[15:i32]=13,[16:i64]=13,[17:f32]=1.8e-44,[18:f64]=7.4e-323,[19:v128]=00000000000000100000000000000011,[20:i32]=17,[21:i64]=18,[22:f32]=2.5e-44,[23:f64]=9e-323,[24:v128]=00000000000000140000000000000015,[25:i32]=21,[26:i64]=22,[27:f32]=3.2e-44,[28:f64]=1.14e-322,[29:v128]=00000000000000170000000000000019,[30:i32]=25,[31:i64]=26,[32:f32]=3.8e-44,[33:f64]=1.4e-322,[34:v128]=000000000000001c000000000000001c,[35:i32]=28,[36:i64]=30,[37:f32]=4.3e-44,[38:f64]=1.6e-322,[39:v128]=00000000000000210000000000000021,[40:i32]=33,[41:i64]=33,[42:f32]=4.9e-44,[43:f64]=1.8e-322,[44:v128]=00000000000000250000000000000026,[45:i32]=38,[46:i64]=38,[47:f32]=5.3e-44,[48:f64]=2e-322,[49:v128]=0000000000000029000000000000002a,[50:i32]=42,[51:i64]=43,[52:f32]=6e-44,[53:f64]=2.1e-322,[54:v128]=000000000000002d000000000000002e,[55:i32]=46,[56:i64]=47,[57:f32]=6.7e-44,[58:f64]=2.37e-322,[59:v128]=00000000000000300000000000000032,[60:i32]=50,[61:i64]=51,[62:f32]=7.3e-44,[63:f64]=2.6e-322,[64:v128]=00000000000000350000000000000035,[65:i32]=53,[66:i64]=55,[67:f32]=7.8e-44,[68:f64]=2.8e-322,[69:v128]=000000000000003a000000000000003a,[70:i32]=58,[71:i64]=58,[72:f32]=8.4e-44,[73:f64]=3e-322,[74:v128]=000000000000003e000000000000003f,[75:i32]=63,[76:i64]=63,[77:f32]=8.8e-44,[78:f64]=3.2e-322,[79:v128]=00000000000000420000000000000043,[80:i32]=67,[81:i64]=68,[82:f32]=9.5e-44,[83:f64]=3.36e-322,[84:v128]=00000000000000460000000000000047,[85:i32]=71,[86:i64]=72,[87:f32]=1.02e-43,[88:f64]=3.6e-322,[89:v128]=0000000000000049000000000000004b,[90:i32]=75,[91:i64]=76,[92:f32]=1.08e-43,[93:f64]=3.85e-322,[94:v128]=000000000000004e000000000000004e,[95:i32]=78,[96:i64]=80,[97:f32]=1.14e-43,[98:f64]=4.05e-322,[99:v128]=00000000000000530000000000000053)
  2021  	<-- (00000000000000620000000000000062,4.84e-322,1.37e-43,97,96,000000000000005f000000000000005d,4.6e-322,1.3e-43,93,92,000000000000005b000000000000005a,4.45e-322,1.23e-43,88,88,00000000000000570000000000000056,4.25e-322,1.19e-43,83,83,00000000000000530000000000000052,4.05e-322,1.14e-43,80,78,000000000000004e000000000000004e,3.85e-322,1.08e-43,76,75,00000000000000490000000000000049,3.6e-322,1.02e-43,72,71,00000000000000460000000000000044,3.36e-322,9.5e-44,68,67,00000000000000420000000000000041,3.2e-322,8.8e-44,63,63,000000000000003e000000000000003d,3e-322,8.4e-44,58,58,000000000000003a0000000000000039,2.8e-322,7.8e-44,55,53,00000000000000350000000000000035,2.6e-322,7.3e-44,51,50,00000000000000300000000000000030,2.37e-322,6.7e-44,47,46,000000000000002d000000000000002b,2.1e-322,6e-44,43,42,00000000000000290000000000000028,2e-322,5.3e-44,38,38,00000000000000250000000000000024,1.8e-322,4.9e-44,33,33,00000000000000210000000000000020,1.6e-322,4.3e-44,30,28,000000000000001c000000000000001c,1.4e-322,3.8e-44,26,25,00000000000000170000000000000017,1.14e-322,3.2e-44,22,21,00000000000000140000000000000012,9e-323,2.5e-44,18,17)
  2022  	--> .doubler([0:v128]=00000000000000620000000000000062,[1:f64]=4.84e-322,[2:f32]=1.37e-43,[3:i64]=97,[4:i32]=96,[5:v128]=000000000000005f000000000000005d,[6:f64]=4.6e-322,[7:f32]=1.3e-43,[8:i64]=93,[9:i32]=92,[10:v128]=000000000000005b000000000000005a,[11:f64]=4.45e-322,[12:f32]=1.23e-43,[13:i64]=88,[14:i32]=88,[15:v128]=00000000000000570000000000000056,[16:f64]=4.25e-322,[17:f32]=1.19e-43,[18:i64]=83,[19:i32]=83,[20:v128]=00000000000000530000000000000052,[21:f64]=4.05e-322,[22:f32]=1.14e-43,[23:i64]=80,[24:i32]=78,[25:v128]=000000000000004e000000000000004e,[26:f64]=3.85e-322,[27:f32]=1.08e-43,[28:i64]=76,[29:i32]=75,[30:v128]=00000000000000490000000000000049,[31:f64]=3.6e-322,[32:f32]=1.02e-43,[33:i64]=72,[34:i32]=71,[35:v128]=00000000000000460000000000000044,[36:f64]=3.36e-322,[37:f32]=9.5e-44,[38:i64]=68,[39:i32]=67,[40:v128]=00000000000000420000000000000041,[41:f64]=3.2e-322,[42:f32]=8.8e-44,[43:i64]=63,[44:i32]=63,[45:v128]=000000000000003e000000000000003d,[46:f64]=3e-322,[47:f32]=8.4e-44,[48:i64]=58,[49:i32]=58,[50:v128]=000000000000003a0000000000000039,[51:f64]=2.8e-322,[52:f32]=7.8e-44,[53:i64]=55,[54:i32]=53,[55:v128]=00000000000000350000000000000035,[56:f64]=2.6e-322,[57:f32]=7.3e-44,[58:i64]=51,[59:i32]=50,[60:v128]=00000000000000300000000000000030,[61:f64]=2.37e-322,[62:f32]=6.7e-44,[63:i64]=47,[64:i32]=46,[65:v128]=000000000000002d000000000000002b,[66:f64]=2.1e-322,[67:f32]=6e-44,[68:i64]=43,[69:i32]=42,[70:v128]=00000000000000290000000000000028,[71:f64]=2e-322,[72:f32]=5.3e-44,[73:i64]=38,[74:i32]=38,[75:v128]=00000000000000250000000000000024,[76:f64]=1.8e-322,[77:f32]=4.9e-44,[78:i64]=33,[79:i32]=33,[80:v128]=00000000000000210000000000000020,[81:f64]=1.6e-322,[82:f32]=4.3e-44,[83:i64]=30,[84:i32]=28,[85:v128]=000000000000001c000000000000001c,[86:f64]=1.4e-322,[87:f32]=3.8e-44,[88:i64]=26,[89:i32]=25,[90:v128]=00000000000000170000000000000017,[91:f64]=1.14e-322,[92:f32]=3.2e-44,[93:i64]=22,[94:i32]=21,[95:v128]=00000000000000140000000000000012,[96:f64]=9e-323,[97:f32]=2.5e-44,[98:i64]=18,[99:i32]=17)
  2023  	<-- (00000000000000620000000000000062,4.84e-322,2.75e-43,194,192,00000000000000be000000000000005d,4.6e-322,1.3e-43,186,184,00000000000000b600000000000000b4,8.9e-322,1.23e-43,88,176,00000000000000ae00000000000000ac,8.5e-322,2.38e-43,83,83,00000000000000a600000000000000a4,8.1e-322,2.27e-43,160,78,000000000000004e000000000000009c,7.7e-322,2.16e-43,152,150,00000000000000490000000000000049,3.6e-322,2.05e-43,144,142,000000000000008c0000000000000044,3.36e-322,9.5e-44,136,134,00000000000000840000000000000082,6.4e-322,8.8e-44,63,126,000000000000007c000000000000007a,6.03e-322,1.68e-43,58,58,00000000000000740000000000000072,5.63e-322,1.57e-43,110,53,0000000000000035000000000000006a,5.24e-322,1.46e-43,102,100,00000000000000300000000000000030,2.37e-322,1.35e-43,94,92,000000000000005a000000000000002b,2.1e-322,6e-44,86,84,00000000000000520000000000000050,3.95e-322,5.3e-44,38,76,000000000000004a0000000000000048,3.56e-322,9.8e-44,33,33,00000000000000420000000000000040,3.16e-322,8.7e-44,60,28,000000000000001c0000000000000038,2.77e-322,7.6e-44,52,50,00000000000000170000000000000017,1.14e-322,6.4e-44,44,42,00000000000000280000000000000012,9e-323,2.5e-44,36,34)
  2024  <-- (00000000000000620000000000000062,4.84e-322,2.75e-43,194,192,00000000000000be000000000000005d,4.6e-322,1.3e-43,186,184,00000000000000b600000000000000b4,8.9e-322,1.23e-43,88,176,00000000000000ae00000000000000ac,8.5e-322,2.38e-43,83,83,00000000000000a600000000000000a4,8.1e-322,2.27e-43,160,78,000000000000004e000000000000009c,7.7e-322,2.16e-43,152,150,00000000000000490000000000000049,3.6e-322,2.05e-43,144,142,000000000000008c0000000000000044,3.36e-322,9.5e-44,136,134,00000000000000840000000000000082,6.4e-322,8.8e-44,63,126,000000000000007c000000000000007a,6.03e-322,1.68e-43,58,58,00000000000000740000000000000072,5.63e-322,1.57e-43,110,53,0000000000000035000000000000006a,5.24e-322,1.46e-43,102,100,00000000000000300000000000000030,2.37e-322,1.35e-43,94,92,000000000000005a000000000000002b,2.1e-322,6e-44,86,84,00000000000000520000000000000050,3.95e-322,5.3e-44,38,76,000000000000004a0000000000000048,3.56e-322,9.8e-44,33,33,00000000000000420000000000000040,3.16e-322,8.7e-44,60,28,000000000000001c0000000000000038,2.77e-322,7.6e-44,52,50,00000000000000170000000000000017,1.14e-322,6.4e-44,44,42,00000000000000280000000000000012,9e-323,2.5e-44,36,34)
  2025  `, "\n"+buf.String())
  2026  
  2027  	exp := []uint64{
  2028  		98, 98, 196, 194, 192, 190, 93, 93, 186, 184, 182, 180, 88, 88, 176, 174, 172, 170, 83, 83, 166, 164, 162,
  2029  		160, 78, 78, 156, 154, 152, 150, 73, 73, 146, 144, 142, 140, 68, 68, 136, 134, 132, 130, 63, 63, 126, 124,
  2030  		122, 120, 58, 58, 116, 114, 112, 110, 53, 53, 106, 104, 102, 100, 48, 48, 96, 94, 92, 90, 43, 43, 86, 84,
  2031  		82, 80, 38, 38, 76, 74, 72, 70, 33, 33, 66, 64, 62, 60, 28, 28, 56, 54, 52, 50, 23, 23, 46, 44, 42, 40, 18,
  2032  		18, 36, 34, 32, 30, 13, 13, 26, 24, 22, 20, 8, 8, 16, 14, 12, 10, 3, 3, 6, 4, 2, 0,
  2033  	}
  2034  	require.Equal(t, exp, results)
  2035  }
  2036  
  2037  func testManyParamsResultsCallManyConstsAndPickLastVector(t *testing.T, r wazero.Runtime) {
  2038  	ctx := context.Background()
  2039  
  2040  	bin, _ := manyParamsResultsMod()
  2041  	mod, err := r.Instantiate(ctx, bin)
  2042  	require.NoError(t, err)
  2043  
  2044  	main := mod.ExportedFunction("call_many_consts_and_pick_last_vector")
  2045  	require.NotNil(t, main)
  2046  
  2047  	results, err := main.Call(ctx)
  2048  	require.NoError(t, err)
  2049  	exp := []uint64{0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f}
  2050  	require.Equal(t, exp, results)
  2051  }
  2052  
  2053  func testManyParamsResultsCallManyConstsAndPickLastVectorListener(t *testing.T, r wazero.Runtime) {
  2054  	var buf bytes.Buffer
  2055  	ctx := context.WithValue(context.Background(), experimental.FunctionListenerFactoryKey{}, logging.NewLoggingListenerFactory(&buf))
  2056  
  2057  	bin, _ := manyParamsResultsMod()
  2058  	mod, err := r.Instantiate(ctx, bin)
  2059  	require.NoError(t, err)
  2060  
  2061  	main := mod.ExportedFunction("call_many_consts_and_pick_last_vector")
  2062  	require.NotNil(t, main)
  2063  
  2064  	results, err := main.Call(ctx)
  2065  	require.NoError(t, err)
  2066  	exp := []uint64{0x5f5f5f5f5f5f5f5f, 0x5f5f5f5f5f5f5f5f}
  2067  	require.Equal(t, exp, results)
  2068  
  2069  	fmt.Println(buf.String())
  2070  	require.Equal(t, `
  2071  --> .call_many_consts_and_pick_last_vector()
  2072  	--> .many_consts()
  2073  	<-- (0,0,0,0,00000000000000000000000000000000,0,5,7e-45,4.16077606e-316,05050505050505050505050505050505,84215045,361700864190383365,1.4e-44,5e-323,000000000a0a0a0a0a0a0a0a0a0a0a0a,168430090,723401728380766730,6.6463464e-33,7.4e-323,000000000000000f000000000f0f0f0f,252645135,1085102592571150095,7.0533445e-30,3.815736827118017e-236,00000000000000140000000000000014,20,336860180,7.47605e-27,5.964208835435795e-212,14141414141414140000000000000019,25,25,7.914983e-24,9.01285756841504e-188,19191919191919191919191919191919,421075225,30,4.2e-44,2.496465636e-315,1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e,505290270,2170205185142300190,4.9e-44,1.73e-322,00000000232323232323232323232323,589505315,2531906049332683555,8.843688e-18,2e-322,00000000000000280000000028282828,673720360,2893606913523066920,9.334581e-15,3.0654356309538037e-115,000000000000002d000000000000002d,45,757935405,9.8439425e-12,4.4759381595361623e-91,2d2d2d2d2d2d2d2d0000000000000032,50,50,1.0372377e-08,6.749300603603778e-67,32323232323232323232323232323232,842150450,55,7.7e-44,4.576853666e-315,37373737373737373737373737373737,926365495,3978709506094217015,8.4e-44,2.96e-322,000000003c3c3c3c3c3c3c3c3c3c3c3c,1010580540,4340410370284600380,0.01148897,3.2e-322,00000000000000410000000041414141,1094795585,4702111234474983745,12.078431,2.2616345098039214e+06,00000000000000460000000000000046,70,1179010630,12689.568,3.5295369653413445e+30,4646464646464646000000000000004b,75,75,1.3323083e+07,5.2285141982483265e+54,4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b,1263225675,80,1.12e-43,6.657241696e-315,50505050505050505050505050505050)
  2074  	--> .pick_last_vector([0:i32]=0,[1:i64]=0,[2:f32]=0,[3:f64]=0,[4:v128]=00000000000000000000000000000000,[5:i32]=0,[6:i64]=5,[7:f32]=7e-45,[8:f64]=4.16077606e-316,[9:v128]=05050505050505050505050505050505,[10:i32]=84215045,[11:i64]=361700864190383365,[12:f32]=1.4e-44,[13:f64]=5e-323,[14:v128]=000000000a0a0a0a0a0a0a0a0a0a0a0a,[15:i32]=168430090,[16:i64]=723401728380766730,[17:f32]=6.6463464e-33,[18:f64]=7.4e-323,[19:v128]=000000000000000f000000000f0f0f0f,[20:i32]=252645135,[21:i64]=1085102592571150095,[22:f32]=7.0533445e-30,[23:f64]=3.815736827118017e-236,[24:v128]=00000000000000140000000000000014,[25:i32]=20,[26:i64]=336860180,[27:f32]=7.47605e-27,[28:f64]=5.964208835435795e-212,[29:v128]=14141414141414140000000000000019,[30:i32]=25,[31:i64]=25,[32:f32]=7.914983e-24,[33:f64]=9.01285756841504e-188,[34:v128]=19191919191919191919191919191919,[35:i32]=421075225,[36:i64]=30,[37:f32]=4.2e-44,[38:f64]=2.496465636e-315,[39:v128]=1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e,[40:i32]=505290270,[41:i64]=2170205185142300190,[42:f32]=4.9e-44,[43:f64]=1.73e-322,[44:v128]=00000000232323232323232323232323,[45:i32]=589505315,[46:i64]=2531906049332683555,[47:f32]=8.843688e-18,[48:f64]=2e-322,[49:v128]=00000000000000280000000028282828,[50:i32]=673720360,[51:i64]=2893606913523066920,[52:f32]=9.334581e-15,[53:f64]=3.0654356309538037e-115,[54:v128]=000000000000002d000000000000002d,[55:i32]=45,[56:i64]=757935405,[57:f32]=9.8439425e-12,[58:f64]=4.4759381595361623e-91,[59:v128]=2d2d2d2d2d2d2d2d0000000000000032,[60:i32]=50,[61:i64]=50,[62:f32]=1.0372377e-08,[63:f64]=6.749300603603778e-67,[64:v128]=32323232323232323232323232323232,[65:i32]=842150450,[66:i64]=55,[67:f32]=7.7e-44,[68:f64]=4.576853666e-315,[69:v128]=37373737373737373737373737373737,[70:i32]=926365495,[71:i64]=3978709506094217015,[72:f32]=8.4e-44,[73:f64]=2.96e-322,[74:v128]=000000003c3c3c3c3c3c3c3c3c3c3c3c,[75:i32]=1010580540,[76:i64]=4340410370284600380,[77:f32]=0.01148897,[78:f64]=3.2e-322,[79:v128]=00000000000000410000000041414141,[80:i32]=1094795585,[81:i64]=4702111234474983745,[82:f32]=12.078431,[83:f64]=2.2616345098039214e+06,[84:v128]=00000000000000460000000000000046,[85:i32]=70,[86:i64]=1179010630,[87:f32]=12689.568,[88:f64]=3.5295369653413445e+30,[89:v128]=4646464646464646000000000000004b,[90:i32]=75,[91:i64]=75,[92:f32]=1.3323083e+07,[93:f64]=5.2285141982483265e+54,[94:v128]=4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b,[95:i32]=1263225675,[96:i64]=80,[97:f32]=1.12e-43,[98:f64]=6.657241696e-315,[99:v128]=50505050505050505050505050505050)
  2075  	<-- 5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f
  2076  <-- 5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f
  2077  `, "\n"+buf.String())
  2078  }