[Mono]: Fix EventPipe profiler recursion in class_loading under full AOT (#71143) #71610
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixing issue #71143.
Happens in full AOT mode where methods have been compiled as direct calls (happens within an assembly). In that case, the method is not known by the runtime (not present in the JIT info table). When a new class is loading, the class_loading profiler callback is called. The EventPipe implementation of that callback will take a stackwalk (inline with CoreCLR behavior), but taking a stackwalk will look up each managed function on the callstack against the JIT info table, if its not there it will load it, that in turn could case additional recursive class_loading event to fire, that will again take the same callstack, ending up in an infinite recursion.
The issue is even a little more problematic, since it turns out you cannot do anything inside the class_loading callback that might end up triggering a class load, since that might lead up to recursively loading the same type, that in turn will assert when outer class_loading call returns and tries to add it into the loaded class cache.
Fix will harden the stackwalking logic inside EventPipe to detect recursive stackwalks (doing a stackwalk triggering another stackwalk) and if that is the case, the stackwalk will be done using the async_context stackwalking capabilities since that won't trigger any additional profiler events, breaking recursion.
Fix also adds logic to the class_loading profiler callback in EventPipe to prevent recursion making sure it won't trigger any additional profiler events, leading up to potential issues loading the same class twice, that will cause an assert inside the class loader logic.
For 1:1 mapping of old Mono profiler events issued into EventPipe, they have been aligned with old Mono log profiler events callstack behaviours, meaning it will only emit callstacks on a few limited profiler events, mitigating the issues seen in the runtime profiler provider.