HS tests: VM step limit fix, callFn error propagation, compiler emit-set fixes
- sx_vm.ml: VM timeout now compares vm_insn_count > step_limit instead of
unconditionally throwing after 65536 instructions when limit > 0
- sx_browser.ml: Expose setStepLimit/resetStepCount APIs on SxKernel;
callFn now returns {__sx_error, message} on Eval_error instead of null
- compiler.sx: emit-set handles array-index targets (host-set! instead of
nth) and 'of' property chains (dom-set-prop with chain navigation)
- hs-run-fast.js: New Node.js test runner with step-limit timeouts,
SX-level guard for error detection, insertAdjacentHTML mock,
range selection (HS_START/HS_END), wall-clock timeout in driveAsync
- hs-debug-test.js: Single-test debugger with DOM state inspection
- hs-verify.js: Assertion verification (proves pass/fail detection works)
Test results: 415/831 (50%), up from 408/831 (49%) baseline.
Fixes: set my style["color"], set X of Y, put at end of (insertAdjacentHTML).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -544,15 +544,14 @@ let api_call_fn fn_js args_js =
|
||||
sync_vm_to_env ();
|
||||
Js.Unsafe.inject (make_js_callFn_suspension request vm)
|
||||
| Eval_error msg ->
|
||||
ignore (Js.Unsafe.meth_call
|
||||
(Js.Unsafe.get Js.Unsafe.global (Js.string "console"))
|
||||
"error" [| Js.Unsafe.inject (Js.string ("[sx] callFn: " ^ msg)) |]);
|
||||
Js.Unsafe.inject Js.null
|
||||
(* Store the error message so callers can detect it *)
|
||||
let err_obj = Js.Unsafe.obj [| ("__sx_error", Js.Unsafe.inject Js._true);
|
||||
("message", Js.Unsafe.inject (Js.string msg)) |] in
|
||||
Js.Unsafe.inject err_obj
|
||||
| exn ->
|
||||
ignore (Js.Unsafe.meth_call
|
||||
(Js.Unsafe.get Js.Unsafe.global (Js.string "console"))
|
||||
"error" [| Js.Unsafe.inject (Js.string ("[sx] callFn: " ^ Printexc.to_string exn)) |]);
|
||||
Js.Unsafe.inject Js.null
|
||||
let err_obj = Js.Unsafe.obj [| ("__sx_error", Js.Unsafe.inject Js._true);
|
||||
("message", Js.Unsafe.inject (Js.string (Printexc.to_string exn))) |] in
|
||||
Js.Unsafe.inject err_obj
|
||||
|
||||
let api_is_callable fn_js =
|
||||
if Js.Unsafe.equals fn_js Js.null || Js.Unsafe.equals fn_js Js.undefined then
|
||||
@@ -1049,4 +1048,16 @@ let () =
|
||||
let log = Sx_primitives.scope_trace_drain () in
|
||||
Js.Unsafe.inject (Js.array (Array.of_list (List.map (fun s -> Js.Unsafe.inject (Js.string s)) log)))));
|
||||
|
||||
(* Step limit for timeout protection *)
|
||||
Js.Unsafe.set sx (Js.string "setStepLimit") (Js.wrap_callback (fun n ->
|
||||
let limit = Js.float_of_number (Js.Unsafe.coerce n) |> int_of_float in
|
||||
Sx_ref.step_limit := limit;
|
||||
Sx_ref.step_count := 0;
|
||||
Sx_vm.vm_reset_counters ();
|
||||
Js.Unsafe.inject Js.null));
|
||||
Js.Unsafe.set sx (Js.string "resetStepCount") (Js.wrap_callback (fun () ->
|
||||
Sx_ref.step_count := 0;
|
||||
Sx_vm.vm_reset_counters ();
|
||||
Js.Unsafe.inject Js.null));
|
||||
|
||||
Js.Unsafe.set Js.Unsafe.global (Js.string "SxKernel") sx
|
||||
|
||||
@@ -448,8 +448,9 @@ and run vm =
|
||||
let op = bc.(frame.ip) in
|
||||
frame.ip <- frame.ip + 1;
|
||||
incr _vm_insn_count;
|
||||
(* Check timeout flag set by SIGALRM *)
|
||||
if !_vm_insn_count land 0xFFFF = 0 && !Sx_ref.step_limit > 0 then
|
||||
(* Check timeout — compare VM instruction count against step limit *)
|
||||
if !_vm_insn_count land 0xFFFF = 0 && !Sx_ref.step_limit > 0
|
||||
&& !_vm_insn_count > !Sx_ref.step_limit then
|
||||
raise (Eval_error "TIMEOUT: step limit exceeded");
|
||||
(try match op with
|
||||
(* ---- Constants ---- *)
|
||||
|
||||
Reference in New Issue
Block a user