Skip to content

Add mixed-mode stepping with a focus-set policy (new default)#412

Open
KristofferC wants to merge 1 commit into
masterfrom
kc/auto_compiled_methods
Open

Add mixed-mode stepping with a focus-set policy (new default)#412
KristofferC wants to merge 1 commit into
masterfrom
kc/auto_compiled_methods

Conversation

@KristofferC

Copy link
Copy Markdown
Member

Interpreting everything through JuliaInterpreter makes stepping over
Base/stdlib/dependency calls painfully slow, while marking them compiled
via the JuliaInterpreter globals breaks stepping into user callbacks
passed to higher-order functions (map, sort(by=...), broadcast, ...).

This adds a MixedInterpreter that decides per call, at runtime: a call
runs natively unless the callee or any argument carries a function or
type from the "focus set" - the modules being debugged. The check walks
runtime types including type parameters, so callbacks survive wrapper
chains (Generator, Broadcasted, kwcall NamedTuples, Base.Fix1, ...) and
calls dispatching on focus types stay interpreted, with no per-method
blacklist. On a sum(sort(rand(100_000))) benchmark, n drops from
218s to 0.27s (~800x).

The focus set is seeded per session: Main, packages loaded from dev
checkouts (pkgdir outside the depots' read-only packages/ stores), and
the entered method's package (except Base/stdlibs). Stepping into a
dependency frame adds it for the session with an info message; stepping
into Base/stdlibs prints a hint instead. For soundness the fast path is
suspended (with a message) while break_on(:error/:throw) is active or a
breakpoint targets a module that native code could reach, including
transitively through reverse dependencies.

UI/API:

  • three modes: interpreted, mixed (default), compiled; prompt shows
    1|mixed> / 1|compiled> with per-mode colors
  • M toggles mixed<->interpreted, C keeps toggling compiled and
    returns to the previous mode; new mode [interpreted|mixed|compiled]
  • new focus command: list the set, focus add Mod, focus rm Mod|i
  • Debugger.set_default_mode!/default_mode, interpret_module!/
    compile_module!/reset_module!, interpreted_modules()

Documented limitations (escape hatch: interpreted mode): type-erased
callbacks (Vector{Any}, ::Function fields), type piracy, and ambient
execution (registries, Tasks, finalizers).

Requires JuliaInterpreter 0.11 (native_call runs in frame.world, giving
consistent Revise semantics).

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

Interpreting everything through JuliaInterpreter makes stepping over
Base/stdlib/dependency calls painfully slow, while marking them compiled
via the JuliaInterpreter globals breaks stepping into user callbacks
passed to higher-order functions (map, sort(by=...), broadcast, ...).

This adds a MixedInterpreter that decides per call, at runtime: a call
runs natively unless the callee or any argument carries a function or
type from the "focus set" - the modules being debugged. The check walks
runtime types including type parameters, so callbacks survive wrapper
chains (Generator, Broadcasted, kwcall NamedTuples, Base.Fix1, ...) and
calls dispatching on focus types stay interpreted, with no per-method
blacklist. On a sum(sort(rand(100_000))) benchmark, `n` drops from
218s to 0.27s (~800x).

The focus set is seeded per session: Main, packages loaded from dev
checkouts (pkgdir outside the depots' read-only packages/ stores), and
the entered method's package (except Base/stdlibs). Stepping into a
dependency frame adds it for the session with an info message; stepping
into Base/stdlibs prints a hint instead. For soundness the fast path is
suspended (with a message) while break_on(:error/:throw) is active or a
breakpoint targets a module that native code could reach, including
transitively through reverse dependencies.

UI/API:
- three modes: interpreted, mixed (default), compiled; prompt shows
  1|mixed> / 1|compiled> with per-mode colors
- `M` toggles mixed<->interpreted, `C` keeps toggling compiled and
  returns to the previous mode; new `mode [interpreted|mixed|compiled]`
- new `focus` command: list the set, `focus add Mod`, `focus rm Mod|i`
- Debugger.set_default_mode!/default_mode, interpret_module!/
  compile_module!/reset_module!, interpreted_modules()

Documented limitations (escape hatch: interpreted mode): type-erased
callbacks (Vector{Any}, ::Function fields), type piracy, and ambient
execution (registries, Tasks, finalizers).

Requires JuliaInterpreter 0.11 (native_call runs in frame.world, giving
consistent Revise semantics).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant