Skip to content

Conversation

davidwrighton
Copy link
Member

Fix various points in the runtime which need to handle the situation of the interpreter precode existing, and allowing the interpreter precode to be considered "part" of the code of the method.

I expect that we may eventually need to treat the interpreter precode as either the "hot" or "cold" code region of the function, but I'm not certain of that yet.

@Copilot Copilot AI review requested due to automatic review settings August 13, 2025 20:20
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Aug 13, 2025
@davidwrighton davidwrighton added area-CodeGen-Interpreter-coreclr and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Aug 13, 2025
@davidwrighton davidwrighton requested review from kg and janvorli August 13, 2025 20:21
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes various points in the CoreCLR runtime to properly handle the interpreter precode when interacting with the debugger. The changes ensure that the interpreter precode is considered "part" of the method code during debugging operations and code analysis.

Key changes:

  • Modifies code discovery logic to handle interpreter precodes by following them to their actual bytecode addresses
  • Updates method compilation checks to use HasNativeCode() instead of direct null checks
  • Removes obsolete interpreter-specific code from event tracing that's now handled more generically

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/coreclr/vm/multicorejitplayer.cpp Updates method compilation check to use HasNativeCode() method
src/coreclr/vm/method.cpp Adds interpreter precode handling in NonVirtualEntry2MethodDesc function
src/coreclr/vm/jitinterface.cpp Adds interpreter precode detection and bytecode address resolution in EECodeInfo::Init
src/coreclr/vm/eventtrace.cpp Removes obsolete interpreter-specific code handling
src/coreclr/debug/daccess/task.cpp Refactors code address retrieval in GetRepresentativeEntryAddress
src/coreclr/debug/daccess/dacdbiimpl.cpp Fixes hot region initialization to include start address

return (MethodDesc*)((StubPrecode*)PCODEToPINSTR(entryPoint))->GetMethodDesc();
StubPrecode stubPrecode = (StubPrecode*)PCODEToPINSTR(entryPoint);
#ifdef FEATURE_INTERPRETER
if (stubPrecode->GetType() == PRECODE_INTERPRETER))
Copy link
Preview

Copilot AI Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an extra closing parenthesis that will cause a compilation error.

Suggested change
if (stubPrecode->GetType() == PRECODE_INTERPRETER))
if (stubPrecode->GetType() == PRECODE_INTERPRETER)

Copilot uses AI. Check for mistakes.

#ifdef FEATURE_INTERPRETER
if (stubPrecode->GetType() == PRECODE_INTERPRETER))
{
entryPoint = dac_cast<PTR_InterpreterPrecode>(pStubPrecode)->GetData()->ByteCodeAddr;
Copy link
Preview

Copilot AI Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable 'pStubPrecode' is used but not defined. It should be 'stubPrecode' to match the variable declared on line 2226.

Suggested change
entryPoint = dac_cast<PTR_InterpreterPrecode>(pStubPrecode)->GetData()->ByteCodeAddr;
entryPoint = dac_cast<PTR_InterpreterPrecode>(stubPrecode)->GetData()->ByteCodeAddr;

Copilot uses AI. Check for mistakes.

else
#endif // FEATURE_INTERPRETER
{
return (MethodDesc*)(stubPrecode)->GetMethodDesc();
Copy link
Preview

Copilot AI Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parentheses around 'stubPrecode' are unnecessary and the cast should be removed. It should be 'return stubPrecode->GetMethodDesc();'

Suggested change
return (MethodDesc*)(stubPrecode)->GetMethodDesc();
return stubPrecode->GetMethodDesc();

Copilot uses AI. Check for mistakes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it wants (MethodDesc*)(stubPrecode->GetMethodDesc()), which feels better to me also

Copy link
Contributor

Tagging subscribers to this area: @BrzVlad, @janvorli, @kg
See info in area-owners.md if you want to be subscribed.

PTR_StubPrecode pStubPrecode = dac_cast<PTR_StubPrecode>(PCODEToPINSTR(codeAddress));
if (pStubPrecode->GetType() == PRECODE_INTERPRETER)
{
codeAddress = dac_cast<PTR_InterpreterPrecode>(pStubPrecode)->GetData()->ByteCodeAddr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will end up creating codeinfo for a different IP than the one passed into Init. I can imagine that it is fixing a problem somewhere, but it is likely creating different problems somewhere else. Is this going to break places like

EECodeInfo codeInfo(ip);
if (!codeInfo.IsValid())
return;
where we expect the valid EECodeInfo to have real code with GCInfo, etc. behind it?

@jkotas
Copy link
Member

jkotas commented Aug 15, 2025

Fix various points in the runtime which need to handle the situation of the interpreter precode existing, and allowing the interpreter precode to be considered "part" of the code of the method.

What is the exact path that motivated this fix?

@davidwrighton
Copy link
Member Author

@jkotas, the interpreter precode is built as part of the interpreter codegen process, and placed into the NativeCode slot in the exact same place that the jitted code would go. Thus it gets used as the proxy for the interpreter compiled byte code all over the codebase. The path which is most visible is that this impacts the way the debugger looks at the process. The easiest path to hit where this fixes things is the behavior of !clrstack. Without this fix, the DAC fails to validate that any MethodDesc with generated interpreted code is a valid MethodDesc. This causes the reporting of stack traces to only show the IP within the interpreter bytecode, but not the name of methods. This could easily be fixed by a one off fix, but there are many such instances of issues. Consider delegate target IP to MethodDesc computation. This would be fixed by this change. Etc. I generally think that we'll end up treating the interpreter precode as a sort of adjunct to the interpreter byte code.

@jkotas
Copy link
Member

jkotas commented Aug 15, 2025

Consider delegate target IP to MethodDesc computation. This would be fixed by this change.

MethodDesc* NonVirtualEntry2MethodDesc(PCODE entryPoint)
is main path for delegate IP to MethodDesc mapping. It does not go through EECodeInfo, so I do not think it is affected by this change. If I am reading the code correctly, it should work fine - STUB_CODE_BLOCK_STUBPRECODE path should take care of it. Is that right?

If there is a need to map interpreter precode to MethodDesc, my thinking is that it should go through InterpreterPrecode::GetMethodDesc like the delegate mapping path. EECodeInfo should be only used to deal with actual JITed code IPs without magic.

@davidwrighton
Copy link
Member Author

I've merged a less complete version of this which is enough for !clrstack. Possibly we may want to pull some more of this logic in the future, but for now, this should be enough.

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

Successfully merging this pull request may close these issues.

3 participants