Compact NativeAOT dispatch cell info encoding - #130824
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c5889318-fe12-47b1-946e-6969e02ef71d
|
Azure Pipelines: Successfully started running 3 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib |
There was a problem hiding this comment.
Pull request overview
This PR changes the NativeAOT dispatch cell info sections to use a more compact encoding when multiple dispatch cells share the same descriptor (dictionary + per-cell index), and updates the runtime decoder accordingly. It also adds smoke tests intended to exercise multiple callsites sharing the same descriptor.
Changes:
- Add dictionary-based encoding for interface dispatch cell info and GVM dispatch cell info (compiler-side), falling back to the existing direct encoding when it’s smaller.
- Update NativeAOT runtime dispatch resolution to decode either direct or dictionary-encoded info regions.
- Add/extend NativeAOT smoke tests to create multiple distinct callsites targeting the same interface/GVM descriptor.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs | Adds a new test to create multiple interface dispatch callsites that should share a descriptor. |
| src/tests/nativeaot/SmokeTests/DynamicGenerics/GenericVirtualMethods.cs | Adds multiple no-inline interface GVM call wrappers to increase shared-descriptor callsites. |
| src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/InterfaceDispatchCellInfoSectionNode.cs | Emits interface dispatch info using direct vs dictionary encoding based on size. |
| src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GvmDispatchCellInfoSectionNode.cs | Emits GVM dispatch info using direct vs dictionary encoding based on size. |
| src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DispatchCellNode.cs | Introduces a shared helper for dictionary size/index encoding decisions. |
| src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Dispatch.cs | Updates decoding logic to understand the new direct/dictionary layouts. |
|
I'm on the fence whether this is worth it at all. This adds 200 lines of complexity to get a 0.34% saving in the best case. Size statisticsPull request #130824
|
Group dispatch cells by descriptor and encode their metadata as compact NativeFormat runs backed by the existing NativeReferences table. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 99d7688e-8d4a-4dcb-a6e4-ca94fdfed0dc
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7f337a9d-27d1-43d9-9c0c-cc6a3ea449a7
Replaced exceptions with assertions for cell index and slot checks, and updated external references initialization.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f55b8ade-cf37-4d2c-91af-cee7b726a3ea
|
Looks like this now costs next to nothing in extra complexity (the NativeArray is a general purpose data structure we can use elsewhere) and still provides a nice saving: Size statistics
|
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
/azp run runtime-nativeaot-outerloop |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Dispatch.cs:106
- GetDispatchCellInfo ignores the return value of InitializeNativeReferences. If the NativeReferences blob is missing/corrupt, subsequent GetIntPtrFromIndex calls will read from an uninitialized table and fail unpredictably. This should fail fast with BadImageFormatException (similar to other TypeLoader code paths).
externalReferences = default;
externalReferences.InitializeNativeReferences(typeManager);
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Dispatch.cs:115
- The fallback loop that decrements cellIndex can underflow in release builds (cellIndex is uint) if TryGetAt never succeeds (e.g., malformed/empty info region), leading to an infinite loop. Add a defensive termination condition (and ideally a small max scan bound) that throws BadImageFormatException.
NativeParser parser;
while (!entries.TryGetAt(cellIndex, out parser))
{
Debug.Assert(cellIndex > 0);
cellIndex--;
}
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Dispatch.cs:109
- GetDispatchCellInfo allocates a new NativeReader (class) on every first-time dispatch resolution. If many dispatch cells are resolved during startup, this can create avoidable GC pressure compared to the previous pointer-based indexing. Consider caching a per-module NativeReader/NativeArray (or otherwise avoiding per-call allocation) and include perf measurements showing this doesn’t regress first-call/startup time.
NativeReader reader = new NativeReader(pInfo, checked((uint)length));
NativeArray entries = new NativeArray(new NativeParser(reader, 0));
jkotas
left a comment
There was a problem hiding this comment.
(make sure to update the PR description before merging)
Replaces the dispatch cell info encoding used for interface methods and generic virtual methods to use Native Layout.
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com
Copilot-Session: c5889318-fe12-47b1-946e-6969e02ef71d