-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Allow emitting line number information into native AOT apps #122227
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
base: main
Are you sure you want to change the base?
Conversation
|
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas |
There was a problem hiding this 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 adds support for embedding line number information into native AOT applications, allowing stack traces to include file names and line numbers without requiring separate debug symbol files (PDB/DWO/DSYM). The implementation uses hashtables to map methods to their line number data, with two different lookup mechanisms: one for methods with dedicated stack trace metadata and another for methods with reflection metadata.
Key Changes
- Introduces
StackTraceLineNumbersNodeandStackTraceDocumentsNodeto embed line number and document information into the executable - Adds
HasLineNumbersflag toMethodStackTraceVisibilityFlagsand correspondingStackTraceRecordFlagsto control line number emission - Extends
VersionResilientHashCodewithCombineThreeValuesIntoHashmethod for hashing three values
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/tests/nativeaot/SmokeTests/Reflection/Reflection.cs |
Adds regression test for issue #121093 validating stack trace contains method names for both reflected and non-reflected generic methods |
src/libraries/Common/src/Internal/VersionResilientHashCode.cs |
Adds CombineThreeValuesIntoHash method for creating stable hash codes from three values |
src/coreclr/tools/aot/ILCompiler/Program.cs |
Updates stack trace emission policy to enable line numbers when stack trace data is emitted |
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj |
Adds new node files to project |
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs |
Updates ComputeMetadata signature to include reflection-based stack trace mappings |
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/StackTraceEmissionPolicy.cs |
Adds HasLineNumbers flag support and constructor parameter to control line number inclusion |
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs |
Refactors stack trace mapping to support both regular and reflection-based line number generation, adds flag-based filtering |
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/StackTraceMethodMappingNode.cs |
Updates to use flag enum instead of boolean |
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/StackTraceLineNumbersNode.cs |
New node that generates hashtable mapping methods to compressed line number data |
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/StackTraceDocumentsNode.cs |
New node that stores document paths with offset-based indexing |
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/AnalysisBasedMetadataManager.cs |
Updates ComputeMetadata signature to include reflection-based stack trace mappings |
src/coreclr/tools/Common/Internal/Runtime/MetadataBlob.cs |
Adds blob IDs for line numbers and documents |
src/coreclr/tools/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs |
Adds ordering entries for new node types |
| // is a document number. Otherwise we use NativeOffsetDelta == 0 as a marker that the next | ||
| // byte is a document number and not a native offset delta. | ||
| if (currentDocument != null) | ||
| bw.Write7BitEncodedInt((byte)0); |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cast to (byte)0 is incorrect. Write7BitEncodedInt expects an int parameter, not a byte. This should be bw.Write7BitEncodedInt(0); instead.
| bw.Write7BitEncodedInt((byte)0); | |
| bw.Write7BitEncodedInt(0); |
| public IEnumerable<ReflectionStackTraceMapping> GetReflectionStackTraceMappings(NodeFactory factor) | ||
| { | ||
| EnsureMetadataGenerated(factor); |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parameter name inconsistency: the parameter is named factor but should be factory to match the pattern used in other similar methods (e.g., GetStackTraceMapping on line 1030).
| public IEnumerable<ReflectionStackTraceMapping> GetReflectionStackTraceMappings(NodeFactory factor) | |
| { | |
| EnsureMetadataGenerated(factor); | |
| public IEnumerable<ReflectionStackTraceMapping> GetReflectionStackTraceMappings(NodeFactory factory) | |
| { | |
| EnsureMetadataGenerated(factory); |
|
|
||
| public static uint CombineThreeValuesIntoHash(uint value1, uint value2, uint value3) | ||
| { | ||
| // This matches the behavior of System.HashCode.Combine(value1, value2) as of the time of authoring |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment on line 209 is incorrect and appears to be copied from CombineTwoValuesIntoHash. It should say "This matches the behavior of System.HashCode.Combine(value1, value2, value3)" to accurately reflect that it combines three values, not two.
| // This matches the behavior of System.HashCode.Combine(value1, value2) as of the time of authoring | |
| // This matches the behavior of System.HashCode.Combine(value1, value2, value3) as of the time of authoring |
| foreach (StackTraceMapping mapping in factory.MetadataManager.GetStackTraceMapping(factory)) | ||
| { | ||
| var entrypointSymbol = factory.MethodEntrypoint(mapping.Method); | ||
| if (entrypointSymbol is not INodeWithDebugInfo debugInfo) | ||
| continue; | ||
|
|
||
| BlobVertex blob = CreateLineNumbersBlob(_documents, debugInfo); | ||
| if (blob == null) | ||
| continue; | ||
|
|
||
| Vertex methodPointer = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(entrypointSymbol)); | ||
| var hashtableEntry = nativeWriter.GetTuple(methodPointer, blob); | ||
|
|
||
| uint hashcode = VersionResilientHashCode.CombineThreeValuesIntoHash((uint)mapping.OwningTypeHandle, (uint)mapping.MethodNameHandle, (uint)mapping.MethodSignatureHandle); | ||
| hashtable.Append(hashcode, nativeSection.Place(hashtableEntry)); | ||
| } |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing flag check: The loop should verify that (mapping.Flags & StackTraceRecordFlags.HasLineNumbers) != 0 before attempting to generate line numbers. Currently, it will attempt to generate line numbers for all methods in the stack trace mapping, regardless of whether the HasLineNumbers flag is set. This could result in generating line numbers for methods where line number emission was not intended according to the policy.
Fixes #121093 (because I needed more precise tracking of what gets stack trace data)
Fixes #68714
Submitting as draft for now:
Cc @dotnet/ilc-contrib