Skip to content

ci: R2R-compile staged DLLs (crossgen2) before nupkg pack#1

Open
oysteinkrog wants to merge 1 commit intoif/mainfrom
ci/r2r-compile-staged-dlls
Open

ci: R2R-compile staged DLLs (crossgen2) before nupkg pack#1
oysteinkrog wants to merge 1 commit intoif/mainfrom
ci/r2r-compile-staged-dlls

Conversation

@oysteinkrog
Copy link
Copy Markdown
Member

Summary

Adds a crossgen2 (ReadyToRun) compilation step to the nupkg build pipeline so the published `InitialForce.WPF` and `InitialForce.WPF.RuntimeOverride` nupkgs contain native code, matching stock `Microsoft.WindowsDesktop.App` behavior.

Why

Stock dotnet/wpf DLLs ship with R2R native code baked in by dotnet/runtime's runtime-pack assembly step. Our fork builds the libraries via `build.cmd` but does not run that step, so the DLLs in our nupkgs were JIT-only.

JIT'd frames are slightly fatter than R2R'd frames. WPF code paths that are already deep on the stack — notably the dispatcher unhandled-exception handler loading `MessageDialog.xaml` → BAML callbacks → WPFLocalizeExtension's 800-culture iteration — overflowed the 1 MB thread stack in consumers, taking the process down instead of merely showing the user an error.

What changed

  • `tools/crossgen-staged.ps1` — new script. Downloads `Microsoft.NETCore.App.Crossgen2.win-x64` 10.0.7 from nuget.org (cached under `.tools-cache/`), runs `crossgen2` over each of the 4 staged DLLs (`PresentationCore`, `PresentationFramework`, `WindowsBase`, `System.Xaml`), verifies the `RTR\0` magic in each output before replacing the input.
  • `.github/workflows/build.yml` — new step "R2R-compile staged DLLs (crossgen2)" inserted between staging and `dotnet pack`. Runs on both packaging trees, with `--targetarch` matching `matrix.arch` (so we get `win-arm64` R2R images for the arm64 build).
  • `.gitignore` — adds `.tools-cache/` so the downloaded crossgen2 binaries aren't tracked.

Verified locally

  • crossgen2 10.0.7 successfully R2R-compiles all 4 patched DLLs from a real build
  • Output sizes: `PresentationCore` +33.7%, `PresentationFramework` +40.1%, `WindowsBase` -0.5%, `System.Xaml` +145.7% (variation reflects native-code density)
  • All outputs contain the RTR magic at the expected offset
  • Consuming the R2R'd DLLs eliminates the deep-stack SO previously exhibited by the nupkgs

Companion fix

There is also a master-side defense-in-depth fix in InitialForce/ScDesktop#6790 that defers error-dialog construction off the deep dispatcher stack. Either fix alone resolves the SO; together they belt-and-suspenders the issue for any consumer of our WPF nupkgs.

Test plan

  • CI green on this PR
  • After merge: confirm the new `if.<run_number>` nupkg contains R2R'd DLLs
  • Smoke-test consumption from MotionCatalyst with the new nupkg

🤖 Generated with Claude Code

Stock dotnet/wpf DLLs in Microsoft.WindowsDesktop.App ship with
ReadyToRun native code, baked in by dotnet/runtime's runtime-pack
assembly step. Our fork builds the libraries via build.cmd but does
not run that step, so the DLLs we ship in the InitialForce.WPF nupkg
are JIT-only. This caused stack overflows in consumers: JIT'd frames
are slightly fatter than R2R'd frames, and WPF code paths that are
already deep on the stack (dispatcher unhandled-exception handler ->
MessageDialog.xaml -> BAML -> WPFLocalizeExtension's 800-culture
iteration) overflow the 1 MB thread stack.

Add a workflow step that downloads the upstream
Microsoft.NETCore.App.Crossgen2.win-x64 NuGet package (cached under
.tools-cache/) and runs crossgen2 over the 4 staged DLLs in both
packaging trees (InitialForce.WPF and InitialForce.WPF.RuntimeOverride).
Each output is verified to contain the R2R magic before replacing the
input. --targetarch matches the matrix.arch so we get win-arm64 R2R
images for the arm64 build.

Verified locally: crossgen2 10.0.7 successfully R2R-compiles all 4
patched DLLs (PresentationCore, PresentationFramework, WindowsBase,
System.Xaml). Output sizes grow ~0-145% (varies by symbol density),
all contain the RTR magic at the expected offset, and consuming the
R2R'd DLLs eliminates the deep-stack SO that the previous nupkgs
exhibited.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant