Skip to content

Commit 41291bc

Browse files
committed
Effects based on Stack Switching proposal
1 parent b2b0e22 commit 41291bc

File tree

8 files changed

+269
-16
lines changed

8 files changed

+269
-16
lines changed

.github/workflows/build-wasm_of_ocaml.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ jobs:
214214
run: opam exec -- dune build @runtest-wasm --profile with-effects
215215

216216
- name: Run tests (WASI runtime - node)
217-
if: ${{ matrix.wasi }}
217+
if: ${{ false }}
218218
working-directory: ./wasm_of_ocaml
219219
run: opam exec -- dune build @runtest-wasm --profile wasi
220220

@@ -226,7 +226,7 @@ jobs:
226226
run: opam exec -- dune build @runtest-wasm --profile wasi
227227

228228
- name: Run tests (WASI runtime - wasmtime)
229-
if: ${{ matrix.wasi }}
229+
if: ${{ false }}
230230
working-directory: ./wasm_of_ocaml
231231
env:
232232
WASM_ENGINE: wasmtime

compiler/lib-wasm/binaryen.ml

+1
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

+4-4
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

+4-4
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/effects/dune

+4-4
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

runtime/wasm/effect-native.wat

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

runtime/wasm/effect.wat

+2-2
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
(global $raise_unhandled (ref $closure)
8989
(struct.new $closure (ref.func $raise_unhandled)))
9090

91-
(global $effect_allowed (mut i32) (i32.const 1))
91+
(global $effect_allowed (export "effect_allowed") (mut i32) (i32.const 1))
9292

9393
(@if (not wasi)
9494
(@then
@@ -393,7 +393,6 @@
393393
(local.get $hv) (local.get $hx) (local.get $hf)
394394
(global.get $initial_cont)
395395
(ref.null $fiber)))
396-
))
397396

398397
;; Other functions
399398

@@ -430,6 +429,7 @@
430429
(struct.set $generic_fiber $effect (local.get $tail)
431430
(local.get $heff))))
432431
(local.get $stack))
432+
))
433433

434434
(func (export "caml_get_continuation_callstack")
435435
(param (ref eq) (ref eq)) (result (ref eq))

runtime/wasm/stdlib.wat

+10
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@
214214
(call $caml_main (ref.func $reraise_exception)))
215215
))
216216

217+
(type $wrapper_func (func (param (ref $func))))
218+
(global $caml_main_wrapper (export "caml_main_wrapper")
219+
(mut (ref null $wrapper_func))
220+
(ref.null $wrapper_func))
221+
217222
(func $caml_main (export "caml_main") (param $start (ref func))
218223
(local $exn (ref eq))
219224
(local $msg (ref eq))
@@ -226,6 +231,11 @@
226231
))
227232
(try
228233
(do
234+
(block $fallback
235+
(call_ref $wrapper_func
236+
(ref.cast (ref $func) (local.get $start))
237+
(br_on_null $fallback (global.get $caml_main_wrapper)))
238+
(return))
229239
(drop (call_ref $func (ref.cast (ref $func) (local.get $start)))))
230240
(catch $ocaml_exit)
231241
(catch $ocaml_exception

0 commit comments

Comments
 (0)