Skip to content

[dotnet-linker] Emit the macro/short form of IL instructions in generated method bodies. - #26471

Open
rolfbjarne wants to merge 3 commits into
mainfrom
dev/rolf/registrar-il-macro-forms
Open

[dotnet-linker] Emit the macro/short form of IL instructions in generated method bodies.#26471
rolfbjarne wants to merge 3 commits into
mainfrom
dev/rolf/registrar-il-macro-forms

Conversation

@rolfbjarne

Copy link
Copy Markdown
Member

The trimmable static registrar (and the Dlfcn inlining step) generate method
bodies using the long form of the ldloc/stloc/ldarg/ldloca instructions.

This trips a bug in the CoreCLR interpreter, where the store/load peephole
optimization reads the operand of the long form of ldloc/stloc at the wrong
offset (ip + 1 instead of ip + 2). The resulting bogus local index is used to
index an array, which leads to an out-of-bounds read and a SIGBUS at runtime:

make clean build run-bare -C tests/monotouch-test/dotnet/MacCatalyst TEST_VARIATION=trimmable-static-registrar

crashed in MonoTouchFixtures.ObjCRuntime.RegistrarTest.TestConstrainedGenericType.

The interpreter bug has been fixed in dotnet/runtime#131547,
but we still need to work around it until we get a runtime with that fix.

Emitting the macro/short form of the instructions avoids the problematic
instruction sequence entirely, and it also makes the generated IL smaller,
which is a good thing in itself.

For monotouch-test on macOS, this removes all 3709 adjacent long-form
'stloc; ldloc' pairs from the generated _monotouchtest.TypeMap.dll.

Copilot-Session: a002000e-438e-48ff-9c22-c716d1a2e7aa

…ated method bodies.

The trimmable static registrar (and the Dlfcn inlining step) generate method
bodies using the long form of the ldloc/stloc/ldarg/ldloca instructions.

This trips a bug in the CoreCLR interpreter, where the store/load peephole
optimization reads the operand of the long form of ldloc/stloc at the wrong
offset (ip + 1 instead of ip + 2). The resulting bogus local index is used to
index an array, which leads to an out-of-bounds read and a SIGBUS at runtime:

    make clean build run-bare -C tests/monotouch-test/dotnet/MacCatalyst TEST_VARIATION=trimmable-static-registrar

crashed in MonoTouchFixtures.ObjCRuntime.RegistrarTest.TestConstrainedGenericType.

The interpreter bug has been fixed in dotnet/runtime#131547,
but we still need to work around it until we get a runtime with that fix.

Emitting the macro/short form of the instructions avoids the problematic
instruction sequence entirely, and it also makes the generated IL smaller,
which is a good thing in itself.

For monotouch-test on macOS, this removes all 3709 adjacent long-form
'stloc; ldloc' pairs from the generated _monotouchtest.TypeMap.dll.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a002000e-438e-48ff-9c22-c716d1a2e7aa
Copilot AI lite review requested due to automatic review settings August 25, 2026 23:25
@rolfbjarne
rolfbjarne requested a review from dalexsoto as a code owner August 25, 2026 23:25

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.

Pull request overview

This PR updates the dotnet-linker’s IL generation to emit macro/short-form IL instructions (where possible) and introduces a reusable “finalize generated body” helper. This serves as a workaround for a CoreCLR interpreter bug involving long-form ldloc/stloc operands, and also reduces generated IL size across registrar- and Dlfcn-related rewriting.

Changes:

  • Introduces OptimizeGeneratedBody / FinalizeGeneratedBody helpers (optimize to macro/short forms + assign unique instruction offsets for linker/trimmer usage).
  • Switches generated registrar/lookup-table bodies from GenerateILOffsets() to FinalizeGeneratedBody().
  • Applies macro/short-form optimization to IL generated/replaced in InlineDlfcnMethodsStep.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tools/dotnet-linker/Steps/ManagedRegistrarStep.cs Finalizes generated registrar method bodies using the new helper (optimization + linker-friendly offsets).
tools/dotnet-linker/Steps/ManagedRegistrarLookupTablesStep.cs Finalizes generated lookup-table method bodies using the new helper.
tools/dotnet-linker/Steps/InlineDlfcnMethodsStep.cs Adds optimization for generated/replaced IL in Dlfcn inlining paths.
tools/dotnet-linker/CecilExtensions.cs Adds macro/short-form optimization helper and a finalization helper that also assigns unique instruction offsets.
tools/dotnet-linker/AppBundleRewriter.cs Updates generated factory methods to use the new finalization helper.
Suppressed comments (1)

tools/dotnet-linker/Steps/InlineDlfcnMethodsStep.cs:923

  • ❌ error: After clearing/rebuilding method.Body.Instructions, the newly created instructions will have default/duplicate offsets, and OptimizeGeneratedBody() won’t fix that. Because this step is configured to run before MarkStep, ensure unique instruction offsets by calling FinalizeGeneratedBody() (which also applies the macro/short-form optimization).
					// See the comment on CecilExtensions.OptimizeGeneratedBody for why this is needed.
					method.Body.OptimizeGeneratedBody ();


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +406 to +408
// See the comment on CecilExtensions.OptimizeGeneratedBody for why this is needed.
body.OptimizeGeneratedBody ();

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

⚠️ AppSizeTest expected files changed ⚠️

The AppSizeTest detected changes in the expected app size files.

To update the expected files, add a comment with the following command:

/apply-gist https://gist.github.com/vs-mobiletools-engineering-service2/8ad3c28c784489b22eb4bf6ef1e948a7
Updated files
  • MacOSX-CoreCLR-Interpreter-size.txt
  • MacOSX-CoreCLR-Interpreter-TrimmableStatic-size.txt

Pipeline on Agent
Hash: 18ea29e114deb9b8b451e9ff73fd059c11f7fd5f [PR build]

rolfbjarne and others added 2 commits August 26, 2026 21:16
Address review feedback: InlineDlfcnMethodsStep runs before MarkStep (see the
_TrimmerCustomSteps item in Xamarin.Shared.Sdk.targets), so the generated method
bodies must also get the unique instruction offsets the trimmer relies on, not
just the macro/short form optimization.

Since all the call sites now use FinalizeGeneratedBody, the OptimizeGeneratedBody
helper is no longer needed, so remove it again and move the comment back into
FinalizeGeneratedBody.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a002000e-438e-48ff-9c22-c716d1a2e7aa
@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ API diff for current PR / commit

NET (empty diffs)

✅ API diff vs stable

NET (empty diffs)

ℹ️ Generator diff

Generator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes)

Pipeline on Agent
Hash: 27d260d27604c3593a6c9a12b5ea39ef8f3193ff [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

🔥 [CI Build #27d260d] Test results 🔥

Test results

❌ Tests failed on VSTS: test results

1 tests crashed, 0 tests failed, 200 tests passed.

Failures

❌ Tests on macOS Ventura (13) tests

🔥 Failed catastrophically on VSTS: test results - mac_ventura (no summary found).

Html Report (VSDrops) Download

Successes

✅ assembly-processing: All 1 tests passed. Html Report (VSDrops) Download
✅ cecil: All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (iOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (MacCatalyst): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (macOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (Multiple platforms): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (tvOS): All 1 tests passed. Html Report (VSDrops) Download
✅ framework: All 2 tests passed. Html Report (VSDrops) Download
✅ fsharp: All 4 tests passed. Html Report (VSDrops) Download
✅ generator: All 5 tests passed. Html Report (VSDrops) Download
✅ interdependent-binding-projects: All 4 tests passed. Html Report (VSDrops) Download
✅ introspection: All 4 tests passed. Html Report (VSDrops) Download
✅ linker (iOS): All 15 tests passed. Html Report (VSDrops) Download
✅ linker (MacCatalyst): All 15 tests passed. Html Report (VSDrops) Download
✅ linker (macOS): All 21 tests passed. Html Report (VSDrops) Download
✅ linker (tvOS): All 15 tests passed. Html Report (VSDrops) Download
✅ monotouch (iOS): All 19 tests passed. Html Report (VSDrops) Download
✅ monotouch (MacCatalyst): All 18 tests passed. Html Report (VSDrops) Download
✅ monotouch (macOS): All 21 tests passed. Html Report (VSDrops) Download
✅ monotouch (tvOS): All 19 tests passed. Html Report (VSDrops) Download
✅ msbuild: All 2 tests passed. Html Report (VSDrops) Download
✅ sharpie: All 1 tests passed. Html Report (VSDrops) Download
✅ windows: All 3 tests passed. Html Report (VSDrops) Download
✅ xcframework: All 4 tests passed. Html Report (VSDrops) Download
✅ xtro: All 1 tests passed. Html Report (VSDrops) Download

macOS tests

✅ Tests on macOS Monterey (12): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sonoma (14): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sequoia (15): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Tahoe (26): All 5 tests passed. Html Report (VSDrops) Download

Linux Build Verification

Linux build succeeded

Pipeline on Agent
Hash: 27d260d27604c3593a6c9a12b5ea39ef8f3193ff [PR build]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants