Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cDAC] Change FrameIdentifiers to be contract literals #113953

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

max-charlamb
Copy link
Contributor

@max-charlamb max-charlamb commented Mar 26, 2025

Previously these were indirect pointers, this places them in the contract directly.

Indirect pointers are used so the dynamic linker can resolve the addresses. These values are known at compile time and therefore don't need the extra layer of indirection.

Additionally adds to the Target interface to allow TryReadGlobal instead of using exceptions for control-flow

@max-charlamb
Copy link
Contributor Author

/azp run runtime-diagnostics

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Contributor

Tagging subscribers to this area: @tommcdon
See info in area-owners.md if you want to be subscribed.

@max-charlamb
Copy link
Contributor Author

/azp run runtime-diagnostics

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@max-charlamb max-charlamb marked this pull request as ready for review March 27, 2025 15:36
@max-charlamb max-charlamb requested review from Copilot, davmason and a team March 27, 2025 15:36
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 updates the contract identifiers by embedding them as literals rather than using indirect pointers, and adds a TryReadGlobal method to avoid exception-driven control flow when accessing globals.

  • Added TryReadGlobal overload in ContractDescriptorTarget
  • Refactored FrameIterator to use TryReadGlobal instead of exception handling
  • Updated the Target abstract class to include the TryReadGlobal method

Reviewed Changes

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

File Description
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs Adds new TryReadGlobal method implementation
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/FrameHandling/FrameIterator.cs Replaces exception-based logic with a TryReadGlobal call
src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs Introduces an abstract TryReadGlobal method
Files not reviewed (1)
  • src/coreclr/debug/runtimeinfo/datadescriptor.h: Language not supported
Comments suppressed due to low confidence (2)

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/FrameHandling/FrameIterator.cs:137

  • [nitpick] Consider caching the concatenated key (frameType.ToString() + "Identifier") in a variable to improve readability and reduce potential issues when updating the identifier naming.
if (target.TryReadGlobal(frameType.ToString() + "Identifier", out ulong? id))

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs:499

  • Consider adding unit tests for the new TryReadGlobal method to verify its behavior for both valid and invalid global names.
public override bool TryReadGlobal<T>(string name, [NotNullWhen(true)] out T? value)

@kg
Copy link
Member

kg commented Mar 27, 2025

LGTM but I don't completely understand what's going on in it

@max-charlamb max-charlamb force-pushed the cdac-pointer-to-globals branch from 79a85ee to a242667 Compare March 27, 2025 17:55
@max-charlamb max-charlamb force-pushed the cdac-pointer-to-globals branch from 7576fbe to 7c74701 Compare March 27, 2025 19:03
@max-charlamb
Copy link
Contributor Author

LGTM but I don't completely understand what's going on in it

There are two related changes here:

  • [cDAC] Stack walk support more Frame types #112997 (comment) Cleaning up FrameIterator to not use exceptions for control-flow by implementing a 'TryGet' for global values.
  • Changing the FrameIdentifiers from a 'global pointer' to a 'global literal'. FrameIdentifiers are pointer sized values that represent a specific Frame type. When I originally added them to the contract, I added them as 'global pointers' because they are pointer sized. However, this adds a layer of indirection by referencing an offset into an array of pointers. This is required for some true pointer types because the dynamic linker has to resolve their values. Because FrameIdentifiers are a compile time constant, we can shove the whole value into the contract, removing a layer of indirection.

@kg
Copy link
Member

kg commented Mar 27, 2025

LGTM but I don't completely understand what's going on in it

Changing the FrameIdentifiers from a 'global pointer' to a 'global literal'. FrameIdentifiers are pointer sized values that represent a specific Frame type. When I originally added them to the contract, I added them as 'global pointers' because they are pointer sized. However, this adds a layer of indirection by referencing an offset into an array of pointers. This is required for some true pointer types because the dynamic linker has to resolve their values. Because FrameIdentifiers are a compile time constant, we can shove the whole value into the contract, removing a layer of indirection.

I had missed that these globals are populated into a cache at initialization time, so I was confused by TryReadGlobal only doing a dictionary lookup instead of a memory read from the target. It makes sense now that I know it's a pre-initialized cache. I'd prefer to see these called "global constants" or something to communicate that they aren't read on-demand from the target and are cached, but that can happen in a later PR if it happens at all.

@@ -144,19 +144,13 @@ private static FrameType GetFrameType(Target target, TargetPointer frameIdentifi
{
foreach (FrameType frameType in Enum.GetValues<FrameType>())
Copy link
Member

Choose a reason for hiding this comment

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

This isn't introduced by your change, but this loop seems expensive for something we do for every frame. You don't need to change it now but we may want to revisit

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