1 package adhoc
2
3 import (
4 "context"
5 "runtime"
6 "sync"
7 "testing"
8
9 "github.com/tetratelabs/wazero"
10 "github.com/tetratelabs/wazero/api"
11 "github.com/tetratelabs/wazero/experimental/opt"
12 "github.com/tetratelabs/wazero/internal/platform"
13 "github.com/tetratelabs/wazero/internal/testing/hammer"
14 "github.com/tetratelabs/wazero/internal/testing/require"
15 "github.com/tetratelabs/wazero/sys"
16 )
17
18 var hammers = map[string]testCase{
19
20 "close importing module while in use": {f: closeImportingModuleWhileInUse},
21 "close imported module while in use": {f: closeImportedModuleWhileInUse},
22 }
23
24 func TestEngineCompiler_hammer(t *testing.T) {
25 if !platform.CompilerSupported() {
26 t.Skip()
27 }
28 runAllTests(t, hammers, wazero.NewRuntimeConfigCompiler(), false)
29 }
30
31 func TestEngineInterpreter_hammer(t *testing.T) {
32 runAllTests(t, hammers, wazero.NewRuntimeConfigInterpreter(), false)
33 }
34
35 func TestEngineWazevo_hammer(t *testing.T) {
36 if runtime.GOARCH != "arm64" {
37 t.Skip()
38 }
39 c := opt.NewRuntimeConfigOptimizingCompiler()
40 runAllTests(t, hammers, c, true)
41 }
42
43 func closeImportingModuleWhileInUse(t *testing.T, r wazero.Runtime) {
44 closeModuleWhileInUse(t, r, func(imported, importing api.Module) (api.Module, api.Module) {
45
46 require.NoError(t, importing.Close(testCtx))
47
48
49 binary := callReturnImportWasm(t, imported.Name(), importing.Name(), i32)
50 importing, err := r.Instantiate(testCtx, binary)
51 require.NoError(t, err)
52 return imported, importing
53 })
54 }
55
56 func closeImportedModuleWhileInUse(t *testing.T, r wazero.Runtime) {
57 closeModuleWhileInUse(t, r, func(imported, importing api.Module) (api.Module, api.Module) {
58
59 require.NoError(t, importing.Close(testCtx))
60 require.NoError(t, imported.Close(testCtx))
61
62
63 imported, err := r.NewHostModuleBuilder(imported.Name()).
64 NewFunctionBuilder().
65 WithFunc(func(ctx context.Context, x uint32) uint32 {
66 return x
67 }).
68 Export("return_input").
69 Instantiate(testCtx)
70 require.NoError(t, err)
71
72
73 binary := callReturnImportWasm(t, imported.Name(), importing.Name(), i32)
74 importing, err = r.Instantiate(testCtx, binary)
75 require.NoError(t, err)
76
77 return imported, importing
78 })
79 }
80
81 func closeModuleWhileInUse(t *testing.T, r wazero.Runtime, closeFn func(imported, importing api.Module) (api.Module, api.Module)) {
82 P := 8
83 if testing.Short() {
84 P = 4
85 }
86
87
88 var calls sync.WaitGroup
89 calls.Add(P)
90 blockAndReturn := func(ctx context.Context, x uint32) uint32 {
91 calls.Wait()
92 return x
93 }
94
95
96 imported, err := r.NewHostModuleBuilder(t.Name() + "-imported").
97 NewFunctionBuilder().WithFunc(blockAndReturn).Export("return_input").
98 Instantiate(testCtx)
99 require.NoError(t, err)
100 defer imported.Close(testCtx)
101
102
103 binary := callReturnImportWasm(t, imported.Name(), t.Name()+"-importing", i32)
104 importing, err := r.Instantiate(testCtx, binary)
105 require.NoError(t, err)
106 defer importing.Close(testCtx)
107
108
109 i := importing
110 hammer.NewHammer(t, P, 1).Run(func(name string) {
111
112 requireFunctionCallExits(t, i.ExportedFunction("call_return_input"))
113 }, func() {
114 imported, importing = closeFn(imported, importing)
115
116 calls.Add(-P)
117 })
118
119 defer imported.Close(testCtx)
120 defer importing.Close(testCtx)
121 if t.Failed() {
122 return
123 }
124
125
126 requireFunctionCall(t, importing.ExportedFunction("call_return_input"))
127 }
128
129 func requireFunctionCall(t *testing.T, fn api.Function) {
130 res, err := fn.Call(testCtx, 3)
131 require.NoError(t, err)
132 require.Equal(t, uint64(3), res[0])
133 }
134
135 func requireFunctionCallExits(t *testing.T, fn api.Function) {
136 _, err := fn.Call(testCtx, 3)
137 require.Equal(t, sys.NewExitError(0), err)
138 }
139
View as plain text