-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
[NativeAOT] Natvis visualization for threadstatic variables. #90473
Conversation
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas Issue DetailsFixes: #89227
|
Limitations:
Natvis is a terrible language for doing anything complex and appears to be unable to parse nested generic types which arise when we need to visualize for a generic instantiation. A typical failure looks like the following (both 7.0 and 8.0): This is visualizing If you notice The natvis diagnostics contains
The unbalanced extra |
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) | ||
{ | ||
sb.Append(_type != null ? nameMangler.NodeMangler.ThreadStaticsIndex(_type) : "_inlinedThreadStaticsIndex"); | ||
sb.Append(nameMangler.NodeMangler.ThreadStaticsIndex(_type)); |
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.
This is the key change. We used to create just one _inlinedThreadStaticsIndex
node for the entire storage block in inlined case and were reusing the node for every type involved.
Now we are back to having individual index nodes for all types that have threadstatics. This allows natvis to know the offsets of each type's storage within the block.
Another limitation:
For example a threadstatic like class c1
{
[ThreadStatic]
public static int tt;
} Such threadstatic would be completely functional - i.e.
I think in simple cases we may be dropping/trimming away parts which are important for the visualization. |
@@ -94,6 +94,11 @@ protected override void EmitCode(NodeFactory factory, ref ARM64Emitter encoder, | |||
encoder.EmitJNE(factory.HelperEntrypoint(HelperEntrypoint.EnsureClassConstructorRunAndReturnThreadStaticBase)); | |||
EmitInlineTLSAccess(factory, ref encoder); | |||
} | |||
|
|||
// REVIEW: how to keep a node around? |
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.
Report it in ComputeNonRelocationBasedDependencies
Line 123 in a19585d
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory) |
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.
I will look into using that.
The tricky part is to not root threadstatic index for every type that has threadstatics, but only for those that are reachable in the code, even though the index itself is not used.
(technically the index node is “used” - at compile time, and maybe debug time, but the code itself, once emitted, does not need the index)
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.
Although, I think, we can assume that for every type with inlined storage the index will be "used", since we build the storage block based on the analysis that we did in the scanner.
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.
I just made the node that describes the storage block report as static dependencies the index nodes for the types whose storage is inlined in the block.
…eadcode MOV" hack
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.
Thank you!
Thanks!!! |
I do not think any changes are necessary. The shape of TLS is not changing, so this should keep working. (I will confirm, just in case) |
Yes, that looks functional. The natvis script digs into the TLS structure on the runtime side and knows about possible shapes, so the visualization should work regardless of how TLS is accessed from the code. |
Fixes: #89227
The change implements visualization for threadstatic variables in common cases.
The essence of the change:
=== Uninlined case:
Made corresponding adjustments for indexing of native vs. managed arrays in the natvis.
m_numThreadLocalModuleStatics
=== Inlined case
TypeThreadStaticIndexNode
is needed for natvis, start emittingTypeThreadStaticIndexNode
for inlined types as well. (we stopped emitting that for inlined threadstatics since the index is not needed at run time)TypeThreadStaticIndexNode
accordingly(that is mostly to treat the offset not as an index of the storage block, but an offset within the storage block)
=== overall