Skip to content

Commit 0e9cbd0

Browse files
committed
Effects based on Stack Switching proposal
1 parent 7a4d3ff commit 0e9cbd0

File tree

7 files changed

+273
-16
lines changed

7 files changed

+273
-16
lines changed

compiler/lib-wasm/binaryen.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ let common_options () =
3737
; "--enable-nontrapping-float-to-int"
3838
; "--enable-strings"
3939
; "--enable-multimemory" (* To keep wasm-merge happy *)
40+
; "--enable-stack-switching"
4041
]
4142
in
4243
if Config.Flag.pretty () then "-g" :: l else l

compiler/tests-jsoo/lib-effects/dune

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
(env
22
(with-effects-double-translation)
33
(with-effects)
4-
(wasi
5-
(wasm_of_ocaml
6-
(flags
7-
(:standard --enable effects))))
4+
; (wasi
5+
; (wasm_of_ocaml
6+
; (flags
7+
; (:standard --enable effects))))
88
(_
99
(js_of_ocaml
1010
(flags

compiler/tests-ocaml/effect-syntax/dune

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
(env
22
(with-effects-double-translation)
33
(with-effects)
4-
(wasi
5-
(flags
6-
(:standard -w -38))
7-
(wasm_of_ocaml
8-
(flags
9-
(:standard --enable=effects))))
4+
; (wasi
5+
; (flags
6+
; (:standard -w -38))
7+
; (wasm_of_ocaml
8+
; (flags
9+
; (:standard --enable=effects))))
1010
(_
1111
(js_of_ocaml
1212
(flags

compiler/tests-ocaml/effects/dune

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
(env
22
(with-effects-double-translation)
33
(with-effects)
4-
(wasi
5-
(flags
6-
(:standard -w -38))
7-
(wasm_of_ocaml
8-
(flags
9-
(:standard --enable=effects))))
4+
; (wasi
5+
; (flags
6+
; (:standard -w -38))
7+
; (wasm_of_ocaml
8+
; (flags
9+
; (:standard --enable=effects))))
1010
(_
1111
(js_of_ocaml
1212
(flags

runtime/wasm/effect-native.wat

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
(module
2+
(@if wasi
3+
(@then
4+
(import "fail" "caml_raise_constant"
5+
(func $caml_raise_constant (param (ref eq))))
6+
(import "fail" "caml_raise_with_arg"
7+
(func $caml_raise_with_arg (param $tag (ref eq)) (param $arg (ref eq))))
8+
(import "obj" "caml_fresh_oo_id"
9+
(func $caml_fresh_oo_id (param (ref eq)) (result (ref eq))))
10+
(import "obj" "cont_tag" (global $cont_tag i32))
11+
(import "stdlib" "caml_named_value"
12+
(func $caml_named_value (param (ref eq)) (result (ref null eq))))
13+
(import "fail" "ocaml_exception" (tag $ocaml_exception (param (ref eq))))
14+
(import "fail" "javascript_exception"
15+
(tag $javascript_exception (param externref)))
16+
(import "jslib" "caml_wrap_exception"
17+
(func $caml_wrap_exception (param externref) (result (ref eq))))
18+
(import "bindings" "start_fiber" (func $start_fiber (param (ref eq))))
19+
(import "bindings" "suspend_fiber"
20+
(func $suspend_fiber
21+
(param externref) (param $f funcref) (param $env eqref)
22+
(result eqref)))
23+
(import "bindings" "resume_fiber"
24+
(func $resume_fiber (param externref) (param (ref eq))))
25+
(import "stdlib" "caml_main_wrapper"
26+
(global $caml_main_wrapper (mut (ref null $wrapper_func))))
27+
28+
(type $block (array (mut (ref eq))))
29+
(type $string (array (mut i8)))
30+
(type $function_1 (func (param (ref eq) (ref eq)) (result (ref eq))))
31+
(type $closure (sub (struct (;(field i32);) (field (ref $function_1)))))
32+
(type $function_3
33+
(func (param (ref eq) (ref eq) (ref eq) (ref eq)) (result (ref eq))))
34+
(type $closure_3
35+
(sub $closure
36+
(struct (field (ref $function_1)) (field (ref $function_3)))))
37+
38+
;; Effect types
39+
40+
(tag $effect (param (ref eq)) (result (ref eq) (ref eq)))
41+
42+
(type $cont_function (func (param (ref eq) (ref eq)) (result (ref eq))))
43+
44+
(type $cont (cont $cont_function))
45+
46+
(type $handlers
47+
(struct
48+
(field $value (ref eq))
49+
(field $exn (ref eq))
50+
(field $effect (ref eq))))
51+
52+
(type $fiber
53+
(struct
54+
(field $handlers (mut (ref $handlers)))
55+
(field $cont (ref $cont))))
56+
57+
(@string $effect_unhandled "Effect.Unhandled")
58+
59+
(func $raise_unhandled
60+
(param $eff (ref eq)) (param (ref eq)) (result (ref eq))
61+
(block $null
62+
(call $caml_raise_with_arg
63+
(br_on_null $null
64+
(call $caml_named_value (global.get $effect_unhandled)))
65+
(local.get $eff)))
66+
(call $caml_raise_constant
67+
(array.new_fixed $block 3 (ref.i31 (i32.const 248))
68+
(global.get $effect_unhandled)
69+
(call $caml_fresh_oo_id (ref.i31 (i32.const 0)))))
70+
(ref.i31 (i32.const 0)))
71+
72+
(global $raise_unhandled (ref $closure)
73+
(struct.new $closure (ref.func $raise_unhandled)))
74+
75+
(type $func (func (result (ref eq))))
76+
(type $wrapper_func (func (param (ref $func))))
77+
(type $func_closure (struct (field (ref $func))))
78+
79+
(func $wrapper_cont
80+
(param $f (ref eq)) (param (ref eq)) (result (ref eq))
81+
(return_call_ref $func
82+
(local.get $f)
83+
(struct.get $func_closure 0
84+
(ref.cast (ref $func_closure) (local.get $f)))))
85+
86+
(func $unhandled_effect_wrapper (param $start (ref $func))
87+
(local $cont (ref $cont))
88+
(local $f (ref eq)) (local $v (ref eq))
89+
(local $resume_res (tuple (ref eq) (ref $cont)))
90+
(local.set $cont (cont.new $cont (ref.func $wrapper_cont)))
91+
(local.set $f (struct.new $func_closure (local.get $start)))
92+
(local.set $v (ref.i31 (i32.const 0)))
93+
(loop $loop
94+
(local.set $resume_res
95+
(block $handle_effect (result (ref eq) (ref $cont))
96+
(resume $cont (on $effect $handle_effect)
97+
(local.get $f) (local.get $v) (local.get $cont))
98+
(return)))
99+
(local.set $cont (tuple.extract 2 1 (local.get $resume_res)))
100+
(local.set $v (tuple.extract 2 0 (local.get $resume_res)))
101+
(local.set $f (global.get $raise_unhandled))
102+
(br $loop)))
103+
104+
(func $init
105+
(global.set $caml_main_wrapper (ref.func $unhandled_effect_wrapper)))
106+
107+
(start $init)
108+
109+
;; Resume
110+
111+
(@string $already_resumed "Effect.Continuation_already_resumed")
112+
113+
(func $resume (export "%resume")
114+
(param $vfiber (ref eq)) (param $f (ref eq)) (param $v (ref eq))
115+
(param $tail (ref eq)) (result (ref eq))
116+
(local $fiber (ref $fiber))
117+
(local $res (ref eq))
118+
(local $exn (ref eq))
119+
(local $resume_res (tuple (ref eq) (ref $cont)))
120+
(if (ref.eq (local.get $vfiber) (ref.i31 (i32.const 0)))
121+
(then
122+
(call $caml_raise_constant
123+
(ref.as_non_null
124+
(call $caml_named_value (global.get $already_resumed))))))
125+
(local.set $fiber (ref.cast (ref $fiber) (local.get $vfiber)))
126+
(local.set $exn
127+
(block $handle_exception (result (ref eq))
128+
(local.set $resume_res
129+
(block $handle_effect (result (ref eq) (ref $cont))
130+
(local.set $res
131+
(try (result (ref eq))
132+
(do
133+
(resume $cont
134+
(on $effect $handle_effect)
135+
(local.get $f) (local.get $v)
136+
(struct.get $fiber $cont (local.get $fiber))))
137+
(catch $javascript_exception
138+
(br $handle_exception
139+
(call $caml_wrap_exception (pop externref))))
140+
(catch $ocaml_exception
141+
(br $handle_exception (pop (ref eq))))))
142+
;; handle return
143+
(return_call_ref $function_1 (local.get $res)
144+
(local.tee $f
145+
(struct.get $handlers $value
146+
(struct.get $fiber $handlers (local.get $fiber))))
147+
(struct.get $closure 0
148+
(ref.cast (ref $closure) (local.get $f))))))
149+
;; handle effect
150+
(return_call_ref $function_3
151+
(tuple.extract 2 0 (local.get $resume_res))
152+
(array.new_fixed $block 3 (ref.i31 (global.get $cont_tag))
153+
(struct.new $fiber
154+
(struct.get $fiber $handlers (local.get $fiber))
155+
(tuple.extract 2 1 (local.get $resume_res)))
156+
(ref.i31 (i32.const 0)))
157+
(ref.i31 (i32.const 0)) ;; unused
158+
(local.tee $f
159+
(struct.get $handlers $effect
160+
(struct.get $fiber $handlers (local.get $fiber))))
161+
(struct.get $closure_3 1
162+
(ref.cast (ref $closure_3) (local.get $f))))))
163+
;; handle exception
164+
(return_call_ref $function_1 (local.get $exn)
165+
(local.tee $f
166+
(struct.get $handlers $exn
167+
(struct.get $fiber $handlers (local.get $fiber))))
168+
(struct.get $closure 0 (ref.cast (ref $closure) (local.get $f)))))
169+
170+
;; Perform
171+
172+
(func (export "%reperform")
173+
(param $eff (ref eq)) (param $cont (ref eq)) (param $tail (ref eq))
174+
(result (ref eq))
175+
(local $res (tuple (ref eq) (ref eq)))
176+
(local.set $res (suspend $effect (local.get $eff)))
177+
(return_call $resume
178+
(ref.as_non_null
179+
(array.get $block
180+
(ref.cast (ref $block) (local.get $cont))
181+
(i32.const 1)))
182+
(tuple.extract 2 0 (local.get $res))
183+
(tuple.extract 2 1 (local.get $res))
184+
(local.get $tail)))
185+
186+
(func (export "%perform") (param $eff (ref eq)) (result (ref eq))
187+
(local $res (tuple (ref eq) (ref eq)))
188+
(local.set $res (suspend $effect (local.get $eff)))
189+
(return_call_ref $function_1 (tuple.extract 2 1 (local.get $res))
190+
(tuple.extract 2 0 (local.get $res))
191+
(struct.get $closure 0
192+
(ref.cast (ref $closure) (tuple.extract 2 0 (local.get $res))))))
193+
194+
;; Allocate a stack
195+
196+
(func $initial_cont
197+
(param $f (ref eq)) (param $x (ref eq)) (result (ref eq))
198+
(return_call_ref $function_1 (local.get $x)
199+
(local.get $f)
200+
(struct.get $closure 0 (ref.cast (ref $closure) (local.get $f)))))
201+
202+
(func (export "caml_alloc_stack")
203+
(param $hv (ref eq)) (param $hx (ref eq)) (param $hf (ref eq))
204+
(result (ref eq))
205+
(struct.new $fiber
206+
(struct.new $handlers (local.get $hv) (local.get $hx) (local.get $hf))
207+
(cont.new $cont (ref.func $initial_cont))))
208+
209+
;; Other functions
210+
211+
(func $caml_continuation_use_noexc (export "caml_continuation_use_noexc")
212+
(param (ref eq)) (result (ref eq))
213+
(local $cont (ref $block))
214+
(local $stack (ref eq))
215+
(drop (block $used (result (ref eq))
216+
(local.set $cont (ref.cast (ref $block) (local.get 0)))
217+
(local.set $stack
218+
(br_on_cast_fail $used (ref eq) (ref $fiber)
219+
(array.get $block (local.get $cont) (i32.const 1))))
220+
(array.set $block (local.get $cont) (i32.const 1)
221+
(ref.i31 (i32.const 0)))
222+
(return (local.get $stack))))
223+
(ref.i31 (i32.const 0)))
224+
225+
(func (export "caml_continuation_use_and_update_handler_noexc")
226+
(param $cont (ref eq)) (param $hval (ref eq)) (param $hexn (ref eq))
227+
(param $heff (ref eq)) (result (ref eq))
228+
(local $stack (ref eq))
229+
(local.set $stack (call $caml_continuation_use_noexc (local.get $cont)))
230+
(drop (block $used (result (ref eq))
231+
(struct.set $fiber $handlers
232+
(br_on_cast_fail $used (ref eq) (ref $fiber)
233+
(local.get $stack))
234+
(struct.new $handlers
235+
(local.get $hval) (local.get $hexn) (local.get $heff)))
236+
(ref.i31 (i32.const 0))))
237+
(local.get $stack))
238+
))
239+
)

runtime/wasm/effect.wat

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,12 @@
211211
(br $loop)))
212212
(local.get $k))
213213

214+
(@string $already_resumed "Effect.Continuation_already_resumed")
215+
216+
(global $effect_allowed (mut i32) (i32.const 1))
217+
218+
(@if (not wasi)
219+
(@then
214220
;; Resume
215221

216222
(func $do_resume (param $k (ref $cont)) (param $vp (ref eq))
@@ -393,6 +399,7 @@
393399
(local.get $hval) (local.get $hexn) (local.get $heff)))
394400
(ref.i31 (i32.const 0))))
395401
(local.get $stack))
402+
))
396403

397404
(func (export "caml_get_continuation_callstack")
398405
(param (ref eq) (ref eq)) (result (ref eq))

runtime/wasm/stdlib.wat

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@
215215
(call $caml_main (ref.func $reraise_exception)))
216216
))
217217

218+
(type $wrapper_func (func (param (ref $func))))
219+
(global $caml_main_wrapper (export "caml_main_wrapper")
220+
(mut (ref null $wrapper_func))
221+
(ref.null $wrapper_func))
222+
218223
(func $caml_main (export "caml_main") (param $start (ref func))
219224
(local $exn (ref eq))
220225
(local $msg (ref eq))
@@ -227,6 +232,11 @@
227232
))
228233
(try
229234
(do
235+
(block $fallback
236+
(call_ref $wrapper_func
237+
(ref.cast (ref $func) (local.get $start))
238+
(br_on_null $fallback (global.get $caml_main_wrapper)))
239+
(return))
230240
(drop (call_ref $func (ref.cast (ref $func) (local.get $start)))))
231241
(catch $ocaml_exit
232242
(call $exit (pop i32)))

0 commit comments

Comments
 (0)