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