Add ReadyToRun test project and create CrossModuleInliningInfo section in R2R reflection library#126486
Merged
jtschuster merged 33 commits intodotnet:mainfrom Apr 17, 2026
Merged
Conversation
Add a new test suite at src/tests/readytorun/crossmoduleresolution/ that tests R2R cross-module reference resolution across different assembly categories: Assembly graph: - A (main) - compilation target - B (version bubble, --inputbubbleref) - C (cross-module-inlineable only, --opt-cross-module) - D (external/transitive dependency) - E (type forwarder to D) Test scenarios cover: - TypeRef, MethodCall, FieldAccess across version bubble and cross-module-only - Transitive dependencies (C → D) - Nested types, type forwarders, mixed-origin generics - Interface dispatch with cross-module interfaces Two test modes via separate .csproj files: - main_crossmodule: --opt-cross-module:assemblyC (MutableModule #:N resolution) - main_bubble: --inputbubbleref:assemblyB.dll (MODULE_ZAPSIG encoding) Also adds CrossModuleResolutionTestPlan.md documenting all 5 planned phases including composite mode, ALC, and programmatic R2R validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add async Task<T> and async Task variants of each cross-module inlineable method in assemblyC, with corresponding test methods in main.cs. Enable runtime-async compilation via Features=runtime-async=on and --opt-async-methods crossgen2 flag in both test projects. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add r2rvalidate tool using ILCompiler.Reflection.ReadyToRun to programmatically verify R2R compilation artifacts: - Assembly references (MSIL + manifest metadata AssemblyRef tables) - CHECK_IL_BODY fixups proving cross-module inlining occurred - RuntimeFunction counts confirming async thunk generation (3+) Integrate validator into test precommands for both main_crossmodule and main_bubble test variants. Validator runs after crossgen2 and before the actual test execution. For non-composite images, reads MSIL AssemblyRefs via GetGlobalMetadata().MetadataReader (not ManifestReferenceAssemblies which only holds extra manifest-level refs). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace ~160 lines of inline bash/batch in each csproj with a shared crossmoduleresolution.targets file that generates scripts from MSBuild items and properties. Each csproj now declaratively specifies: - Crossgen2Step items (dependency assemblies with extra args) - Crossgen2MainRef items (references for main assembly) - R2RExpect* items (validation expectations) - Crossgen2CommonArgs/MainExtraArgs properties The targets file generates: - A __crossgen2() helper function (bash) / :__cg2_invoke subroutine (batch) - IL_DLLS copy loop from Crossgen2Step + main assembly names - Per-step crossgen2 calls via @() item transforms - Main assembly compilation with extra args and --map - R2R validation invocation with args from R2RExpect* items Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace inline bash/batch precommands with a C# RunCrossgen tool invoked at MSBuild build time via corerun. The targets file now uses an AfterTargets=Build Exec target that runs runcrossgen.dll to: - Copy IL assemblies before crossgen2 overwrites them - Run crossgen2 on each dependency in declared order - Run crossgen2 on the main assembly with refs and flags - Run r2rvalidate for R2R image validation This moves all crossgen2 work from test execution time to build time, making the generated test scripts clean (no precommands). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Set OutputPath to $(CORE_ROOT)/runcrossgen/ so the tool lives alongside crossgen2 and corerun. The targets file now references it from CORE_ROOT instead of navigating relative to the test output directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Set RuntimeIdentifier=$(NETCoreSdkRuntimeIdentifier) since runcrossgen runs at build time on the build machine, not at test time on the target. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Roslyn-based test framework for crossgen2 R2R validation: - Compiles test assemblies with Roslyn at test time - Invokes crossgen2 out-of-process via dotnet exec - Validates R2R output using ILCompiler.Reflection.ReadyToRun - 4 test cases: basic inlining, transitive refs, async, composite - Integrated into crossgen2.slnx and clr.toolstests subset Status: crossgen2 invocation works, fixup validation WIP. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use FixupKind enum + ToString(SignatureFormattingOptions) instead of ToString() which returned the class name for TodoSignature fixups - Add System.Private.CoreLib from native/ dir to crossgen2 references - Use dotnet exec instead of corerun to invoke crossgen2 - Remove opt-async-methods plumbing (unrelated to runtime-async) - Rename AsyncMethodThunks to AsyncCrossModuleInlining with correct expectations (CHECK_IL_BODY fixups, not RuntimeFunction counts) - Remove unused CoreRun property from TestPaths - Add KEEP_R2R_TESTS env var to preserve temp dirs for debugging All 4 tests pass: BasicCrossModuleInlining, TransitiveReferences, AsyncCrossModuleInlining, CompositeBasic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add 5 new tests covering key runtime-async crossgen2 PRs: - RuntimeAsyncMethodEmission (dotnet#124203): Validates [ASYNC] variant entries for Task/ValueTask-returning methods - RuntimeAsyncContinuationLayout (dotnet#123643): Validates ContinuationLayout and ResumptionStubEntryPoint fixups for methods with GC refs across awaits - RuntimeAsyncDevirtualize (dotnet#125420): Validates async virtual method devirtualization produces [ASYNC] entries for sealed/interface dispatch - RuntimeAsyncNoYield (dotnet#124203): Validates async methods without await still produce [ASYNC] variants - RuntimeAsyncCrossModule (dotnet#121679): Validates MutableModule async references work with cross-module inlining of runtime-async methods Infrastructure changes: - Add Roslyn feature flag support (runtime-async=on) to R2RTestCaseCompiler - Add R2RExpectations for async variants, resumption stubs, continuation layouts, and arbitrary fixup kinds - Add MainExtraSourceResourceNames to R2RTestCase for shared source files - Add null guard for method.Fixups in CheckFixupKinds All 9 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…dd typed Crossgen2Option - Rename DependencyInfo -> CompiledAssembly with IsCrossgenInput property - Remove AdditionalReferences: compile dependencies in listed order, each referencing all previously compiled assemblies - Add Crossgen2OptionKind enum and Crossgen2Option record replacing raw string CLI args - Remove unused CrossgenOptions from CompiledAssembly - Remove dead ReadEmbeddedSource locals in async tests - Fix Crossgen2Dir fallback to check for crossgen2.dll file instead of just directory existence (empty Debug dir was preventing Checked fallback) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…back - R2RTestCase now takes an Action<ReadyToRunReader> Validate callback instead of an R2RExpectations data object - Move CompositeMode, Crossgen2Options, Features to R2RTestCase directly - Convert R2RResultChecker to R2RAssert static helper class with methods: HasManifestRef, HasInlinedMethod, HasAsyncVariant, HasResumptionStub, HasContinuationLayout, HasResumptionStubFixup, HasFixupKind - Delete unused Expectations/R2RExpectationAttributes.cs (attribute-based design replaced by inline test code) - Each test now owns its assertions directly, making them more readable and easier to extend with custom checks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix --opt-cross-module arg emission: use space-separated args without .dll suffix instead of colon-joined format - Add -composite suffix to composite output FilePath to prevent component stubs from overwriting the composite image - Add IsComposite property to CrossgenCompilation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
InliningInfoSection2: - Add InliningEntry struct, GetEntries(), GetInliningPairs() - Method name resolution via local method map and OpenReferenceAssembly R2RResultChecker: - HasInlinedMethod checks both CrossModuleInlineInfo and all per-assembly InliningInfo2 sections (needed for composite images) - Add HasContinuationLayout(reader, methodName) overload - Add HasResumptionStubFixup(reader, methodName) overload - Add HasFixupKindOnMethod generic helper - GetAllInliningInfo2Sections iterates global + all assembly headers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New tests covering the intersection of cross-module inlining, runtime-async, and composite mode: - CompositeCrossModuleInlining, CompositeTransitive - CompositeAsync, CompositeAsyncCrossModuleInlining, CompositeAsyncTransitive (skipped: async not in composite yet) - AsyncCrossModuleContinuation, AsyncCrossModuleTransitive - MultiStepCompositeConsumer, CompositeAsyncDevirt, RuntimeAsyncNoYield Fix existing tests: BasicCrossModuleInlining (InlineableLib as Reference), TransitiveReferences (CrossModuleOptimization on lib). Use method-targeted HasContinuationLayout/HasResumptionStubFixup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add C# source files for CompositeAsync, MultiStepConsumer, AsyncCrossModuleContinuation, AsyncTransitiveMain, CompositeAsyncDevirt test cases and their dependencies. Add CrossModuleInliningInfoSection parser for ILCompiler.Reflection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sertion In composite mode, crossgen2 skips the DebuggableAttribute-based optimization detection (Program.cs:588), defaulting to OptimizationMode.None which sets CORJIT_FLAG_DEBUG_CODE and disables all inlining. Add Crossgen2Option.Optimize to all composite compilations. Add HasInlinedMethod assertion to CompositeCrossModuleInlining test to verify cross-assembly inlining actually occurs in composite mode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- CrossModuleInliningInfoSection: Fix cross-module inliner index parsing. The writer emits absolute ILBody indices (baseIndex is never updated), and the runtime reads them as absolute. The parser was incorrectly accumulating them as deltas, which would break for inlinees with 2+ cross-module inliners. - R2RDriver: Read stdout/stderr concurrently via ReadToEndAsync to avoid the classic redirected-stdio deadlock when crossgen2 fills one pipe buffer while we block reading the other. - R2RResultChecker: Load PE images into memory via File.ReadAllBytes instead of holding FileStream handles open. IAssemblyMetadata has no disposal contract and ReadyToRunReader caches instances indefinitely, so stream-backed implementations leak file handles. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a test that exercises the cross-module INLINER parsing path in CrossModuleInliningInfoSection, where multiple cross-module inliner entries exist for the same inlinee. The test uses two generic types (GenericWrapperA<T>, GenericWrapperB<T>) from a --opt-cross-module reference library, each with a virtual method that inlines the same Utility.GetValue(). Value type instantiations (LocalStruct) are required because CrossModuleCompileable discovery uses CanonicalFormKind.Specific, which preserves value types (unlike reference types that canonicalize to __Canon, losing alternate location info). This produces two distinct cross-module inliner MethodDefs for the same inlinee, validating that the parser correctly reads absolute (not delta-accumulated) inliner indices. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Rename HasMultipleCrossModuleInliners to HasCrossModuleInliners and accept expected inliner method names instead of just a count. This ensures the absolute-encoded ILBody import indices actually resolve to the correct methods (GenericWrapperA, GenericWrapperB). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
These are local session artifacts that should not be in the repository. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
These tests were superseded by the ILCompiler.ReadyToRun.Tests test suite which compiles and validates R2R images programmatically. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- R2RResultChecker: fix broken see-cref (R2RTestCase.Validate -> CrossgenCompilation.Validate) - R2RTestRunner: fix comment on BuildReferencePaths (runtime pack only, not compiled assemblies) - CrossModuleInliningInfoSection: fix version to v6.2 per readytorun.h - AsyncMethods.cs: describe actual test behavior (cross-module inlining, not RuntimeFunction layout) - BasicAsyncEmission.cs: remove false claim about resumption stubs - AsyncDevirtualize.cs: describe actual validation ([ASYNC] variants, not devirtualized calls) - AsyncCrossModule.cs: describe actual validation (manifest refs + [ASYNC] variants) - AsyncCrossModuleContinuation.cs: remove false claim about ContinuationLayout fixups - R2RTestSuites: fix 'and' -> 'or' for inlining info sections, fix A+B -> A ref, clarify devirt test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jkoritzinsky
reviewed
Apr 3, 2026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Apr 9, 2026
Open
Address review feedback on CrossModuleInlineInfo and InliningInfo2 parsers: - Fix inliner module default: use inlinee's module index (not 0) when InlinerRidHasModule flag is absent, matching writer encoding - Fix TryGetModuleName: module index 0 means owner module in both composite and non-composite images (remove CompositeBuildMode=1 ./src/tests/run.sh --runcrossgen2tests guard) - Key _localMethodMap by (moduleIndex, rid) tuple to avoid RID collisions across modules in composite images - Refactor InliningInfoSection2.ToString() to use TryGetModuleName instead of inline bounds-check with incorrect offset - Fix version comment: CrossModuleInlineInfo is v6.3, not v6.2 - Add NativeAotSupported condition to test project in Subsets.props - Exclude TestCases subdirectory sources from compilation (compiled in-memory by R2RTestCaseCompiler) - Add missing 'using System' in RuntimeAsyncMethodGenerationAttribute.cs - Remove unused usings, rename PascalCase local variable Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jkoritzinsky
approved these changes
Apr 13, 2026
The crossgen2 test infrastructure was not passing System.Private.CoreLib to crossgen2 as a reference, causing all tests to fail with: 'Failed to load assembly System.Private.CoreLib' SPCL lives in the runtime pack's native/ directory, not the lib/tfm/ directory where other managed references are found. The existing code attempted a relative path walk-up to find it but silently skipped when the directory was missing. Changes: - Add R2RTest.RuntimePackNativeDir config option plumbed from MSBuild property MicrosoftNetCoreAppRuntimePackNativeDir - Make TestPaths non-static to accept ITestOutputHelper for logging - Add Regex-based config fallback (Checked→Release/Debug) with logging when the exact config directory is not found - Thread TestPaths instance through R2RTestRunner, R2RDriver, R2RTestCaseCompiler, and SimpleAssemblyResolver - Assert with clear message if SPCL is not found after all fallbacks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The R2R tests need System.Private.CoreLib.dll in the runtime pack's native/ directory, but the CLR_Tools_Tests CI job didn't include clr.corelib in its build subsets. Without it, libs.sfx never copies SPCL into the runtime pack, causing all crossgen2 tests to fail with 'System.Private.CoreLib.dll not found'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ve dir In partial CI builds (e.g. CLR_Tools_Tests) that include clr.nativecorelib but skip libs.pretest, the runtime pack native/ layout is not populated. SPCL is still available in the CoreCLR artifacts directory. Add a fallback so tests find it in either location. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Apr 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
As part of enabling async thunks to be generated in composite mode, we'll need a number of tests to validate things work as expected. Instead of having to carefully craft coreclr tests and make sure they test what we expect, it would be helpful to have unit tests that can assert things about the output that aren't easily tested in behavioral tests. For example, we can validate that a method was inlined, or certain methods were or weren't compiled.
Create a new ILCompiler.ReadyToRun.Tests.csproj project to more granularly test readytorun outputs. The tests work similarly to ILLink. They compile the source via an in-memory Roslyn compilation, then shells out to crossgen2 to compile the app (since the JIT library cannot be initialized twice in the same process). Then, the ILCompiler.Reflection.ReadyToRun library is used to assert expectations about the final compiled R2R image.
Also add CrossModuleInliningInfoSection to the R2R reflection library and add functionality to InliningInfoSection2 to allow resolving the inliner/inlinee.
Adds a few tests to validate ReadyToRun output related to async codegen and cross-module inlining. Some tests exist that validate async method compilation in composite mode are skipped since that hasn't been implemented yet.