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