Skip to content

Refactor ObjectDataInterner to support pluggable deduplicators and enable for ReadyToRun#126112

Open
jkoritzinsky wants to merge 8 commits intodotnet:mainfrom
jkoritzinsky:objectdatainterner
Open

Refactor ObjectDataInterner to support pluggable deduplicators and enable for ReadyToRun#126112
jkoritzinsky wants to merge 8 commits intodotnet:mainfrom
jkoritzinsky:objectdatainterner

Conversation

@jkoritzinsky
Copy link
Copy Markdown
Member

Note

This PR was generated with the help of GitHub Copilot.

Summary

Refactors ObjectDataInterner to accept a set of pluggable IObjectDataDeduplicator strategies instead of hard-coding method body deduplication logic, then extends the infrastructure to ReadyToRun.

Changes

Pluggable deduplicator interface

  • Introduced IObjectDataDeduplicator with a single DeduplicatePass method.
  • ObjectDataInterner now accepts params IObjectDataDeduplicator[] and delegates each convergence-loop iteration to them.
  • Moved ObjectDataInterner to Common/Compiler/ so both NativeAOT and ReadyToRun can share it.

Method body deduplication (NativeAOT)

  • Extracted all MethodDesc/IMethodBodyNode-specific logic (CanFold, MethodInternKey, MethodInternComparer) into a new MethodBodyDeduplicator : IObjectDataDeduplicator class.
  • Added a virtual bool CanFold(MethodDesc) on the base NodeFactory (returns false), overridden in RyuJitNodeFactory to delegate to MethodBodyDeduplicator.

Copied method IL deduplication (ReadyToRun)

  • Added CopiedMethodILDeduplicator : IObjectDataDeduplicator in ILCompiler.ReadyToRun that deduplicates CopiedMethodILNode instances by comparing their raw IL bytes.
  • Added ObjectDataInterner property to the ReadyToRun NodeFactory, wired up with the new deduplicator.
  • Added Values property to the ReadyToRun NodeCache<TKey, TValue> to enable enumeration.
  • Removed the #if !READYTORUN guards around ObjectInterner.GetDeduplicatedSymbol calls in the common ObjectWriter, so deduplication now runs uniformly for both pipelines.

jkoritzinsky and others added 4 commits March 25, 2026 09:48
Extract method-body-specific deduplication logic from ObjectDataInterner
into a new MethodBodyDeduplicator class behind an IObjectDataDeduplicator
interface. ObjectDataInterner now accepts a set of deduplicator instances
and delegates the deduplication passes to them.

- Add IObjectDataDeduplicator interface with DeduplicatePass method
- Move MethodInternKey, MethodInternComparer, and CanFold logic into
  MethodBodyDeduplicator
- Add virtual CanFold method on NodeFactory (returns false by default)
- Override CanFold in RyuJitNodeFactory to delegate to MethodBodyDeduplicator

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move ObjectDataInterner.cs (with IObjectDataDeduplicator interface) from
ILCompiler.Compiler/Compiler/ to Common/Compiler/ so it can be shared
across AOT projects. Add it to ILCompiler.ReadyToRun.csproj. The
MethodBodyDeduplicator implementation stays in ILCompiler.Compiler.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a new IObjectDataDeduplicator implementation that deduplicates
CopiedMethodILNode instances based on their IL body bytes. Uses a
HashSet with a custom key/comparer to correctly handle hash collisions.

- Add Values property to ReadyToRun NodeCache for enumeration
- Add ObjectDataInterner to ReadyToRun NodeFactory
- Wire up CopiedMethodILDeduplicator in NodeFactory constructor

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the three #if !READYTORUN / #if READYTORUN guards around
ObjectInterner.GetDeduplicatedSymbol calls in the common ObjectWriter.
Now that ReadyToRun's NodeFactory has an ObjectDataInterner, the
deduplication logic applies uniformly to both NativeAOT and ReadyToRun.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 25, 2026 17:51
@jkoritzinsky
Copy link
Copy Markdown
Member Author

cc @kotlarmilos @jkotas here's an alternative implementation of #126047 based on ObjectDataInterner. It also enables ObjectDataInterner for R2R so we could eventually add more deduplicators easily if we so desired.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refactors the object-data deduplication infrastructure so ObjectDataInterner can run one or more pluggable deduplication strategies, and wires this up for both NativeAOT (method body folding) and ReadyToRun (copied IL folding).

Changes:

  • Introduces IObjectDataDeduplicator and a shared ObjectDataInterner in src/coreclr/tools/Common/Compiler/.
  • Extracts NativeAOT method-body folding into MethodBodyDeduplicator and routes folding decisions through NodeFactory.CanFold.
  • Enables ReadyToRun deduplication by adding CopiedMethodILDeduplicator and an ObjectInterner on the R2R NodeFactory, plus removes READYTORUN guards in the common ObjectWriter.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilationBuilder.cs Creates MethodBodyDeduplicator based on folding mode and builds an ObjectDataInterner from it.
src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/DependencyAnalysis/RyuJitNodeFactory.cs Plumbs MethodBodyDeduplicator into the factory and overrides CanFold.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj Links shared ObjectDataInterner and adds the new R2R deduplicator source.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs Adds cache enumeration (Values) and instantiates an ObjectInterner for R2R.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedMethodILDeduplicator.cs Implements R2R strategy to fold CopiedMethodILNode instances by raw IL bytes.
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj Moves ObjectDataInterner to shared location and adds MethodBodyDeduplicator.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MethodBodyDeduplicator.cs Extracts method-body folding logic into a dedicated IObjectDataDeduplicator.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs Replaces direct ObjectInterner.CanFold usage with overridable CanFold.
src/coreclr/tools/Common/Compiler/ObjectWriter/ObjectWriter.cs Runs deduplication uniformly (including READYTORUN builds) when emitting nodes/relocs.
src/coreclr/tools/Common/Compiler/ObjectDataInterner.cs Adds shared pluggable interner + interface for iterative convergence passes.

- Guard GetDeduplicatedSymbol call in ObjectWriter when symbolNode is null
- Cache IL bytes in InternKey to avoid repeated PE reads during equality checks
- Use Func<IEnumerable<CopiedMethodILNode>> for deferred enumeration so
  the deduplicator sees the final cache contents after marking is complete

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 7, 2026 20:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

jkoritzinsky and others added 2 commits April 7, 2026 13:29
- ObjectDataInterner: Replace count-only convergence check with full
  dictionary content comparison to detect mapping changes even when
  count stays the same.
- CopiedMethodILDeduplicator: Cache deduplication results to avoid
  repeated GetData allocations across convergence loop iterations.
- CopiedMethodILDeduplicator: Sort nodes with CompilerComparer before
  iterating to ensure deterministic canonical representative selection
  regardless of ConcurrentDictionary enumeration order.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants