Skip to content

Make GetMethodInfo work for non-jit'ed code#1358

Open
leculver wants to merge 5 commits intomicrosoft:mainfrom
leculver:issue_1306
Open

Make GetMethodInfo work for non-jit'ed code#1358
leculver wants to merge 5 commits intomicrosoft:mainfrom
leculver:issue_1306

Conversation

@leculver
Copy link
Contributor

@leculver leculver commented Feb 12, 2026

Fix GetMethodByHandle for struct methods and generic method instantiations

Problem

GetMethodByHandle had two related bugs in DacMethodLocator.GetMethodInfo:

  1. Struct methods returned null (Get ClrMethod from virtual method of struct #1306): The old code unconditionally called GetCodeHeaderData(NativeCodeAddr) in the same conditional as GetMethodDescData. When HasNativeCode == 0 (unboxing stubs, un-jitted inherited methods like ToString/Equals/GetHashCode), NativeCodeAddr is 0 and GetCodeHeaderData fails, causing GetMethodInfo to return false — which made GetMethodByHandle return null.

  2. Value-type generic method instantiations reported wrong compilation info (Missing some compilation information for generic methods #935): For methods like Echo<int>(), the old code's slot-based lookup via GetMethodTableSlot returned the generic method definition (uninstantiated stub) instead of the JIT'd instantiation, yielding CompilationType=None and HotSize=0 even though WinDbg's !DumpMD correctly shows the method as jitted. The reporter's own investigation confirmed that GetCodeHeaderData(NativeCodeAddr) returns the correct data while the slot-based path does not.

Fix

Restructured GetMethodInfo into a three-tier approach:

  1. Primary path (HasNativeCode != 0): Use GetCodeHeaderData(NativeCodeAddr) to get the correct JIT type and code size. This handles all jitted methods including value-type generic instantiations (the Missing some compilation information for generic methods #935 scenario).

  2. Slot-based fallback (HasNativeCode == 0 but slot has code): Try GetMethodTableSlot + GetCodeHeaderData(slot). This is a defensive path for cases where a per-instantiation MethodDesc has HasNativeCode=0 but the method table slot points to shared JIT'd code (e.g., reference-type generic instantiations sharing code via __Canon).

  3. No native code: Return CompilationType.None with default HotColdRegions for methods that genuinely haven't been JIT compiled.

Tests

Six new regression tests covering both issues:

Test Scenario
GetMethodByHandle_StructImplementingInterface_FindsAllMethods All methods on StructWithInterface resolve via GetMethodByHandle (#1306)
StructMethodCompilationType_MatchesJitStatus Struct has both jitted and un-jitted methods with correct CompilationType (#1306)
GetMethodByHandle_ValueTypeGenericMethod_ReturnsJittedInfo Echo<int>() reports CompilationType=Jit and non-zero HotSize (#935 exact scenario)
GetMethodByHandle_GenericMethodWithRefType_ReturnsJittedInfo GenericClass<bool,int,float,string,object>.Invoke resolves correctly (#935)
GetMethodByHandle_RefTypeGenericInstantiation_ResolvesAllMethods All methods on a ref-type generic instantiation from the heap resolve (#935)

All tests pass on both Windows (.NET Framework dumps) and Linux (.NET Core 10 dumps).

Fixes #1306. Fixes #935. (CompilationType and HotSize; the Name truncation sub-issue is tracked separately.)

…t#1306)

GetMethodInfo in DacMethodLocator unconditionally required GetCodeHeaderData
to succeed, which fails for methods that haven't been JIT compiled (e.g.,
struct unboxing stubs, un-jitted inherited methods). This fix separates the
GetMethodDescData call from the GetCodeHeaderData call and handles the case
where native code is not available by returning a MethodInfo with
CompilationType.None and default HotColdRegions.
…icrosoft#1306)

Add two test cases to MethodTests.cs:
- GetMethodByHandle_StructImplementingInterface_FindsAllMethods: verifies
  all methods on a struct implementing an interface can be resolved via
  GetMethodByHandle, including unboxing stubs and inherited un-jitted methods.
- StructMethodCompilationType_MatchesJitStatus: verifies un-jitted methods
  return CompilationType.None while JIT-compiled methods return non-None.

Supporting changes:
- SharedLibrary.cs: add IStructTest interface and StructWithInterface struct
- Types.cs: exercise struct interface dispatch to create unboxing stub
Copy link
Contributor

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 ClrRuntime.GetMethodByHandle resolution for method handles whose MethodDesc exists but which don’t have code header data available (commonly for non-JIT’ed methods and some stubs), by no longer requiring GetCodeHeaderData to succeed in order to return MethodInfo. It also adds a regression scenario and tests around struct interface dispatch to cover issue #1306.

Changes:

  • Update DacMethodLocator.GetMethodInfo to succeed when GetMethodDescData succeeds even if code header/native code data is unavailable, returning CompilationType.None + default HotColdRegions in that case.
  • Extend the Types test target and shared test library to exercise struct interface dispatch (unboxing stub scenario).
  • Add regression tests validating GetMethodByHandle can resolve methods for a struct implementing an interface, and asserting compilation-type behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
src/Microsoft.Diagnostics.Runtime/DacImplementation/DacMethodLocator.cs Decouples MethodDesc lookup from code header lookup; returns a usable MethodInfo even when native code metadata can’t be read.
src/Microsoft.Diagnostics.Runtime.Tests/src/MethodTests.cs Adds regression tests for struct/interface method handle resolution and compilation-type expectations.
src/TestTargets/Types/Types.cs Triggers struct interface dispatch in the dump target to reproduce issue conditions.
src/TestTargets/Shared/SharedLibrary.cs Adds IStructTest and StructWithInterface used by the new dump/test scenario.

@leculver leculver changed the title Make GetMethodInfo for non-jit'ed code Make GetMethodInfo work for non-jit'ed code Feb 13, 2026
…ocator.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@leculver leculver marked this pull request as draft February 13, 2026 14:14
…est (issue microsoft#935)

DacMethodLocator.GetMethodInfo: when HasNativeCode==0, fall back to
GetMethodTableSlot + GetCodeHeaderData to resolve JIT info for methods
whose per-instantiation MethodDesc lacks NativeCodeAddr (ref-type
generic type instantiations sharing canonical code).

Test target: stores per-instantiation MethodDesc handles for
GenericClass<bool,int,float,string,object>.Invoke and Echo<string>
via RuntimeHelpers.PrepareMethod + MethodHandle.Value.

Test: GetMethodByHandle_GenericMethodWithRefType_ReturnsJittedInfo
reads the stored handle and verifies CompilationType and HotSize.

Note: on .NET Framework dumps HasNativeCode is already set for
per-instantiation MethodDescs so the fallback path is not exercised.
Full coverage requires .NET Core dumps (to be tested on Linux).
…sues microsoft#935, microsoft#1306)

- Add RefGenericClass<T> to exercise ref-type generic instantiation sharing
- Add Echo<int> MethodDesc storage for issue microsoft#935 exact scenario
- Add test GetMethodByHandle_ValueTypeGenericMethod_ReturnsJittedInfo
- Add test GetMethodByHandle_RefTypeGenericInstantiation_ResolvesAllMethods
- Verified on Linux (.NET 10 Core): 6 MethodTests pass, 3 skipped
@leculver leculver marked this pull request as ready for review February 13, 2026 14:53
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.

Get ClrMethod from virtual method of struct Missing some compilation information for generic methods

1 participant

Comments