| 
 | 1 | +(module  | 
 | 2 | +(@if (and wasi (<> effects "cps"))  | 
 | 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 $generic_fiber  | 
 | 41 | +      (sub  | 
 | 42 | +         (struct  | 
 | 43 | +            (field $value (mut (ref eq)))  | 
 | 44 | +            (field $exn (mut (ref eq)))  | 
 | 45 | +            (field $effect (mut (ref eq))))))  | 
 | 46 | + | 
 | 47 | +   (type $fiber  | 
 | 48 | +      (sub final $generic_fiber  | 
 | 49 | +         (struct  | 
 | 50 | +            (field $value (mut (ref eq)))  | 
 | 51 | +            (field $exn (mut (ref eq)))  | 
 | 52 | +            (field $effect (mut (ref eq)))  | 
 | 53 | +            (field $cont (mut (ref $cont))))))  | 
 | 54 | + | 
 | 55 | +   ;; Unhandled effects  | 
 | 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 | +(@if (not wasi)  | 
 | 138 | +(@then  | 
 | 139 | +                        (catch $javascript_exception  | 
 | 140 | +                           (br $handle_exception  | 
 | 141 | +                              (call $caml_wrap_exception (pop externref))))  | 
 | 142 | +))  | 
 | 143 | +                        (catch $ocaml_exception  | 
 | 144 | +                           (br $handle_exception (pop (ref eq))))))  | 
 | 145 | +                  ;; handle return  | 
 | 146 | +                  (return_call_ref $function_1 (local.get $res)  | 
 | 147 | +                     (local.tee $f  | 
 | 148 | +                        (struct.get $fiber $value (local.get $fiber)))  | 
 | 149 | +                     (struct.get $closure 0  | 
 | 150 | +                        (ref.cast (ref $closure) (local.get $f))))))  | 
 | 151 | +            ;; handle effect  | 
 | 152 | +            (struct.set $fiber $cont (local.get $fiber)  | 
 | 153 | +               (tuple.extract 2 1 (local.get $resume_res)))  | 
 | 154 | +            (return_call_ref $function_3  | 
 | 155 | +               (tuple.extract 2 0 (local.get $resume_res))  | 
 | 156 | +               (array.new_fixed $block 3 (ref.i31 (global.get $cont_tag))  | 
 | 157 | +                  (local.get $fiber)  | 
 | 158 | +                  (local.get $fiber))  | 
 | 159 | +               (local.get $tail)  | 
 | 160 | +               (local.tee $f  | 
 | 161 | +                  (struct.get $fiber $effect (local.get $fiber)))  | 
 | 162 | +               (struct.get $closure_3 1  | 
 | 163 | +                  (ref.cast (ref $closure_3) (local.get $f))))))  | 
 | 164 | +      ;; handle exception  | 
 | 165 | +      (return_call_ref $function_1 (local.get $exn)  | 
 | 166 | +         (local.tee $f  | 
 | 167 | +            (struct.get $fiber $exn (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 | +      (if (i32.eqz (global.get $effect_allowed))  | 
 | 189 | +         (then  | 
 | 190 | +            (return_call $raise_unhandled  | 
 | 191 | +               (local.get $eff) (ref.i31 (i32.const 0)))))  | 
 | 192 | +      (local.set $res (suspend $effect (local.get $eff)))  | 
 | 193 | +      (return_call_ref $function_1 (tuple.extract 2 1 (local.get $res))  | 
 | 194 | +         (tuple.extract 2 0 (local.get $res))  | 
 | 195 | +         (struct.get $closure 0  | 
 | 196 | +            (ref.cast (ref $closure) (tuple.extract 2 0 (local.get $res))))))  | 
 | 197 | + | 
 | 198 | +   ;; Allocate a stack  | 
 | 199 | + | 
 | 200 | +   (func $initial_cont  | 
 | 201 | +      (param $f (ref eq)) (param $x (ref eq)) (result (ref eq))  | 
 | 202 | +      (return_call_ref $function_1 (local.get $x)  | 
 | 203 | +         (local.get $f)  | 
 | 204 | +         (struct.get $closure 0 (ref.cast (ref $closure) (local.get $f)))))  | 
 | 205 | + | 
 | 206 | +   (func (export "caml_alloc_stack")  | 
 | 207 | +      (param $hv (ref eq)) (param $hx (ref eq)) (param $hf (ref eq))  | 
 | 208 | +      (result (ref eq))  | 
 | 209 | +      (struct.new $fiber  | 
 | 210 | +         (local.get $hv) (local.get $hx) (local.get $hf)  | 
 | 211 | +         (cont.new $cont (ref.func $initial_cont))))  | 
 | 212 | +))  | 
 | 213 | +)  | 
0 commit comments