Repository navigation
jdwp_set_fast_breakpoint — conditional breakpoint whose condition runs inside the target JVM #42
Description
Problem
A conditional breakpoint (jdwp_set_breakpoint with condition) suspends the thread on every hit and evaluates the condition through the debugger (method invocation over JDWP), then resumes it when the condition is false. That costs 3–30 ms per hit (measured in #41) and serializes the threads passing the line through the debugger.
In highly concurrent code this changes the thread interleavings enough that the race being hunted often stops reproducing — exactly when the condition is supposed to catch it.
Proposal
A separate tool, jdwp_set_fast_breakpoint, built on the fast-logpoint machinery from #40 / #41. It requires the same explicit userApproved=true consent, because it rewrites the application's bytecode.
On the first hit, the condition is compiled into a probe class defined in the declaring class's loader. The class is redefined with:
if (McpFastBreak_X.test(<locals>)) {
McpFastBreak_X.hit();
}A regular JDI breakpoint (suspend policy all by default) sits on the hit() call or method.
- The condition runs natively, at about 100 ns per hit (the fast-logpoint measurement).
- Threads where the condition is false are never suspended and never round-trip to the debugger.
- Only a true hit stops, and the state can then be inspected without haste.
Reused from fast logpoints
- the consent gate and risk briefing;
- probe compilation against the arming frame;
- ASM instrumentation at the line, redefinition with live-bytecode read-back, and re-creation of breakpoints after redefinition;
- the kill switch;
- the leftover registry (
MCP_*constants,GenerationRecord, RECOVERED / STRANDED classification); - restore on clear, reset, disconnect and shutdown.
Leftover behaviour is better than for a fast logpoint. Without a debugger attached, hit() is an empty call, so a fast breakpoint left behind by a crashed server only costs the condition evaluation.
Design decisions to settle
- Where the JDI breakpoint lives.
- (a) In the probe's
hit()method. The hot method stays JIT-compiled and the request survives redefinitions of the target class. But frame 0 is the probe, so inspection tools (get_locals,evaluate_expression, breakpoint context) must present frame 1 as the current frame. - (b) At the bytecode index of the injected call in the target method (
Method.locationOfCodeIndex). Frame 0 is the user's frame with its locals. But the location moves on every redefinition, and we need to verify whether HotSpot keeps a method that holds a JVMTI breakpoint interpreted, which would slow down the hot method.
- (a) In the probe's
- Stop once or on every true hit. In stop-once mode, the probe could flip its own kill switch after the first true condition so a hot path doesn't stop repeatedly.
- Suspend policy.
allis not atomic: other threads keep running for a short time before they are parked, so the snapshot reflects "shortly after the condition held", not the exact instant. This must be documented.threadshould stay available. - Inspection with all threads suspended. Method invocation (expression evaluation,
to_string) can block on monitors held by parked threads. This is the same as anySUSPEND_ALLbreakpoint today, but worth stating in the tool description. - Condition failures (an exception thrown by the condition) are recorded the way fast logpoints record them, and the hit does not stop. Alternatively it fails open, like
CONDITION_ERROR; this is a policy choice to make.
Out of scope
- Any change to
jdwp_set_breakpointitself; the fast variant is opt-in with consent. - Field and exception variants.
Depends on #41 (fast logpoints and the leftover registry) being merged.
Activity
feat: generate the in-target probe of a fast breakpoint (#42)
feat: arm fast breakpoints and publish their stops (#42)
feat: add the jdwp_set_fast_breakpoint tool (#42)
feat: hide probe frames at a fast stop and step out of probes (#42)
feat: never redefine a method a stopped thread is in; arming and remo…
feat: watchers on fast breakpoints, a full-stack scan of every breakp…
fix: the fast-breakpoint briefing and tool descriptions say how a cle…
docs: fast breakpoints and the redefinition rule in the docs, README …
fix: fast-breakpoint findings of the Codex code review (#42)
Merge pull request #46 from FgForrest/feat/fast-breakpoint-42
chore: release 2.11.0 — fast logpoints, fast breakpoints and suspensi…