3
3
use arbitrary:: Arbitrary ;
4
4
use std:: ops:: Range ;
5
5
use wasm_encoder:: {
6
- CodeSection , EntityType , Export , ExportSection , Function , FunctionSection , ImportSection ,
7
- Instruction , Module , TableSection , TableType , TypeSection , ValType ,
6
+ CodeSection , EntityType , Export , ExportSection , Function , FunctionSection , GlobalSection ,
7
+ ImportSection , Instruction , Module , TableSection , TableType , TypeSection , ValType ,
8
8
} ;
9
9
10
10
/// A description of a Wasm module that makes a series of `externref` table
11
11
/// operations.
12
12
#[ derive( Arbitrary , Debug ) ]
13
13
pub struct TableOps {
14
14
num_params : u8 ,
15
+ num_globals : u8 ,
15
16
table_size : u32 ,
16
17
ops : Vec < TableOp > ,
17
18
}
18
19
19
20
const NUM_PARAMS_RANGE : Range < u8 > = 1 ..10 ;
21
+ const NUM_GLOBALS_RANGE : Range < u8 > = 1 ..10 ;
20
22
const TABLE_SIZE_RANGE : Range < u32 > = 1 ..100 ;
21
23
const MAX_OPS : usize = 100 ;
22
24
@@ -28,6 +30,13 @@ impl TableOps {
28
30
num_params
29
31
}
30
32
33
+ /// Get the number of globals this module has.
34
+ pub fn num_globals ( & self ) -> u8 {
35
+ let num_globals = std:: cmp:: max ( self . num_globals , NUM_GLOBALS_RANGE . start ) ;
36
+ let num_globals = std:: cmp:: min ( num_globals, NUM_GLOBALS_RANGE . end ) ;
37
+ num_globals
38
+ }
39
+
31
40
/// Get the size of the table that this module uses.
32
41
pub fn table_size ( & self ) -> u32 {
33
42
let table_size = std:: cmp:: max ( self . table_size , TABLE_SIZE_RANGE . start ) ;
@@ -98,6 +107,18 @@ impl TableOps {
98
107
maximum : None ,
99
108
} ) ;
100
109
110
+ // Define our globals.
111
+ let mut globals = GlobalSection :: new ( ) ;
112
+ for _ in 0 ..self . num_globals ( ) {
113
+ globals. global (
114
+ wasm_encoder:: GlobalType {
115
+ val_type : wasm_encoder:: ValType :: ExternRef ,
116
+ mutable : true ,
117
+ } ,
118
+ Instruction :: RefNull ( wasm_encoder:: ValType :: ExternRef ) ,
119
+ ) ;
120
+ }
121
+
101
122
// Define the "run" function export.
102
123
let mut functions = FunctionSection :: new ( ) ;
103
124
functions. function ( 1 ) ;
@@ -111,7 +132,12 @@ impl TableOps {
111
132
112
133
func. instruction ( Instruction :: Loop ( wasm_encoder:: BlockType :: Empty ) ) ;
113
134
for op in self . ops . iter ( ) . take ( MAX_OPS ) {
114
- op. insert ( & mut func, self . num_params ( ) as u32 , self . table_size ( ) ) ;
135
+ op. insert (
136
+ & mut func,
137
+ self . num_params ( ) as u32 ,
138
+ self . table_size ( ) ,
139
+ self . num_globals ( ) as u32 ,
140
+ ) ;
115
141
}
116
142
func. instruction ( Instruction :: Br ( 0 ) ) ;
117
143
func. instruction ( Instruction :: End ) ;
@@ -125,89 +151,118 @@ impl TableOps {
125
151
. section ( & imports)
126
152
. section ( & functions)
127
153
. section ( & tables)
154
+ . section ( & globals)
128
155
. section ( & exports)
129
156
. section ( & code) ;
130
157
131
158
module. finish ( )
132
159
}
133
160
}
134
161
135
- #[ derive( Arbitrary , Debug ) ]
162
+ #[ derive( Arbitrary , Copy , Clone , Debug ) ]
136
163
pub ( crate ) enum TableOp {
137
164
// `call $gc; drop; drop; drop;`
138
165
Gc ,
166
+
139
167
// `(drop (table.get x))`
140
168
Get ( i32 ) ,
169
+
170
+ // `(drop (global.get i))`
171
+ GetGlobal ( u32 ) ,
172
+
141
173
// `(table.set x (local.get y))`
142
174
SetFromParam ( i32 , u32 ) ,
175
+
143
176
// `(table.set x (table.get y))`
144
177
SetFromGet ( i32 , i32 ) ,
178
+
145
179
// `call $make_refs; table.set x; table.set y; table.set z`
146
180
SetFromMake ( i32 , i32 , i32 ) ,
181
+
182
+ // `(global.set x (local.get y))`
183
+ SetGlobalFromParam ( u32 , u32 ) ,
184
+
185
+ // `(global.set x (table.get y))`
186
+ SetGlobalFromGet ( u32 , i32 ) ,
187
+
188
+ // `call $make_refs; global.set x; global.set y; global.set z`
189
+ SetGlobalFromMake ( u32 , u32 , u32 ) ,
190
+
147
191
// `call $make_refs; drop; drop; drop;`
148
192
Make ,
193
+
149
194
// `local.get x; local.get y; local.get z; call $take_refs`
150
195
TakeFromParams ( u32 , u32 , u32 ) ,
196
+
151
197
// `table.get x; table.get y; table.get z; call $take_refs`
152
198
TakeFromGet ( i32 , i32 , i32 ) ,
199
+
200
+ // `global.get x; global.get y; global.get z; call $take_refs`
201
+ TakeFromGlobalGet ( u32 , u32 , u32 ) ,
202
+
153
203
// `call $make_refs; call $take_refs`
154
204
TakeFromMake ,
205
+
155
206
// `call $gc; call $take_refs`
156
207
TakeFromGc ,
157
208
}
158
209
159
210
impl TableOp {
160
- fn insert ( & self , func : & mut Function , num_params : u32 , table_size : u32 ) {
211
+ fn insert ( self , func : & mut Function , num_params : u32 , table_size : u32 , num_globals : u32 ) {
161
212
assert ! ( num_params > 0 ) ;
162
213
assert ! ( table_size > 0 ) ;
163
214
164
215
// Add one to make sure that out of bounds table accesses are possible,
165
216
// but still rare.
166
217
let table_mod = table_size as i32 + 1 ;
167
218
219
+ let gc_func_idx = 0 ;
220
+ let take_refs_func_idx = 1 ;
221
+ let make_refs_func_idx = 2 ;
222
+
168
223
match self {
169
224
Self :: Gc => {
170
- func. instruction ( Instruction :: Call ( 0 ) ) ;
225
+ func. instruction ( Instruction :: Call ( gc_func_idx ) ) ;
171
226
func. instruction ( Instruction :: Drop ) ;
172
227
func. instruction ( Instruction :: Drop ) ;
173
228
func. instruction ( Instruction :: Drop ) ;
174
229
}
175
230
Self :: Get ( x) => {
176
- func. instruction ( Instruction :: I32Const ( * x % table_mod) ) ;
231
+ func. instruction ( Instruction :: I32Const ( x % table_mod) ) ;
177
232
func. instruction ( Instruction :: TableGet { table : 0 } ) ;
178
233
func. instruction ( Instruction :: Drop ) ;
179
234
}
180
235
Self :: SetFromParam ( x, y) => {
181
- func. instruction ( Instruction :: I32Const ( * x % table_mod) ) ;
182
- func. instruction ( Instruction :: LocalGet ( * y % num_params) ) ;
236
+ func. instruction ( Instruction :: I32Const ( x % table_mod) ) ;
237
+ func. instruction ( Instruction :: LocalGet ( y % num_params) ) ;
183
238
func. instruction ( Instruction :: TableSet { table : 0 } ) ;
184
239
}
185
240
Self :: SetFromGet ( x, y) => {
186
- func. instruction ( Instruction :: I32Const ( * x % table_mod) ) ;
187
- func. instruction ( Instruction :: I32Const ( * y % table_mod) ) ;
241
+ func. instruction ( Instruction :: I32Const ( x % table_mod) ) ;
242
+ func. instruction ( Instruction :: I32Const ( y % table_mod) ) ;
188
243
func. instruction ( Instruction :: TableGet { table : 0 } ) ;
189
244
func. instruction ( Instruction :: TableSet { table : 0 } ) ;
190
245
}
191
246
Self :: SetFromMake ( x, y, z) => {
192
- func. instruction ( Instruction :: Call ( 2 ) ) ;
247
+ func. instruction ( Instruction :: Call ( make_refs_func_idx ) ) ;
193
248
194
249
func. instruction ( Instruction :: LocalSet ( num_params) ) ;
195
- func. instruction ( Instruction :: I32Const ( * x % table_mod) ) ;
250
+ func. instruction ( Instruction :: I32Const ( x % table_mod) ) ;
196
251
func. instruction ( Instruction :: LocalGet ( num_params) ) ;
197
252
func. instruction ( Instruction :: TableSet { table : 0 } ) ;
198
253
199
254
func. instruction ( Instruction :: LocalSet ( num_params) ) ;
200
- func. instruction ( Instruction :: I32Const ( * y % table_mod) ) ;
255
+ func. instruction ( Instruction :: I32Const ( y % table_mod) ) ;
201
256
func. instruction ( Instruction :: LocalGet ( num_params) ) ;
202
257
func. instruction ( Instruction :: TableSet { table : 0 } ) ;
203
258
204
259
func. instruction ( Instruction :: LocalSet ( num_params) ) ;
205
- func. instruction ( Instruction :: I32Const ( * z % table_mod) ) ;
260
+ func. instruction ( Instruction :: I32Const ( z % table_mod) ) ;
206
261
func. instruction ( Instruction :: LocalGet ( num_params) ) ;
207
262
func. instruction ( Instruction :: TableSet { table : 0 } ) ;
208
263
}
209
264
TableOp :: Make => {
210
- func. instruction ( Instruction :: Call ( 2 ) ) ;
265
+ func. instruction ( Instruction :: Call ( make_refs_func_idx ) ) ;
211
266
func. instruction ( Instruction :: Drop ) ;
212
267
func. instruction ( Instruction :: Drop ) ;
213
268
func. instruction ( Instruction :: Drop ) ;
@@ -216,27 +271,52 @@ impl TableOp {
216
271
func. instruction ( Instruction :: LocalGet ( x % num_params) ) ;
217
272
func. instruction ( Instruction :: LocalGet ( y % num_params) ) ;
218
273
func. instruction ( Instruction :: LocalGet ( z % num_params) ) ;
219
- func. instruction ( Instruction :: Call ( 1 ) ) ;
274
+ func. instruction ( Instruction :: Call ( take_refs_func_idx ) ) ;
220
275
}
221
276
TableOp :: TakeFromGet ( x, y, z) => {
222
- func. instruction ( Instruction :: I32Const ( * x % table_mod) ) ;
277
+ func. instruction ( Instruction :: I32Const ( x % table_mod) ) ;
223
278
func. instruction ( Instruction :: TableGet { table : 0 } ) ;
224
279
225
- func. instruction ( Instruction :: I32Const ( * y % table_mod) ) ;
280
+ func. instruction ( Instruction :: I32Const ( y % table_mod) ) ;
226
281
func. instruction ( Instruction :: TableGet { table : 0 } ) ;
227
282
228
- func. instruction ( Instruction :: I32Const ( * z % table_mod) ) ;
283
+ func. instruction ( Instruction :: I32Const ( z % table_mod) ) ;
229
284
func. instruction ( Instruction :: TableGet { table : 0 } ) ;
230
285
231
- func. instruction ( Instruction :: Call ( 1 ) ) ;
286
+ func. instruction ( Instruction :: Call ( take_refs_func_idx ) ) ;
232
287
}
233
288
TableOp :: TakeFromMake => {
234
- func. instruction ( Instruction :: Call ( 2 ) ) ;
235
- func. instruction ( Instruction :: Call ( 1 ) ) ;
289
+ func. instruction ( Instruction :: Call ( make_refs_func_idx ) ) ;
290
+ func. instruction ( Instruction :: Call ( take_refs_func_idx ) ) ;
236
291
}
237
292
Self :: TakeFromGc => {
238
- func. instruction ( Instruction :: Call ( 0 ) ) ;
239
- func. instruction ( Instruction :: Call ( 1 ) ) ;
293
+ func. instruction ( Instruction :: Call ( gc_func_idx) ) ;
294
+ func. instruction ( Instruction :: Call ( take_refs_func_idx) ) ;
295
+ }
296
+ TableOp :: GetGlobal ( x) => {
297
+ func. instruction ( Instruction :: GlobalGet ( x % num_globals) ) ;
298
+ func. instruction ( Instruction :: Drop ) ;
299
+ }
300
+ TableOp :: SetGlobalFromParam ( global, param) => {
301
+ func. instruction ( Instruction :: LocalGet ( param % num_params) ) ;
302
+ func. instruction ( Instruction :: GlobalSet ( global % num_globals) ) ;
303
+ }
304
+ TableOp :: SetGlobalFromGet ( global, x) => {
305
+ func. instruction ( Instruction :: I32Const ( x) ) ;
306
+ func. instruction ( Instruction :: TableGet { table : 0 } ) ;
307
+ func. instruction ( Instruction :: GlobalSet ( global % num_globals) ) ;
308
+ }
309
+ TableOp :: SetGlobalFromMake ( x, y, z) => {
310
+ func. instruction ( Instruction :: Call ( make_refs_func_idx) ) ;
311
+ func. instruction ( Instruction :: GlobalSet ( x % num_globals) ) ;
312
+ func. instruction ( Instruction :: GlobalSet ( y % num_globals) ) ;
313
+ func. instruction ( Instruction :: GlobalSet ( z % num_globals) ) ;
314
+ }
315
+ TableOp :: TakeFromGlobalGet ( x, y, z) => {
316
+ func. instruction ( Instruction :: GlobalGet ( x % num_globals) ) ;
317
+ func. instruction ( Instruction :: GlobalGet ( y % num_globals) ) ;
318
+ func. instruction ( Instruction :: GlobalGet ( z % num_globals) ) ;
319
+ func. instruction ( Instruction :: Call ( take_refs_func_idx) ) ;
240
320
}
241
321
}
242
322
}
@@ -250,6 +330,7 @@ mod tests {
250
330
fn test_wat_string ( ) {
251
331
let ops = TableOps {
252
332
num_params : 5 ,
333
+ num_globals : 1 ,
253
334
table_size : 20 ,
254
335
ops : vec ! [
255
336
TableOp :: Gc ,
@@ -261,6 +342,11 @@ mod tests {
261
342
TableOp :: TakeFromParams ( 8 , 9 , 10 ) ,
262
343
TableOp :: TakeFromGet ( 11 , 12 , 13 ) ,
263
344
TableOp :: TakeFromMake ,
345
+ TableOp :: GetGlobal ( 14 ) ,
346
+ TableOp :: SetGlobalFromParam ( 15 , 16 ) ,
347
+ TableOp :: SetGlobalFromGet ( 17 , 18 ) ,
348
+ TableOp :: SetGlobalFromMake ( 19 , 20 , 21 ) ,
349
+ TableOp :: TakeFromGlobalGet ( 22 , 23 , 24 ) ,
264
350
] ,
265
351
} ;
266
352
@@ -320,9 +406,25 @@ mod tests {
320
406
call 1
321
407
call 2
322
408
call 1
409
+ global.get 0
410
+ drop
411
+ local.get 1
412
+ global.set 0
413
+ i32.const 18
414
+ table.get 0
415
+ global.set 0
416
+ call 2
417
+ global.set 0
418
+ global.set 0
419
+ global.set 0
420
+ global.get 0
421
+ global.get 0
422
+ global.get 0
423
+ call 1
323
424
br 0 (;@1;)
324
425
end)
325
426
(table (;0;) 20 externref)
427
+ (global (;0;) (mut externref) (ref.null extern))
326
428
(export "run" (func 3)))
327
429
"# ;
328
430
eprintln ! ( "expected WAT = {}" , expected) ;
0 commit comments