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