Conversation
This comment has been minimized.
This comment has been minimized.
Contributor
CI Test ResultsRun: #35868811509 | Commit:
Status Overview
Legend: ✅ passed | ❌ failed | ⚪ skipped | 🚫 cancelled Summary: Total: 32 | Passed: 32 | Failed: 0 Updated: 2026-09-23 14:01:26 UTC |
rkennke
force-pushed
the
sphinx/fix-jira-PROF-15955
branch
from
September 22, 2026 16:48
a78aa75 to
36ff97c
Compare
Contributor
walkVM fed the raw walking pc to findLibraryByAddress, findFrameDesc and the DW_REG_PLT stub-offset test. Past the leaf that pc is a return address, so a call that is the last instruction of its caller selected the following function's CFA row, derived a sender sp from it, and could miss a MARK_THREAD_ENTRY sitting on the caller -- the same defect already fixed in StackWalker::walkFP/walkDwarf, on the path CSTACK_DEFAULT actually resolves to. Track per-frame whether the pc came out of a return-address slot and route the range-based lookups through attributionPC(). Exact-address consumers (isContReturnBarrier, isContEntryReturnPc, isEntryFrame), the DW_PC_OFFSET arithmetic and the no-progress guard keep the raw pc, and a signal-frame CIE suppresses the adjustment exactly as it does in walkDwarf. resolveNativeFrameForWalkVM was using one address for two jobs. It now takes the attribution address for findLibraryByAddress/binarySearch while the emitted pc_offset keeps deriving from the raw pc, so the remote-symbolication wire value is unchanged and no cross-team contract moves. unwindPrologue/unwindEpilogue/unwindStub are left alone: x86_64 already folds the adjustment into the pc they return and does so inconsistently (the isFrameComplete branch omits it) while aarch64 returns it raw, so their results are flagged as non-return-addresses and cannot be adjusted twice. Unifying that contract also fixes the exact-address comparisons those helpers currently break on x86_64, and is left to its own change. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
rkennke
force-pushed
the
sphinx/fix-jira-PROF-15955
branch
from
September 23, 2026 13:41
36ff97c to
09d5f7d
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses PROF-15955.
Summary
HotspotSupport::walkVMfed the raw walking pc tofindLibraryByAddress,findFrameDescand theDW_REG_PLTstub-offset test. Past the leaf that pc is a return address, so a call that is the last instruction of its caller selected the following function's CFA row, derived a sender sp from it, and could miss aMARK_THREAD_ENTRYsitting on the caller. Same defect #786 fixed inStackWalker::walkFP/walkDwarf— except this is the pathCSTACK_DEFAULTactually resolves to whenever the JVM exposes VMStructs on Linux, so it is the common production configuration rather than a fallback.walkVM now tracks per-frame whether the pc came out of a return-address slot and routes the range-based lookups through
attributionPC().Which pcs get adjusted, and which deliberately do not
findLibraryByAddress,findFrameDescDW_REG_PLTstub-offset testisContReturnBarrier,isContEntryReturnPc,isEntryFrameDW_PC_OFFSETarithmeticDW_OP_breg<PC>names the pc register valueinDeadZoneisFrameCompleteAt,findScopeOffset(PcDesc)A signal-frame CIE suppresses the adjustment exactly as it does in
walkDwarf(pc_is_ra = !f.isSignalFrame()).Every site in walkVM that writes
pc— 16 of them — sets the flag. Two were missing from the original enumeration in the ticket: both in-loopanchor->getFrame(pc, sp, fp)calls silently rewritepctolastJavaPC(), which is a return address.The wire format does not move
resolveNativeFrameForWalkVMwas using one address for two jobs: range lookups and the emitted remote-symbolicationpc_offset. It now takes the attribution address forfindLibraryByAddress/binarySearchwhilepc_offsetkeeps deriving from the raw pc, so the emitted wire value is byte-identical.This matters for review: it means this PR does not depend on the unresolved cross-team question about
pc_offsetsemantics raised in #786. It is effectively option (b) from that PR's own list of options, applied locally.Two findings that correct the ticket's premises
The suspected PcDesc double-subtraction bug does not exist. PROF-15955 flagged that x64's ad hoc
-1being re-fed intoisFrameCompleteAt/findScopeOffsetmight be a second latent bug. It is not:findScopeOffset(vmStructs.cpp:798) is a ceiling search — on an exact miss it returns the first PcDesc with_pc >= pc_offset— and HotSpot records PcDescs at return addresses, soRA-1andRAresolve to the same entry.isFrameCompleteAtis a monotone threshold. Both absorb the decrement, so the PcDesc sites are safe on the raw pc.There is a different, real x86_64 bug — filed as PROF-16033, not fixed here.
unwindPrologue/unwindEpilogue/unwindStubfold-1into the pc they return on x86_64 but not on aarch64, so on x86_64 the three exact-equality comparisons above always fail for pcs arriving through those helpers: continuation-boundary and entry-frame detection silently do not fire. The adjustment is also branch-inconsistent (unwindPrologue'sisFrameCompletebranch athotspotStackFrame_x64.cpp:155omits it), which is why a correct flag cannot be threaded without changing those helpers' contract.Those three call sites are therefore flagged
pc_is_ra = falsehere — conservative, cannot double-adjust, and no behaviour change on either arch. The arch files are untouched. Fixing them properly means touching x86_64/aarch64 pattern-matching code shared with the legacygetJavaTraceAsync/AsyncGetCallTrace path, which is a different blast radius and belongs in its own change.Deliberately left untouched
Per the ticket's step 5, calling these out so they do not read as oversights:
CodeHeap::findNMethod,isFrameCompleteAt,findScopeOffset→ PcDesc) stay on the raw pc — correct by HotSpot's own convention, confirmed above.unwindPrologue/unwindEpilogue/unwindStub— PROF-16033.unwindCompiled— same inconsistency, but only reachable from the AGCT path, not walkVM. Covered by PROF-16033.PerfEvents::walkKernel— carries a related defect but is outside PROF-15955's scope; it is a pure consumer of the kernel's ring buffer and would be a much smaller separate change.Test plan
buildDebug— cleanbuildRelease— cleangtestDebug— 64 test binaries, 0 failures, including Fix: PROF-15934 - native stack walker return-address attribution #786'sreturnAddressAttribution_utwalkVM's affected paths only fire inside a live JVM, and
resolveNativeFrameForWalkVMresolves through theLibrariessingleton whose_native_libsis private with no injection seam. Adding a test that exercises adjacent code rather than the changed code would be false confidence, so none was added. The passing suite establishes no regression, not correctness. Real coverage needs the harness described in step 4 of the ticket — a synthetic CodeCache/Libraries seam, or a live-JVM fixture forcing a noreturn call as the last instruction of a native function reached from Java — and that is its own piece of work.Reviewers: the judgement calls worth pushing back on are (a) the raw-vs-attribution split in the table above, and (b) whether shipping this without behavioural coverage is acceptable given walkVM is the default path.
🤖 Generated with Claude Code