Skip to content

ABI: preserve debugger async-call lifecycle and stacks #259

Description

@chrisbbreuer

Parent: #140
Tracked by: #134, #139, #163, #164

Implement the four shared Home/Bun Debugger__*AsyncCall exports as one coherent inspector lifecycle boundary. The pinned consumer enum and declarations are byte-identical in Home Debugger.zig and Bun src/jsc/Debugger.zig; the pinned Bun C++ bridge maps values 1–5 to JavaScriptCore inspector call types, returns immediately without an attached debugger agent, and forwards schedule/cancel/will-dispatch/did-dispatch to that agent.

Acceptance

  • Pin the exact Home/Bun declaration hashes and Bun BunDebugger.cpp forwarding semantics, including the enum(u8) values DOMTimer=1, EventListener=2, PostMessage=3, RequestAnimationFrame=4, and Microtask=5.
  • Implement Debugger__didScheduleAsyncCall, Debugger__didCancelAsyncCall, Debugger__willDispatchAsyncCall, and Debugger__didDispatchAsyncCall with the exact C ABI and same-VM global validation.
  • Preserve the no-agent fast no-op, including no dereference or enum assertion when no debugger is attached; with an agent, reject invalid call types as an ABI contract violation rather than silently aliasing them.
  • Track scheduled calls by (AsyncCallType, callbackId), preserve the scheduling stack and selected global, support repeated/non-single-shot dispatch, and retire single-shot and cancelled calls at the exact lifecycle boundary.
  • Make willDispatch install the matching async parent for debugger pauses/errors and make didDispatch restore nested/reentrant dispatch state without leaking one task's ancestry into another.
  • Define and test duplicate schedule, missing cancel/dispatch, sibling-realm, foreign-VM, detach/reattach, callback-id extremes, all five call types, and teardown behavior without retaining a dead realm or VM.
  • Extend the generated compile-link-runtime fixture through all four exports and add inspector protocol evidence that an async dispatch exposes the captured parent stack only while active.
  • Mark all four exports implemented in both inventories, preserve zero unclassified entries, and update the README/private ABI counts and evidence.

Design constraint

A symbol-only no-op is not completion. These hooks exist to preserve debugger async causality, but their bookkeeping must remain dormant when no inspector agent is attached and must never turn into a general runtime root.

Evidence

Completed on main in runtime commit ed109b6d with README/private-ABI evidence in 8ee1ef21.

  • docs/abi/debugger-async-call-contract.json pins both declaration files, Bun C++ forwarding, the five exact enum(u8) values, and the no-agent/invalid-agent boundaries.
  • Focused coverage exercises no-agent behavior, all call types, zero/max callback IDs, sibling and foreign VMs, duplicate/cancel/missing operations, nested LIFO dispatch, single-shot/repeated calls, protocol projection, disable, and teardown.
  • Full suite from the clean runtime commit: 989/989 passed, zero skipped, zero failed, zero leaked.
  • Generated Home consumer: 278/278 symbols linked; runtime matrix passed.
  • Home inventory: 276/431 implemented, 155 pending, zero unclassified.
  • Bun core inventory: 268/421 implemented, 153 pending, zero unclassified.
  • Public/private export audit: 117 public functions complete and 284 classified private profile exports.
  • The committed 1,540-sample benchmark matrix remains current because these dormant/inspector-only hooks are outside its workloads.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions