Lambda→CEK dispatch: enable IO suspension through sx_call
Lambda calls in sx_call now go through the CEK machine instead of returning a Thunk for the tree-walker trampoline. This lets perform/ IO suspension work everywhere — including hyperscript wait/bounce. Key changes: - sx_runtime: Lambda case calls _cek_eval_lambda_ref (forward ref) - sx_vm: initializes ref with cek_step_loop + stub VM for suspension - sx_apply_cek: VmSuspended → __vm_suspended marker dict (not exception) - continue_with_call callable path: handles __vm_suspended with vm-resume-frame, matching the existing JIT Lambda pattern - sx_render: let VmSuspended propagate through try_catch - Remove invalid io-contract test (perform now suspends, not errors) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,15 @@ type vm = {
|
||||
ip past OP_PERFORM, stack ready for a result push). *)
|
||||
exception VmSuspended of value * vm
|
||||
|
||||
(* Register the VM suspension converter so sx_runtime.sx_apply_cek can
|
||||
catch VmSuspended and convert it to CekPerformRequest without a
|
||||
direct dependency on this module. *)
|
||||
let () = Sx_types._convert_vm_suspension := (fun exn ->
|
||||
match exn with
|
||||
| VmSuspended (request, _vm) -> raise (CekPerformRequest request)
|
||||
| _ -> ())
|
||||
|
||||
|
||||
(** Forward reference for JIT compilation — set after definition. *)
|
||||
let jit_compile_ref : (lambda -> (string, value) Hashtbl.t -> vm_closure option) ref =
|
||||
ref (fun _ _ -> None)
|
||||
@@ -936,6 +945,27 @@ let jit_compile_lambda (l : lambda) globals =
|
||||
(* Wire up forward references *)
|
||||
let () = jit_compile_ref := jit_compile_lambda
|
||||
let () = _vm_call_closure_ref := (fun cl args -> call_closure_reuse cl args)
|
||||
let () = _vm_suspension_to_dict := (fun exn ->
|
||||
match exn with
|
||||
| VmSuspended (request, vm) ->
|
||||
let d = Hashtbl.create 3 in
|
||||
Hashtbl.replace d "__vm_suspended" (Bool true);
|
||||
Hashtbl.replace d "request" request;
|
||||
Hashtbl.replace d "resume" (NativeFn ("vm-resume", fun args ->
|
||||
match args with [result] -> resume_vm vm result | _ -> Nil));
|
||||
Some (Dict d)
|
||||
| _ -> None)
|
||||
let () = _cek_eval_lambda_ref := (fun f args ->
|
||||
let state = Sx_ref.continue_with_call f (List args) (Env (make_env ())) (List args) (List []) in
|
||||
let final = Sx_ref.cek_step_loop state in
|
||||
match Sx_runtime.get_val final (String "phase") with
|
||||
| String "io-suspended" ->
|
||||
(* Create a stub VM to carry the suspended CEK state.
|
||||
resume_vm will: cek_resume → push result → run (no-op, no frames) → pop *)
|
||||
let vm = create (Hashtbl.create 0) in
|
||||
vm.pending_cek <- Some final;
|
||||
raise (VmSuspended (Sx_runtime.get_val final (String "request"), vm))
|
||||
| _ -> Sx_ref.cek_value final)
|
||||
|
||||
|
||||
(** {1 Debugging / introspection} *)
|
||||
|
||||
Reference in New Issue
Block a user