(* Surgical repro for the serving-JIT OP_PERFORM/resume stack misalignment.
   Mirrors what register_jit_hook's resolve_loop does: call_closure, catch
   VmSuspended, resolve IO (return Nil), resume_vm — looping on re-suspend.
   No CEK evaluator needed for the direct/multi-frame/reuse paths. *)

open Sx_types

let req_dict () =
  let h = Hashtbl.create 1 in
  Hashtbl.replace h "op" (String "noop");
  Dict h

(* Mirror the serving hook's resolve loop exactly. *)
let drive cl =
  let globals = cl.vm_closure_env |> ignore; cl.vm_env_ref in
  let rec resolve_loop req vm =
    let _ = req in
    (try Sx_vm.resume_vm vm Nil
     with Sx_vm.VmSuspended (r2, v2) -> resolve_loop r2 v2)
  in
  try Sx_vm.call_closure cl [] globals
  with Sx_vm.VmSuspended (req, vm) -> resolve_loop req vm

let mk_code ~locals ~bc ~consts = {
  vc_arity = 0; vc_rest_arity = -1; vc_locals = locals;
  vc_bytecode = Array.of_list bc;
  vc_constants = Array.of_list consts;
  vc_bytecode_list = None; vc_constants_list = None;
}

let mk_cl ?(name="tf") ?(env=Hashtbl.create 64) code =
  { vm_code = code; vm_upvalues = [||]; vm_name = Some name;
    vm_env_ref = env; vm_closure_env = None }

let report label v =
  Printf.printf "%-28s => %s\n%!" label (Sx_runtime.value_to_str v)

let run label f =
  (try report label (f ())
   with
   | Eval_error m -> Printf.printf "%-28s => ERROR: %s\n%!" label m
   | e -> Printf.printf "%-28s => EXN: %s\n%!" label (Printexc.to_string e))

(* opcodes *)
let _const i = [1; i land 0xff; (i lsr 8) land 0xff]
let _perform = [112]
let _pop = [5]
let _call_prim idx argc = [52; idx land 0xff; (idx lsr 8) land 0xff; argc]
let _call argc = [48; argc]
let _return = [50]

let () =
  (* Serving mode: a synchronous IO resolver is installed (mirrors
     sx_server's http setup). Our mock resolves every request to Nil. *)
  Sx_types._cek_io_resolver := Some (fun _req _ -> Nil);

  (* Case 1: direct OP_PERFORM then a list prim in the SAME frame.
     (do (perform {..}) (rest (list 1 2 3)))  =>  (2 3) *)
  run "1.direct perform→rest" (fun () ->
    let consts = [ req_dict (); List [Number 1.; Number 2.; Number 3.]; String "rest" ] in
    let bc = _const 0 @ _perform @ _pop @ _const 1 @ _call_prim 2 1 @ _return in
    drive (mk_cl (mk_code ~locals:0 ~bc ~consts)));

  (* Case 2: direct perform then map (2-arg prim).
     (do (perform {..}) (map inc (list 1 2 3)))  — needs a fn; use a NativeFn const *)
  run "2.direct perform→map" (fun () ->
    let inc = NativeFn ("inc1", function [Number n] -> Number (n +. 1.) | _ -> Nil) in
    let consts = [ req_dict (); inc; List [Number 1.; Number 2.; Number 3.]; String "map" ] in
    (* push fn, push list, CALL_PRIM map 2 *)
    let bc = _const 0 @ _perform @ _pop @ _const 1 @ _const 2 @ _call_prim 3 2 @ _return in
    drive (mk_cl (mk_code ~locals:0 ~bc ~consts)));

  (* Case 3: multi-frame — outer calls a JIT'd helper that performs, THEN outer maps.
     helper: (do (perform {..}) 99)
     outer:  (do (helper) (map inc (list 1 2 3))) *)
  run "3.multiframe perform→map" (fun () ->
    let env = Hashtbl.create 64 in
    let helper_code = mk_code ~locals:0
      ~bc:(_const 0 @ _perform @ _pop @ _const 1 @ _return)
      ~consts:[ req_dict (); Number 99. ] in
    let helper_cl = mk_cl ~name:"helper" ~env helper_code in
    let inc = NativeFn ("inc1", function [Number n] -> Number (n +. 1.) | _ -> Nil) in
    let consts = [ VmClosure helper_cl; inc; List [Number 1.; Number 2.; Number 3.]; String "map" ] in
    (* push helper-closure, CALL 0, POP its result, push inc, push list, CALL_PRIM map 2 *)
    let bc = _const 0 @ _call 0 @ _pop @ _const 1 @ _const 2 @ _call_prim 3 2 @ _return in
    drive (mk_cl ~name:"outer" ~env (mk_code ~locals:0 ~bc ~consts)));

  (* Case 4: map whose CALLBACK performs (reuse_stack path), then a trailing prim.
     callback: (do (perform {..}) (inc e))   — but callback gets arg e in slot 0
     outer: (do (map cb (list 1 2 3)) (rest (list 7 8 9)))  *)
  run "4.map-callback-perform" (fun () ->
    let env = Hashtbl.create 64 in
    (* callback arity 1: slot0 = e. body: (perform {..}); (inc e) ; return
       LOCAL_GET 0 then CALL_PRIM inc... use NativeFn inc via CALL_PRIM *)
    let cb_code = {
      vc_arity = 1; vc_rest_arity = -1; vc_locals = 1;
      vc_bytecode = Array.of_list (_const 0 @ _perform @ _pop
                                   @ [16;0] (* LOCAL_GET 0 *)
                                   @ _call_prim 1 1 @ _return);
      vc_constants = [| req_dict (); String "inc" |];
      vc_bytecode_list = None; vc_constants_list = None } in
    let cb_cl = mk_cl ~name:"cb" ~env cb_code in
    let consts = [ VmClosure cb_cl; List [Number 1.; Number 2.; Number 3.]; String "map";
                   List [Number 7.; Number 8.; Number 9.]; String "rest" ] in
    (* push cb, push list, CALL_PRIM map 2, POP, push list2, CALL_PRIM rest 1, RETURN *)
    let bc = _const 0 @ _const 1 @ _call_prim 2 2 @ _pop @ _const 3 @ _call_prim 4 1 @ _return in
    drive (mk_cl ~name:"outer4" ~env (mk_code ~locals:0 ~bc ~consts)));

  (* Case 5: THE HOST CASE — perform via an INTERPRETED helper (pending_cek path),
     then a list prim. helper is a Lambda (l_compiled = jit_failed) whose body
     performs; vm_call routes it through cek_call_or_suspend → pending_cek.
       helper: (perform {..})  [interpreted via CEK]
       outer:  (do (helper) (rest (list 1 2 3)))  => (2 3) *)
  run "5.pending_cek perform→rest" (fun () ->
    let env = Sx_types.make_env () in
    let helper = Lambda {
      l_params = []; l_body = List [Symbol "perform"; req_dict ()];
      l_closure = env; l_name = Some "kvread";
      l_compiled = Some Sx_vm.jit_failed_sentinel; l_call_count = 0;
      l_uid = Sx_types.next_lambda_uid () } in
    let consts = [ helper; List [Number 1.; Number 2.; Number 3.]; String "rest" ] in
    (* push helper, CALL 0, POP, push list, CALL_PRIM rest 1, RETURN *)
    let bc = _const 0 @ _call 0 @ _pop @ _const 1 @ _call_prim 2 1 @ _return in
    drive (mk_cl ~name:"outer5" ~env:(Hashtbl.create 64) (mk_code ~locals:0 ~bc ~consts)));

  (* Case 6: pending_cek perform → MAP (2-arg), the exact host shape. *)
  run "6.pending_cek perform→map" (fun () ->
    let env = Sx_types.make_env () in
    let helper = Lambda {
      l_params = []; l_body = List [Symbol "perform"; req_dict ()];
      l_closure = env; l_name = Some "kvread";
      l_compiled = Some Sx_vm.jit_failed_sentinel; l_call_count = 0;
      l_uid = Sx_types.next_lambda_uid () } in
    let inc = NativeFn ("inc1", function [Number n] -> Number (n +. 1.) | _ -> Nil) in
    let consts = [ helper; inc; List [Number 1.; Number 2.; Number 3.]; String "map" ] in
    (* push helper, CALL 0, POP, push inc, push list, CALL_PRIM map 2, RETURN *)
    let bc = _const 0 @ _call 0 @ _pop @ _const 1 @ _const 2 @ _call_prim 3 2 @ _return in
    drive (mk_cl ~name:"outer6" ~env:(Hashtbl.create 64) (mk_code ~locals:0 ~bc ~consts)));

  (* Case 7: THE HOST SHAPE — map whose callback calls an INTERPRETED helper
     that performs (kv read via persist helper inside a map), THEN a trailing
     prim. callback(e): (do (kvread) e)  — kvread suspends via pending_cek.
     outer: (do (map cb (list 1 2 3)) (drop (list 5 6 7 8) 2)) => (7 8) *)
  run "7.HOST: map[cb→helper perform]→drop" (fun () ->
    let genv = Sx_types.make_env () in
    let helper = Lambda {
      l_params = []; l_body = List [Symbol "perform"; req_dict ()];
      l_closure = genv; l_name = Some "kvread";
      l_compiled = Some Sx_vm.jit_failed_sentinel; l_call_count = 0;
      l_uid = Sx_types.next_lambda_uid () } in
    let env = Hashtbl.create 64 in
    (* cb(e): push helper, CALL 0, POP, LOCAL_GET 0, RETURN *)
    let cb_code = {
      vc_arity = 1; vc_rest_arity = -1; vc_locals = 1;
      vc_bytecode = Array.of_list (_const 0 @ _call 0 @ _pop @ [16;0] @ _return);
      vc_constants = [| helper |]; vc_bytecode_list=None; vc_constants_list=None } in
    let cb_cl = mk_cl ~name:"cb7" ~env cb_code in
    let consts = [ VmClosure cb_cl; List [Number 1.; Number 2.; Number 3.]; String "map";
                   List [Number 5.; Number 6.; Number 7.; Number 8.]; Number 2.; String "drop" ] in
    (* push cb, push list, CALL_PRIM map 2, POP, push list2, push 2, CALL_PRIM drop 2, RETURN *)
    let bc = _const 0 @ _const 1 @ _call_prim 2 2 @ _pop
             @ _const 3 @ _const 4 @ _call_prim 5 2 @ _return in
    drive (mk_cl ~name:"outer7" ~env (mk_code ~locals:0 ~bc ~consts)));

  (* Case 8: reduce whose callback performs. (reduce + 0 (list 1 2 3)) with a
     perform in the reducer => 6 *)
  run "8.reduce[acc→perform]" (fun () ->
    let env = Hashtbl.create 64 in
    (* reducer(acc e): (do (perform {..}) (+ acc e)). slots: 0=acc 1=e *)
    let rd_code = {
      vc_arity = 2; vc_rest_arity = -1; vc_locals = 2;
      vc_bytecode = Array.of_list (_const 0 @ _perform @ _pop
                                   @ [16;0] @ [16;1] @ _call_prim 1 2 @ _return);
      vc_constants = [| req_dict (); String "+" |];
      vc_bytecode_list=None; vc_constants_list=None } in
    let rd_cl = mk_cl ~name:"rd" ~env rd_code in
    let consts = [ VmClosure rd_cl; Number 0.; List [Number 1.; Number 2.; Number 3.]; String "reduce" ] in
    (* push reducer, push 0, push list, CALL_PRIM reduce 3, RETURN *)
    let bc = _const 0 @ _const 1 @ _const 2 @ _call_prim 3 3 @ _return in
    drive (mk_cl ~name:"outer8" ~env (mk_code ~locals:0 ~bc ~consts)));

  (* Case 9: nested map — outer map callback runs an inner map whose callback
     performs. outer over (list 1 2), inner over (list 10 20) performing.
     cb_outer(x): (map cb_inner (list 10 20)) ; cb_inner(y): (do (perform) y)
     => ((10 20) (10 20)) *)
  run "9.nested map[inner→perform]" (fun () ->
    let env = Hashtbl.create 64 in
    let inner_code = {
      vc_arity = 1; vc_rest_arity = -1; vc_locals = 1;
      vc_bytecode = Array.of_list (_const 0 @ _perform @ _pop @ [16;0] @ _return);
      vc_constants = [| req_dict () |]; vc_bytecode_list=None; vc_constants_list=None } in
    let inner_cl = mk_cl ~name:"cbin" ~env inner_code in
    (* outer cb(x): push inner_cl, push (10 20), CALL_PRIM map 2, RETURN *)
    let outer_cb_code = {
      vc_arity = 1; vc_rest_arity = -1; vc_locals = 1;
      vc_bytecode = Array.of_list (_const 0 @ _const 1 @ _call_prim 2 2 @ _return);
      vc_constants = [| VmClosure inner_cl; List [Number 10.; Number 20.]; String "map" |];
      vc_bytecode_list=None; vc_constants_list=None } in
    let outer_cb_cl = mk_cl ~name:"cbout" ~env outer_cb_code in
    let consts = [ VmClosure outer_cb_cl; List [Number 1.; Number 2.]; String "map" ] in
    let bc = _const 0 @ _const 1 @ _call_prim 2 2 @ _return in
    drive (mk_cl ~name:"outer9" ~env (mk_code ~locals:0 ~bc ~consts)))
