Skip to content

Commit 8b1f75b

Browse files
committed
[test] Add more tests for cont.new
Also add support for `ref.cont` return patterns in assertions.
1 parent 927e96c commit 8b1f75b

5 files changed

Lines changed: 357 additions & 3 deletions

File tree

interpreter/exec/eval.mli

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@ exception Crash of Source.region * string
1010

1111
val init : Ast.module_ -> extern list -> module_inst (* raises Link, Trap *)
1212
val invoke : func_inst -> value list -> value list (* raises Trap *)
13+
14+
type ctxt
15+
type handle_table
16+
17+
type cont = int32 * ctxt (* TODO: represent type properly *)
18+
type ref_ += ContRef of cont option ref

interpreter/script/run.ml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,10 +412,11 @@ let assert_ref_pat r p =
412412
| RefTypePat Types.EqHT, (I31.I31Ref _ | Aggr.StructRef _ | Aggr.ArrayRef _)
413413
| RefTypePat Types.I31HT, I31.I31Ref _
414414
| RefTypePat Types.StructHT, Aggr.StructRef _
415-
| RefTypePat Types.ArrayHT, Aggr.ArrayRef _ -> true
415+
| RefTypePat Types.ArrayHT, Aggr.ArrayRef _
416416
| RefTypePat Types.FuncHT, Instance.FuncRef _
417+
| RefTypePat Types.ContHT, Eval.ContRef _
417418
| RefTypePat Types.ExnHT, Exn.ExnRef _
418-
| RefTypePat Types.ExternHT, _ -> true
419+
| RefTypePat Types.ExternHT, _
419420
| NullPat, Value.NullRef _ -> true
420421
| _ -> false
421422

interpreter/text/lexer.mll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ rule token = parse
341341
| "ref.func" -> REF_FUNC
342342
| "ref.struct" -> REF_STRUCT
343343
| "ref.array" -> REF_ARRAY
344+
| "ref.cont" -> REF_CONT
344345
| "ref.exn" -> REF_EXN
345346
| "ref.extern" -> REF_EXTERN
346347
| "ref.host" -> REF_HOST

interpreter/text/parser.mly

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ let parse_annots (m : module_) : Custom.section list =
319319
%token<string> OFFSET_EQ_NAT ALIGN_EQ_NAT
320320
%token<string Source.phrase -> Ast.instr' * Value.num> CONST
321321
%token<Ast.instr'> UNARY BINARY TEST COMPARE CONVERT
322-
%token REF_NULL REF_FUNC REF_I31 REF_STRUCT REF_ARRAY REF_EXN REF_EXTERN REF_HOST
322+
%token REF_NULL REF_FUNC REF_I31 REF_STRUCT REF_ARRAY REF_CONT REF_EXN REF_EXTERN REF_HOST
323323
%token REF_EQ REF_IS_NULL REF_AS_NON_NULL REF_TEST REF_CAST
324324
%token<Ast.instr'> I31_GET
325325
%token<Ast.idx -> Ast.instr'> STRUCT_NEW ARRAY_NEW ARRAY_GET
@@ -1626,6 +1626,7 @@ result :
16261626
| LPAR REF_STRUCT RPAR { RefResult (RefTypePat StructHT) @@ $sloc }
16271627
| LPAR REF_ARRAY RPAR { RefResult (RefTypePat ArrayHT) @@ $sloc }
16281628
| LPAR REF_FUNC RPAR { RefResult (RefTypePat FuncHT) @@ $sloc }
1629+
| LPAR REF_CONT RPAR { RefResult (RefTypePat ContHT) @@ $sloc }
16291630
| LPAR REF_EXN RPAR { RefResult (RefTypePat ExnHT) @@ $sloc }
16301631
| LPAR REF_EXTERN RPAR { RefResult (RefTypePat ExternHT) @@ $sloc }
16311632
| LPAR REF_NULL RPAR { RefResult NullPat @@ $sloc }
Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
;; No type immediate.
2+
(assert_malformed
3+
(module quote
4+
"(module"
5+
"(func (drop (cont.new)))"
6+
")"
7+
)
8+
"unexpected token"
9+
)
10+
11+
(assert_malformed
12+
(module binary
13+
"\00asm\01\00\00\00"
14+
"\01\04\01\60\00\00" ;; Type section: 1 type
15+
"\03\02\01\00" ;; Function section: 1 function
16+
"\0a\04\01" ;; Code section: 1 function
17+
;; function 0
18+
"\02\00" ;; Function size and local type count
19+
"\e0" ;; cont.new (missing type immediate)
20+
)
21+
"unexpected end"
22+
)
23+
24+
;; Valid binary module parsing, validating, and executing correctly
25+
(module binary
26+
"\00\61\73\6d\01\00\00\00" ;; Magic header and version
27+
"\01\8b\80\80\80\00\03" ;; Type section: 3 types
28+
"\60\00\00" ;; type 0: func [] -> []
29+
"\5d\00" ;; type 1: cont 0
30+
"\60\00\01\64\01" ;; type 2: func [] -> [ref 1]
31+
"\03\83\80\80\80\00\02" ;; Function section: 2 functions
32+
"\00\02" ;; func 0: type 0, func 1: type 2
33+
"\07\88\80\80\80\00\01" ;; Export section: 1 export
34+
"\04\74\65\73\74\00\01" ;; "test" -> func 1
35+
"\09\85\80\80\80\00\01" ;; Element section: 1 segment
36+
"\03\00\01\00" ;; declarative, elem kind func, 1 func, func index 0
37+
"\0a\93\80\80\80\00\02" ;; Code section: 2 functions
38+
;; function 0
39+
"\82\80\80\80\00\00\0b" ;; size 2, 0 locals, end
40+
;; function 1
41+
"\86\80\80\80\00\00" ;; size 6, 0 locals
42+
"\d2\00" ;; ref.func 0
43+
"\e0\01" ;; cont.new 1
44+
"\0b" ;; end
45+
)
46+
(assert_return (invoke "test") (ref.cont))
47+
48+
;; Out-of-bounds type immediate.
49+
(assert_invalid
50+
(module
51+
(func (drop (cont.new 0 (unreachable))))
52+
)
53+
"non-continuation type"
54+
)
55+
56+
;; Non-continuation type.
57+
(assert_invalid
58+
(module
59+
(type $f (func))
60+
(func (drop (cont.new $f (unreachable))))
61+
)
62+
"non-continuation type"
63+
)
64+
65+
;; Defined function ref.func operand.
66+
(module
67+
(type $f (func))
68+
(type $k (cont $f))
69+
(elem declare func $f)
70+
(func $f (type $f))
71+
(func (export "test") (result (ref $k)) (cont.new $k (ref.func $f)))
72+
)
73+
(assert_return (invoke "test") (ref.cont))
74+
75+
;; Imported function ref.func operand.
76+
(module definition
77+
(type $f (func))
78+
(type $k (cont $f))
79+
(elem declare func $f)
80+
(import "" "" (func $f (type $f)))
81+
(func (result (ref $k)) (cont.new $k (ref.func $f)))
82+
)
83+
84+
;; Defined global operand.
85+
(module
86+
(type $f (func))
87+
(type $k (cont $f))
88+
(global $g (ref null $f) (ref.null nofunc))
89+
(func (export "test") (result (ref $k)) (cont.new $k (global.get $g)))
90+
)
91+
(assert_trap (invoke "test") "null function reference")
92+
93+
;; Defined global operand (non-null at runtime).
94+
(module
95+
(type $f (func))
96+
(type $k (cont $f))
97+
(elem declare func $f)
98+
(func $f (type $f))
99+
(global $g (ref null $f) (ref.func $f))
100+
(func (export "test") (result (ref $k)) (cont.new $k (global.get $g)))
101+
)
102+
(assert_return (invoke "test") (ref.cont))
103+
104+
;; Imported global operand.
105+
(module definition
106+
(type $f (func))
107+
(type $k (cont $f))
108+
(import "" "" (global $g (ref null $f)))
109+
(func (result (ref $k)) (cont.new $k (global.get $g)))
110+
)
111+
112+
;; Param operand.
113+
(module
114+
(type $f (func))
115+
(type $k (cont $f))
116+
(func (export "test") (param (ref null $f)) (result (ref $k))
117+
(cont.new $k (local.get 0))
118+
)
119+
)
120+
(assert_trap (invoke "test" (ref.null nofunc)) "null function reference")
121+
122+
;; Stack-polymorphic (unreachable) input.
123+
(module
124+
(type $f (func))
125+
(type $k (cont $f))
126+
(func (export "test") (result (ref $k)) (cont.new $k (unreachable)))
127+
)
128+
(assert_trap (invoke "test") "unreachable")
129+
130+
;; Stack-polymorphic (unreachable) input due to branch.
131+
(module
132+
(type $f (func))
133+
(type $k (cont $f))
134+
(func (export "test")
135+
(drop
136+
(block $l (result (ref $k))
137+
(cont.new $k (return))
138+
)
139+
)
140+
)
141+
)
142+
(assert_return (invoke "test"))
143+
144+
;; Uninhabitable bottom input.
145+
(module
146+
(type $f (func))
147+
(type $k (cont $f))
148+
(func (param (ref nofunc)) (result (ref $k)) (cont.new $k (local.get 0)))
149+
)
150+
151+
;; Null constant input.
152+
(module
153+
(type $f (func))
154+
(type $k (cont $f))
155+
(func (export "test") (result (ref $k)) (cont.new $k (ref.null $f)))
156+
)
157+
(assert_trap (invoke "test") "null function reference")
158+
159+
;; Bottom null constant input.
160+
(module
161+
(type $f (func))
162+
(type $k (cont $f))
163+
(func (export "test") (result (ref $k)) (cont.new $k (ref.null nofunc)))
164+
)
165+
(assert_trap (invoke "test") "null function reference")
166+
167+
;; Top null constant input.
168+
(assert_invalid
169+
(module
170+
(type $f (func))
171+
(type $k (cont $f))
172+
(func (result (ref $k)) (cont.new $k (ref.null func)))
173+
)
174+
"type mismatch"
175+
)
176+
177+
;; Any hierarchy null constant input.
178+
(assert_invalid
179+
(module
180+
(type $f (func))
181+
(type $k (cont $f))
182+
(func (result (ref $k)) (cont.new $k (ref.null none)))
183+
)
184+
"type mismatch"
185+
)
186+
187+
;; Cont hierarchy null constant input.
188+
(assert_invalid
189+
(module
190+
(type $f (func))
191+
(type $k (cont $f))
192+
(func (result (ref $k)) (cont.new $k (ref.null nocont)))
193+
)
194+
"type mismatch"
195+
)
196+
197+
;; Top reference input.
198+
(assert_invalid
199+
(module
200+
(type $f (func))
201+
(type $k (cont $f))
202+
(func (param funcref) (result (ref $k)) (cont.new $k (local.get 0)))
203+
)
204+
"type mismatch"
205+
)
206+
207+
;; Declared subtype input.
208+
(module
209+
(type $super (sub (func)))
210+
(type $sub (sub $super (func)))
211+
(type $k (cont $super))
212+
(elem declare func $sub)
213+
(func $sub (type $sub))
214+
(func (export "test") (result (ref $k)) (cont.new $k (ref.func $sub)))
215+
)
216+
(assert_return (invoke "test") (ref.cont))
217+
218+
;; Declared supertype input.
219+
(assert_invalid
220+
(module
221+
(type $super (sub (func)))
222+
(type $sub (sub $super (func)))
223+
(type $k (cont $sub))
224+
(func (param (ref null $super)) (result (ref $k)) (cont.new $k (local.get 0)))
225+
)
226+
"type mismatch"
227+
)
228+
229+
;; Unrelated input.
230+
(assert_invalid
231+
(module
232+
(rec
233+
(type $f (func))
234+
(type $other (func))
235+
)
236+
(type $k (cont $f))
237+
(func (param (ref null $other)) (result (ref $k)) (cont.new $k (local.get 0)))
238+
)
239+
"type mismatch"
240+
)
241+
242+
;; Missing input.
243+
(assert_invalid
244+
(module
245+
(type $f (func))
246+
(type $k (cont $f))
247+
(func (result (ref $k)) (cont.new $k))
248+
)
249+
"type mismatch"
250+
)
251+
252+
;; Extra input.
253+
(assert_invalid
254+
(module
255+
(type $f (func))
256+
(type $k (cont $f))
257+
(func (param (ref null $f)) (result (ref $k)) (cont.new $k (i32.const 0) (local.get 0)))
258+
)
259+
"type mismatch"
260+
)
261+
262+
;; Extra input matching continuation params.
263+
(assert_invalid
264+
(module
265+
(type $f (func (param i32)))
266+
(type $k (cont $f))
267+
(func (param (ref null $f)) (result (ref $k)) (cont.new $k (i32.const 0) (local.get 0)))
268+
)
269+
"type mismatch"
270+
)
271+
272+
;; Contref output type.
273+
(module
274+
(type $f (func))
275+
(type $k (cont $f))
276+
(func (param (ref null $f)) (result contref) (cont.new $k (local.get 0)))
277+
)
278+
279+
;; Nullable cont reference output type.
280+
(module
281+
(type $f (func))
282+
(type $k (cont $f))
283+
(func (param (ref null $f)) (result (ref null cont)) (cont.new $k (local.get 0)))
284+
)
285+
286+
;; Non-nullable cont reference output type.
287+
(module
288+
(type $f (func))
289+
(type $k (cont $f))
290+
(func (param (ref null $f)) (result (ref cont)) (cont.new $k (local.get 0)))
291+
)
292+
293+
;; Declared supertype output type.
294+
(module
295+
(type $f (func))
296+
(type $super (sub (cont $f)))
297+
(type $sub (sub $super (cont $f)))
298+
(func (param (ref null $f)) (result (ref $super)) (cont.new $sub (local.get 0)))
299+
)
300+
301+
;; Declared subtype output type.
302+
(assert_invalid
303+
(module
304+
(type $f (func))
305+
(type $super (sub (cont $f)))
306+
(type $sub (sub $super (cont $f)))
307+
(func (param (ref null $f)) (result (ref $sub)) (cont.new $super (local.get 0)))
308+
)
309+
"type mismatch"
310+
)
311+
312+
;; Unrelated output.
313+
(assert_invalid
314+
(module
315+
(type $f (func))
316+
(rec
317+
(type $k (cont $f))
318+
(type $other (cont $f))
319+
)
320+
(func (param (ref null $f)) (result (ref $other)) (cont.new $k (local.get 0)))
321+
)
322+
"type mismatch"
323+
)
324+
325+
;; TODO: Make cont.new constant
326+
;; https://github.com/WebAssembly/stack-switching/issues/145
327+
328+
;; ;; Constant expression in global definition.
329+
;; (module
330+
;; (type $f (func))
331+
;; (type $k (cont $f))
332+
;; (global $k (export "k") (ref $k) (cont.new $k (ref.func $f)))
333+
;; (func $f (type $f))
334+
;; )
335+
;; (assert_return (get "k") (ref.cont))
336+
337+
;; ;; Constant expression in element segment definition.
338+
;; (module
339+
;; (type $f (func))
340+
;; (type $k (cont $f))
341+
;; (table $t (ref null $k) (elem (cont.new $k (ref.func $f))))
342+
;; (func $f (type $f))
343+
;; (func (export "get") (result (ref null $k)) (table.get $t (i32.const 0)))
344+
;; )
345+
;; (assert_return (invoke "get") (ref.cont))

0 commit comments

Comments
 (0)