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