1 package wasm
2
3 import (
4 "context"
5 "math"
6 "testing"
7
8 "github.com/tetratelabs/wazero/api"
9 "github.com/tetratelabs/wazero/internal/internalapi"
10 "github.com/tetratelabs/wazero/internal/leb128"
11 "github.com/tetratelabs/wazero/internal/testing/require"
12 "github.com/tetratelabs/wazero/internal/u64"
13 )
14
15 func TestGlobalTypes(t *testing.T) {
16 tests := []struct {
17 name string
18 global api.Global
19 expectedType api.ValueType
20 expectedVal uint64
21 expectedString string
22 expectedMutable bool
23 }{
24 {
25 name: "i32 - immutable",
26 global: constantGlobal{g: &GlobalInstance{
27 Type: GlobalType{ValType: ValueTypeI32},
28 Val: 1,
29 }},
30 expectedType: ValueTypeI32,
31 expectedVal: 1,
32 expectedString: "global(1)",
33 },
34 {
35 name: "i32 - immutable - max",
36 global: constantGlobal{g: &GlobalInstance{
37 Type: GlobalType{ValType: ValueTypeI32},
38 Val: math.MaxInt32,
39 }},
40 expectedType: ValueTypeI32,
41 expectedVal: math.MaxInt32,
42 expectedString: "global(2147483647)",
43 },
44 {
45 name: "i64 - immutable",
46 global: constantGlobal{g: &GlobalInstance{
47 Type: GlobalType{ValType: ValueTypeI64},
48 Val: 1,
49 }},
50 expectedType: ValueTypeI64,
51 expectedVal: 1,
52 expectedString: "global(1)",
53 },
54 {
55 name: "i64 - immutable - max",
56 global: constantGlobal{g: &GlobalInstance{
57 Type: GlobalType{ValType: ValueTypeI64},
58 Val: math.MaxInt64,
59 }},
60 expectedType: ValueTypeI64,
61 expectedVal: math.MaxInt64,
62 expectedString: "global(9223372036854775807)",
63 },
64 {
65 name: "f32 - immutable",
66 global: constantGlobal{g: &GlobalInstance{
67 Type: GlobalType{ValType: ValueTypeF32},
68 Val: api.EncodeF32(1.0),
69 }},
70 expectedType: ValueTypeF32,
71 expectedVal: api.EncodeF32(1.0),
72 expectedString: "global(1.000000)",
73 },
74 {
75 name: "f32 - immutable - max",
76 global: constantGlobal{g: &GlobalInstance{
77 Type: GlobalType{ValType: ValueTypeF32},
78 Val: api.EncodeF32(math.MaxFloat32),
79 }},
80 expectedType: ValueTypeF32,
81 expectedVal: api.EncodeF32(math.MaxFloat32),
82 expectedString: "global(340282346638528859811704183484516925440.000000)",
83 },
84 {
85 name: "f64 - immutable",
86 global: constantGlobal{g: &GlobalInstance{
87 Type: GlobalType{ValType: ValueTypeF64},
88 Val: api.EncodeF64(1.0),
89 }},
90 expectedType: ValueTypeF64,
91 expectedVal: api.EncodeF64(1.0),
92 expectedString: "global(1.000000)",
93 },
94 {
95 name: "f64 - immutable - max",
96 global: constantGlobal{g: &GlobalInstance{
97 Type: GlobalType{ValType: ValueTypeF64},
98 Val: api.EncodeF64(math.MaxFloat64),
99 }},
100 expectedType: ValueTypeF64,
101 expectedVal: api.EncodeF64(math.MaxFloat64),
102 expectedString: "global(179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000)",
103 },
104 {
105 name: "i32 - mutable",
106 global: mutableGlobal{internalapi.WazeroOnlyType{}, &GlobalInstance{
107 Type: GlobalType{ValType: ValueTypeI32, Mutable: true},
108 Val: 1,
109 }},
110 expectedType: ValueTypeI32,
111 expectedVal: 1,
112 expectedString: "global(1)",
113 expectedMutable: true,
114 },
115 {
116 name: "i64 - mutable",
117 global: mutableGlobal{internalapi.WazeroOnlyType{}, &GlobalInstance{
118 Type: GlobalType{ValType: ValueTypeI64, Mutable: true},
119 Val: 1,
120 }},
121 expectedType: ValueTypeI64,
122 expectedVal: 1,
123 expectedString: "global(1)",
124 expectedMutable: true,
125 },
126 {
127 name: "f32 - mutable",
128 global: mutableGlobal{internalapi.WazeroOnlyType{}, &GlobalInstance{
129 Type: GlobalType{ValType: ValueTypeF32, Mutable: true},
130 Val: api.EncodeF32(1.0),
131 }},
132 expectedType: ValueTypeF32,
133 expectedVal: api.EncodeF32(1.0),
134 expectedString: "global(1.000000)",
135 expectedMutable: true,
136 },
137 {
138 name: "f64 - mutable",
139 global: mutableGlobal{internalapi.WazeroOnlyType{}, &GlobalInstance{
140 Type: GlobalType{ValType: ValueTypeF64, Mutable: true},
141 Val: api.EncodeF64(1.0),
142 }},
143 expectedType: ValueTypeF64,
144 expectedVal: api.EncodeF64(1.0),
145 expectedString: "global(1.000000)",
146 expectedMutable: true,
147 },
148 }
149
150 for _, tt := range tests {
151 tc := tt
152
153 t.Run(tc.name, func(t *testing.T) {
154 require.Equal(t, tc.expectedType, tc.global.Type())
155 require.Equal(t, tc.expectedVal, tc.global.Get())
156 require.Equal(t, tc.expectedString, tc.global.String())
157
158 mutable, ok := tc.global.(api.MutableGlobal)
159 require.Equal(t, tc.expectedMutable, ok)
160 if ok {
161 mutable.Set(2)
162 require.Equal(t, uint64(2), tc.global.Get())
163
164 mutable.Set(tc.expectedVal)
165 require.Equal(t, tc.expectedVal, tc.global.Get())
166 }
167 })
168 }
169 }
170
171 func TestPublicModule_Global(t *testing.T) {
172 tests := []struct {
173 name string
174 module *Module
175 expected api.Global
176 }{
177 {
178 name: "no global",
179 module: &Module{},
180 },
181 {
182 name: "global not exported",
183 module: &Module{
184 GlobalSection: []Global{
185 {
186 Type: GlobalType{ValType: ValueTypeI32},
187 Init: ConstantExpression{Opcode: OpcodeI32Const, Data: const1},
188 },
189 },
190 },
191 },
192 {
193 name: "global exported - immutable I32",
194 module: &Module{
195 GlobalSection: []Global{
196 {
197 Type: GlobalType{ValType: ValueTypeI32},
198 Init: ConstantExpression{Opcode: OpcodeI32Const, Data: const1},
199 },
200 },
201 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}},
202 },
203 expected: constantGlobal{g: &GlobalInstance{
204 Type: GlobalType{ValType: ValueTypeI32},
205 Val: 1,
206 }},
207 },
208 {
209 name: "global exported - immutable I64",
210 module: &Module{
211 GlobalSection: []Global{
212 {
213 Type: GlobalType{ValType: ValueTypeI64},
214 Init: ConstantExpression{Opcode: OpcodeI64Const, Data: leb128.EncodeInt64(1)},
215 },
216 },
217 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}},
218 },
219 expected: constantGlobal{g: &GlobalInstance{
220 Type: GlobalType{ValType: ValueTypeI64},
221 Val: 1,
222 }},
223 },
224 {
225 name: "global exported - immutable F32",
226 module: &Module{
227 GlobalSection: []Global{
228 {
229 Type: GlobalType{ValType: ValueTypeF32},
230 Init: ConstantExpression{
231 Opcode: OpcodeF32Const,
232 Data: u64.LeBytes(api.EncodeF32(1.0)),
233 },
234 },
235 },
236 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}},
237 },
238 expected: constantGlobal{g: &GlobalInstance{
239 Type: GlobalType{ValType: ValueTypeF32},
240 Val: api.EncodeF32(1.0),
241 }},
242 },
243 {
244 name: "global exported - immutable F64",
245 module: &Module{
246 GlobalSection: []Global{
247 {
248 Type: GlobalType{ValType: ValueTypeF64},
249 Init: ConstantExpression{
250 Opcode: OpcodeF64Const,
251 Data: u64.LeBytes(api.EncodeF64(1.0)),
252 },
253 },
254 },
255 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}},
256 },
257 expected: constantGlobal{g: &GlobalInstance{
258 Type: GlobalType{ValType: ValueTypeF64},
259 Val: api.EncodeF64(1.0),
260 }},
261 },
262 {
263 name: "global exported - mutable I32",
264 module: &Module{
265 GlobalSection: []Global{
266 {
267 Type: GlobalType{ValType: ValueTypeI32, Mutable: true},
268 Init: ConstantExpression{Opcode: OpcodeI32Const, Data: leb128.EncodeInt32(1)},
269 },
270 },
271 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}},
272 },
273 expected: mutableGlobal{
274 internalapi.WazeroOnlyType{}, &GlobalInstance{
275 Type: GlobalType{ValType: ValueTypeI32, Mutable: true}, Val: 1,
276 },
277 },
278 },
279 {
280 name: "global exported - mutable I64",
281 module: &Module{
282 GlobalSection: []Global{
283 {
284 Type: GlobalType{ValType: ValueTypeI64, Mutable: true},
285 Init: ConstantExpression{Opcode: OpcodeI64Const, Data: leb128.EncodeInt64(1)},
286 },
287 },
288 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}},
289 },
290 expected: mutableGlobal{
291 internalapi.WazeroOnlyType{}, &GlobalInstance{
292 Type: GlobalType{ValType: ValueTypeI64, Mutable: true}, Val: 1,
293 },
294 },
295 },
296 {
297 name: "global exported - mutable F32",
298 module: &Module{
299 GlobalSection: []Global{
300 {
301 Type: GlobalType{ValType: ValueTypeF32, Mutable: true},
302 Init: ConstantExpression{
303 Opcode: OpcodeF32Const,
304 Data: u64.LeBytes(api.EncodeF32(1.0)),
305 },
306 },
307 },
308 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}},
309 },
310 expected: mutableGlobal{
311 internalapi.WazeroOnlyType{}, &GlobalInstance{
312 Type: GlobalType{ValType: ValueTypeF32, Mutable: true}, Val: api.EncodeF32(1.0),
313 },
314 },
315 },
316 {
317 name: "global exported - mutable F64",
318 module: &Module{
319 GlobalSection: []Global{
320 {
321 Type: GlobalType{ValType: ValueTypeF64, Mutable: true},
322 Init: ConstantExpression{
323 Opcode: OpcodeF64Const,
324 Data: u64.LeBytes(api.EncodeF64(1.0)),
325 },
326 },
327 },
328 Exports: map[string]*Export{"global": {Type: ExternTypeGlobal, Name: "global"}},
329 },
330 expected: mutableGlobal{
331 internalapi.WazeroOnlyType{}, &GlobalInstance{
332 Type: GlobalType{ValType: ValueTypeF64, Mutable: true}, Val: api.EncodeF64(1.0),
333 },
334 },
335 },
336 }
337
338 for _, tt := range tests {
339 tc := tt
340
341 s := newStore()
342 t.Run(tc.name, func(t *testing.T) {
343
344 module, err := s.Instantiate(context.Background(), tc.module, t.Name(), nil, nil)
345 require.NoError(t, err)
346
347 if global := module.ExportedGlobal("global"); tc.expected != nil {
348 require.Equal(t, tc.expected, global)
349 } else {
350 require.Nil(t, global)
351 }
352 })
353 }
354 }
355
View as plain text