Skip to content

Reduce allocations in MethodBodyScanner - #135563

Closed
prozolic wants to merge 1 commit into
dotnet:mainfrom
prozolic:ilcompier-reduce-list-allocation
Closed

prozolic wants to merge 1 commit into
dotnet:mainfrom
prozolic:ilcompier-reduce-list-allocation

Conversation

@prozolic

Copy link
Copy Markdown
Contributor

In MethodBodyScanner.HandleCall, create the ValueNodeList directly instead of building an intermediate List<T> and copying it. Apply the same change to MethodBodyScanner in src\tools\illink\src\linker\Linker.Dataflow to keep the two in sync.

Also specify the initial capacity when creating a List<T> in ILCompiler and ILCompiler.Compiler where the number of elements is known up front. This avoids reallocating the backing array as the list grows.
In single-method mode, fill the generic argument array directly instead of going through a List<T> and ToArray().

I ran the NativeAOT smoketests and ILCompiler.*.Tests/Mono.Linker.Tests using the following commands and confirmed that they all passed in local.

.\build.cmd clr.aot -rc Release -lc Release
.\src\tests\build.cmd nativeaot Release tree nativeaot /p:LibrariesConfiguration=Release
.\src\tests\run.cmd runnativeaottests Release
dotnet test src/coreclr/tools/aot/ILCompiler.Trimming.Tests/ILCompiler.Trimming.Tests.csproj -c Release
dotnet test src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILCompiler.TypeSystem.Tests.csproj -c Release
dotnet test src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework.Tests/ILCompiler.DependencyAnalysisFramework.Tests.csproj -c Release

.\build.cmd -s tools.illink -c Debug
dotnet test src/tools/illink/test/Mono.Linker.Tests/Mono.Linker.Tests.csproj -c Debug

In MethodBodyScanner.HandleCall, create the ValueNodeList directly
instead of building an intermediate List<T> and copying it. Apply the
same change to MethodBodyScanner in
src\tools\illink\src\linker\Linker.Dataflow to keep the two in sync.

Also specify the initial capacity when creating a List<T> in
ILCompiler and ILCompiler.Compiler where the number of elements is
known up front. This avoids reallocating the backing array as the list
grows.

In single-method mode, fill the generic argument array directly
instead of going through a List<T> and ToArray().
Copilot AI balanced review requested due to automatic review settings October 10, 2026 05:56
@dotnet-policy-service dotnet-policy-service Bot added linkable-framework Issues associated with delivering a linker friendly framework community-contribution Indicates that the PR has been added by a community member labels Oct 10, 2026
@azure-pipelines

Copy link
Copy Markdown
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.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Performance measurements are missing, and the removed call sites leave dead synchronized constructors.

2 open findings
What changed in this PR

Reduces allocations in NativeAOT and ILLink compiler paths.

Changes:

  • Builds ValueNodeList directly in synchronized dataflow scanners.
  • Preallocates lists with known capacities.
  • Fills generic argument arrays directly.
File Description
src/​tools/​illink/​src/​linker/​Linker.Dataflow/​MethodBodyScanner.cs Removes an intermediate list allocation.
src/​coreclr/​tools/​Common/​Compiler/​Win32Resources/​ResourceData.cs Preallocates resource-type storage.
src/​coreclr/​tools/​aot/​ILCompiler/​Program.cs Preallocates lists and directly fills generic arguments.
src/​coreclr/​tools/​aot/​ILCompiler.Compiler/​Compiler/​TypePreinit.cs Preallocates serialized field values.
src/​coreclr/​tools/​aot/​ILCompiler.Compiler/​Compiler/​MetadataManager.cs Preallocates generic metadata arguments.
src/​coreclr/​tools/​aot/​ILCompiler.Compiler/​Compiler/​DependencyAnalysis/​NativeLayoutVertexNode.cs Preallocates layout collections.
src/​coreclr/​tools/​aot/​ILCompiler.Compiler/​Compiler/​Dataflow/​MethodBodyScanner.cs Removes an intermediate list allocation.

🧠 Review effort: Balanced

@MichalStrehovsky

Copy link
Copy Markdown
Member

I only skimmed this, but I'm not sure if any of this is worth it, sorry. Just as an example, the TypePreinit change makes it look like we care about perf here because we want to correctly size things. But if we care about perf, this should be an array not a list. And we shouldn't process it as IEnumerable down the line. But the truth is we don't care about the perf here and go for simplicity.

Perf fixes should come with perf measurements. We care about wall clock time. Making source code lines longer and perturbing git blame history with no wall clock time wins for it doesn't move the needle.

@prozolic

Copy link
Copy Markdown
Contributor Author

@MichalStrehovsky I measured the build times and memory allocation for helloworld and webapi, but the differences were so small that they were negligible, so as you said, it doesn't really mean much.
Closing. Thanks for the review.

@prozolic prozolic closed this Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-NativeAOT-coreclr community-contribution Indicates that the PR has been added by a community member linkable-framework Issues associated with delivering a linker friendly framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants