Skip to content

Commit 63959f0

Browse files
authored
Fix arity of generated switcher continuation. (#105)
This patch fixes a bug with the arity of the continuation reference generated by a `switch` (aka the current continuation). Its arity was mistakenly derived from the switch-tag's codomain. The arity of the current continuation can be obtained at the `switch` point by deconstructing the type annotation on it.
1 parent 0ebce95 commit 63959f0

File tree

3 files changed

+83
-45
lines changed

3 files changed

+83
-45
lines changed

interpreter/exec/eval.ml

+8-6
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ and admin_instr' =
7373
| Frame of int * frame * code
7474
| Handler of int * catch list * code
7575
| Handle of handle_table * code
76-
| Suspending of tag_inst * value stack * ref_ option * ctxt
76+
| Suspending of tag_inst * value stack * (int32 * ref_) option * ctxt
7777

7878
and ctxt = code -> code
7979
and handle_table = (tag_inst * idx) list * tag_inst list
@@ -413,10 +413,13 @@ let rec step (c : config) : config =
413413
| Switch (x, y), Ref (ContRef {contents = None}) :: vs ->
414414
vs, [Trapping "continuation already consumed" @@ e.at]
415415

416-
| Switch (x, y), Ref (ContRef {contents = Some (n, ctxt)} as cont) :: vs ->
416+
| Switch (x, y), Ref (ContRef ({contents = Some (n, ctxt)} as cont)) :: vs ->
417+
let FuncT (ts, _) = func_type_of_cont_type c.frame.inst (cont_type c.frame.inst x) in
418+
let FuncT (ts', _) = as_cont_func_ref_type (Lib.List.last ts) in
419+
let arity = Lib.List32.length ts' in
417420
let tagt = tag c.frame.inst y in
418421
let args, vs' = i32_split (Int32.sub n 1l) vs e.at in
419-
vs', [Suspending (tagt, args, Some cont, fun code -> code) @@ e.at]
422+
vs', [Suspending (tagt, args, Some (arity, ContRef cont), fun code -> code) @@ e.at]
420423

421424
| ReturnCall x, vs ->
422425
(match (step {c with code = (vs, [Plain (Call x) @@ e.at])}).code with
@@ -1292,11 +1295,10 @@ let rec step (c : config) : config =
12921295
[Ref (ContRef (ref (Some (Lib.List32.length ts, ctxt'))))] @ vs1 @ vs,
12931296
[Plain (Br (List.assq tagt hs)) @@ e.at]
12941297

1295-
| Handle ((_, hs) as hso, (vs', {it = Suspending (tagt, vs1, Some (ContRef ({contents = Some (_, ctxt)} as cont)), ctxt'); at} :: es')), vs
1298+
| Handle ((_, hs) as hso, (vs', {it = Suspending (tagt, vs1, Some (ar, ContRef ({contents = Some (_, ctxt)} as cont)), ctxt'); at} :: es')), vs
12961299
when List.memq tagt hs ->
1297-
let FuncT (_, ts) = func_type_of_tag_type c.frame.inst (Tag.type_of tagt) in
12981300
let ctxt'' code = compose (ctxt' code) (vs', es') in
1299-
let cont' = Ref (ContRef (ref (Some (Int32.add (Lib.List32.length ts) 1l, ctxt'')))) in
1301+
let cont' = Ref (ContRef (ref (Some (ar, ctxt'')))) in
13001302
let args = cont' :: vs1 in
13011303
cont := None;
13021304
vs' @ vs, [Handle (hso, ctxt (args, [])) @@ e.at]

interpreter/syntax/types.ml

+43-39
Original file line numberDiff line numberDiff line change
@@ -114,44 +114,6 @@ let defaultable = function
114114
| BotT -> assert false
115115

116116

117-
(* Conversions & Projections *)
118-
119-
let num_type_of_addr_type = function
120-
| I32AT -> I32T
121-
| I64AT -> I64T
122-
123-
let addr_type_of_num_type = function
124-
| I32T -> I32AT
125-
| I64T -> I64AT
126-
| _ -> assert false
127-
128-
129-
let unpacked_storage_type = function
130-
| ValStorageT t -> t
131-
| PackStorageT _ -> NumT I32T
132-
133-
let unpacked_field_type (FieldT (_mut, t)) = unpacked_storage_type t
134-
135-
136-
let as_func_str_type (st : str_type) : func_type =
137-
match st with
138-
| DefFuncT ft -> ft
139-
| _ -> assert false
140-
141-
let as_struct_str_type (st : str_type) : struct_type =
142-
match st with
143-
| DefStructT st -> st
144-
| _ -> assert false
145-
146-
let as_array_str_type (st : str_type) : array_type =
147-
match st with
148-
| DefArrayT at -> at
149-
| _ -> assert false
150-
151-
let extern_type_of_import_type (ImportT (et, _, _)) = et
152-
let extern_type_of_export_type (ExportT (et, _)) = et
153-
154-
155117
(* Filters *)
156118

157119
let funcs = List.filter_map (function ExternFuncT ft -> Some ft | _ -> None)
@@ -310,17 +272,59 @@ let expand_def_type (dt : def_type) : str_type =
310272
st
311273

312274

313-
(* Projections *)
275+
(* Conversions & Projections *)
276+
277+
let num_type_of_addr_type = function
278+
| I32AT -> I32T
279+
| I64AT -> I64T
280+
281+
let addr_type_of_num_type = function
282+
| I32T -> I32AT
283+
| I64T -> I64AT
284+
| _ -> assert false
314285

315286
let unpacked_storage_type = function
316287
| ValStorageT t -> t
317288
| PackStorageT _ -> NumT I32T
318289

290+
let unpacked_field_type (FieldT (_mut, t)) = unpacked_storage_type t
291+
292+
let as_def_heap_type (ht : heap_type) : def_type =
293+
match ht with
294+
| DefHT def -> def
295+
| _ -> assert false
296+
297+
let as_func_str_type (st : str_type) : func_type =
298+
match st with
299+
| DefFuncT ft -> ft
300+
| _ -> assert false
301+
319302
let as_cont_str_type (dt : str_type) : cont_type =
320303
match dt with
321304
| DefContT ct -> ct
322305
| _ -> assert false
323306

307+
let as_struct_str_type (st : str_type) : struct_type =
308+
match st with
309+
| DefStructT st -> st
310+
| _ -> assert false
311+
312+
let as_array_str_type (st : str_type) : array_type =
313+
match st with
314+
| DefArrayT at -> at
315+
| _ -> assert false
316+
317+
let as_cont_func_heap_type (ht : heap_type) : func_type =
318+
let ContT ht' = as_cont_str_type (expand_def_type (as_def_heap_type ht)) in
319+
as_func_str_type (expand_def_type (as_def_heap_type ht'))
320+
321+
let as_cont_func_ref_type (rt : val_type) : func_type =
322+
match rt with
323+
| RefT (_, ht) -> as_cont_func_heap_type ht
324+
| _ -> assert false
325+
326+
let extern_type_of_import_type (ImportT (et, _, _)) = et
327+
let extern_type_of_export_type (ExportT (et, _)) = et
324328

325329
(* String conversion *)
326330

test/core/stack-switching/cont.wast

+32
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,38 @@
927927
)
928928
(assert_return (invoke "main") (i32.const 10))
929929

930+
(module
931+
(type $f1 (func (result i32)))
932+
(type $c1 (cont $f1))
933+
(type $f2 (func (param (ref null $c1)) (result i32)))
934+
(type $c2 (cont $f2))
935+
(type $f3 (func (param (ref null $c2)) (result i32)))
936+
(type $c3 (cont $f3))
937+
(tag $e (result i32))
938+
939+
(func $fn_1 (param (ref null $c2)) (result i32)
940+
(local.get 0)
941+
(switch $c2 $e)
942+
(i32.const 24)
943+
)
944+
(elem declare func $fn_1)
945+
946+
(func $fn_2 (result i32)
947+
(cont.new $c3 (ref.func $fn_1))
948+
(switch $c3 $e)
949+
(drop)
950+
(i32.const -1)
951+
)
952+
(elem declare func $fn_2)
953+
954+
(func (export "main") (result i32)
955+
(cont.new $c1 (ref.func $fn_2))
956+
(resume $c1 (on $e switch))
957+
)
958+
)
959+
960+
(assert_return (invoke "main") (i32.const -1))
961+
930962
;; Syntax: check unfolded forms
931963
(module
932964
(type $ft (func))

0 commit comments

Comments
 (0)