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