diff --git a/eng/Subsets.props b/eng/Subsets.props index 337bca6fa63caf..318ffc4179c8ec 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -168,7 +168,7 @@ clr.nativeprereqs+clr.iltools+clr.runtime+clr.native+clr.aot+clr.nativeaotlibs+clr.nativeaotruntime+clr.crossarchtools - $(AllSubsetsExpansion)+clr.paltests+clr.paltestlist+clr.hosts+clr.jit+clr.alljits+clr.alljitscommunity+clr.spmi+clr.corelib+clr.nativecorelib+clr.tools+clr.toolstests+clr.packages + $(AllSubsetsExpansion)+clr.paltests+clr.paltestlist+clr.hosts+clr.jit+clr.alljits+clr.alljitscommunity+clr.spmi+clr.corelib+clr.nativecorelib+clr.tools+clr.toolstests+clr.r2rtests+clr.packages $(AllSubsetsExpansion)+linuxdac+alpinedac $(AllSubsetsExpansion)+mono.runtime+provision.emsdk+mono.aotcross+mono.corelib+mono.manifests+mono.packages+mono.tools+mono.wasmruntime+mono.wasiruntime+mono.wasmworkload+mono.mscordbi $(AllSubsetsExpansion)+tools.illink+tools.cdac+tools.illinktests+tools.cdactests+tools.cdacdumptests @@ -232,6 +232,7 @@ + @@ -393,7 +394,6 @@ - <_CrossToolSubset Condition="'$(_BuildCrossComponents)' == 'true' and '$(TargetArchitecture)' != 'wasm' and $(_subset.Contains('+clr.toolstests+'))" Include="ClrAllJitsSubset=true" /> <_CrossToolSubset Condition="'$(_BuildCrossComponents)' == 'true' and '$(TargetArchitecture)' != 'wasm' and ($(_subset.Contains('+clr.tools+')) or $(_subset.Contains('+clr.nativecorelib+')) or $(_subset.Contains('+clr.crossarchtools+')))" Include="ClrJitSubset=true" /> <_CrossToolSubset Condition="'$(_BuildCrossComponents)' == 'true' and '$(TargetArchitecture)' == 'wasm' and ($(_subset.Contains('+clr.tools+')) or $(_subset.Contains('+clr.nativecorelib+')) or $(_subset.Contains('+clr.crossarchtools+')))" Include="ClrWasmJitSubset=true" /> @@ -519,14 +519,17 @@ Test="true" Category="clr" Condition="'$(DotNetBuildSourceOnly)' != 'true' and '$(NativeAotSupported)' == 'true'"/> - + + + + <_CDacToolsBuilt Condition="'$(_CDacToolsBuilt)' != 'true'">true diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index af2fc6e3392cf5..53dc7851765d6d 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -232,6 +232,7 @@ extends: eq(variables['wasmDarcDependenciesChanged'], true), eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true), eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_wasm_coreclr_runtimetests.containsChange'], true), + eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), eq(variables['isRollingBuild'], true)) - template: /eng/pipelines/common/platform-matrix.yml @@ -951,6 +952,166 @@ extends: eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_illink.containsChange'], true), eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_tools_cdac.containsChange'], true), eq(variables['isRollingBuild'], true)) + + # The R2R test suite compiles for one target per run: the test assembly itself always runs on + # the build machine, while crossgen2 and the shared framework it compiles against are staged + # for whatever the build targets. Each leg therefore needs only its own target's artifacts, + # and test cases the target cannot compile are skipped rather than failed. + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + buildConfig: checked + platforms: + - linux_x64 + jobParameters: + dependsOn: + - build_linux_x64_checked_CoreCLR_ReleaseLibraries + timeoutInMinutes: 120 + nameSuffix: CLR_R2R_Tests_linux_x64 + buildArgs: -s clr.r2rtests -lc Release -c $(_BuildConfig) -test + enablePublishTestResults: true + testResultsFormat: 'xunit' + preBuildSteps: + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + artifactName: CoreCLR_ReleaseLibraries_BuildArtifacts_linux_x64_Checked + artifactFileName: CoreCLR_ReleaseLibraries_BuildArtifacts_linux_x64_Checked$(archiveExtension) + unpackFolder: $(Build.SourcesDirectory)/artifacts/bin + cleanUnpackFolder: false + overwriteExistingFiles: true + displayName: Download linux-x64 artifacts + condition: >- + or( + eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), + eq(variables['isRollingBuild'], true)) + + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + buildConfig: checked + platforms: + - linux_x64 + variables: + - name: _osParameter + value: -os browser + - name: _archParameter + value: -arch wasm + jobParameters: + dependsOn: + - build_browser_wasm_linux_checked_CoreCLR_ReleaseLibraries + timeoutInMinutes: 120 + nameSuffix: CLR_R2R_Tests_browser_wasm + buildArgs: -s clr.r2rtests -lc Release -c $(_BuildConfig) -test + enablePublishTestResults: true + testResultsFormat: 'xunit' + preBuildSteps: + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + artifactName: CoreCLR_ReleaseLibraries_BuildArtifacts_browser_wasm_linux_Checked + artifactFileName: CoreCLR_ReleaseLibraries_BuildArtifacts_browser_wasm_linux_Checked$(archiveExtension) + unpackFolder: $(Build.SourcesDirectory)/artifacts/bin + cleanUnpackFolder: false + overwriteExistingFiles: true + displayName: Download browser-wasm artifacts + condition: >- + or( + eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), + eq(variables['isRollingBuild'], true)) + + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + buildConfig: checked + platforms: + - linux_x64 + variables: + - name: _archParameter + value: -arch arm + jobParameters: + dependsOn: + - build_linux_arm_checked_CoreCLR_ReleaseLibraries + timeoutInMinutes: 120 + nameSuffix: CLR_R2R_Tests_linux_arm + buildArgs: -s clr.r2rtests -lc Release -c $(_BuildConfig) -test + enablePublishTestResults: true + testResultsFormat: 'xunit' + preBuildSteps: + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + artifactName: CoreCLR_ReleaseLibraries_BuildArtifacts_linux_arm_Checked + artifactFileName: CoreCLR_ReleaseLibraries_BuildArtifacts_linux_arm_Checked$(archiveExtension) + unpackFolder: $(Build.SourcesDirectory)/artifacts/bin + cleanUnpackFolder: false + overwriteExistingFiles: true + displayName: Download linux-arm artifacts + condition: >- + or( + eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), + eq(variables['isRollingBuild'], true)) + + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + buildConfig: checked + platforms: + - linux_x64 + variables: + - name: _osParameter + value: -os ios + - name: _archParameter + value: -arch arm64 + jobParameters: + timeoutInMinutes: 120 + nameSuffix: CLR_R2R_Tests_ios_arm64 + # No prebuilt artifact can supply this leg: the iOS jobs run on macOS, so their cross + # components are Mach-O and unusable here. The cross components are built from source + # instead - they target the build host (linux-x64), not iOS, so no Apple SDK is needed. + # libs.sfx rather than libs, because libs.native does require the Apple SDK. + buildArgs: -s clr.crossarchtools+clr.corelib+libs.sfx -rf CoreCLR -lc Release -c $(_BuildConfig) + enablePublishTestResults: true + testResultsFormat: 'xunit' + postBuildSteps: + # A separate invocation because clr.r2rtests is ordered ahead of libs.sfx in + # Subsets.props, so a single build would run the tests before their inputs exist. + - template: /eng/pipelines/common/templates/global-build-step.yml + parameters: + buildArgs: -s clr.r2rtests -rf CoreCLR -lc Release -c $(_BuildConfig) -test + displayName: Build and run R2R tests + condition: >- + or( + eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), + eq(variables['isRollingBuild'], true)) + + # The only leg with a Windows host, which the two --pdb test cases require: crossgen2 writes + # Windows PDBs through Microsoft.DiaSymReader.Native, which is restored for Windows only. + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + buildConfig: checked + platforms: + - windows_x64 + jobParameters: + dependsOn: + - build_windows_x64_checked_CoreCLR_ReleaseLibraries + timeoutInMinutes: 120 + nameSuffix: CLR_R2R_Tests_windows_x64 + buildArgs: -s clr.r2rtests -lc Release -c $(_BuildConfig) -test + enablePublishTestResults: true + testResultsFormat: 'xunit' + preBuildSteps: + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + artifactName: CoreCLR_ReleaseLibraries_BuildArtifacts_windows_x64_Checked + artifactFileName: CoreCLR_ReleaseLibraries_BuildArtifacts_windows_x64_Checked$(archiveExtension) + unpackFolder: $(Build.SourcesDirectory)/artifacts/bin + cleanUnpackFolder: false + overwriteExistingFiles: true + displayName: Download windows-x64 artifacts + condition: >- + or( + eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), + eq(variables['isRollingBuild'], true)) + # # Build CrossDacs # diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj index 9969de865e5fe9..1c77956d8bbe6b 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/ILCompiler.ReadyToRun.Tests.csproj @@ -1,17 +1,22 @@ + + + ILCompiler.ReadyToRun.Tests $(NetCoreAppToolCurrent) enable - false - true - x64;x86 - AnyCPU - linux-x64;win-x64;osx-x64 - Debug;Release;Checked - true -notrait category=failing + + AnyCPU + $(NETCoreSdkRuntimeIdentifier) + false + + $(BaseOutputPath)$(Configuration)\$(CoreCLRConfiguration)_CLR\$(TargetRid)\ @@ -21,93 +26,49 @@ - - - - CopyAllJitLibrariesToAotCompilerOutput=true - Configuration=$(CoreCLRConfiguration);CopyAllJitLibrariesToAotCompilerOutput=true + + Configuration=$(CoreCLRConfiguration);CopyAllJitLibrariesToAotCompilerOutput=true;TargetArchitecture=$(TargetArchitecture);TargetOS=$(TargetOS) - - - <_BuildJitsCrossArch Condition="'$(CrossBuild)' == 'true' or '$(BuildArchitecture)' != '$(TargetArchitecture)' or '$(HostOS)' != '$(TargetOS)' or '$(TargetsLinuxBionic)' == 'true' or '$(EnableNativeSanitizers)' != ''">true - <_BuildJitsProperties>ClrAllJitsSubset=true;ClrWasmJitSubset=true;Configuration=$(CoreCLRConfiguration) - <_BuildJitsProperties Condition="!$([MSBuild]::IsOsPlatform(Windows))">$(_BuildJitsProperties);Ninja=true - <_BuildJitsProperties Condition="'$(_BuildJitsCrossArch)' == 'true'">$(_BuildJitsProperties);HostArchitecture=$(BuildArchitecture);HostCrossOS=$(HostOS);CrossBuild=false;BuildSubdirectory=$(BuildArchitecture);CMakeArgs=$(CMakeArgs) -DCLR_CROSS_COMPONENTS_BUILD=1;PgoInstrument=false;NoPgoOptimize=true - - - - - - - <_WasmJitCrossHostArchSubdir Condition="'$(_BuildJitsCrossArch)' == 'true'">$(BuildArchitecture)/ - <_WasmJitFileName>$(HostLibPrefix)clrjit_universal_wasm_$(BuildArchitecture)$(HostLibSuffix) - <_WasmJitSourcePath>$(CoreCLRArtifactsPath)$(_WasmJitCrossHostArchSubdir)$(_WasmJitFileName) - <_Crossgen2InbuildPublishDir>$(CoreCLRArtifactsPath)$(BuildArchitecture)/crossgen2/ - - - - - - + + + + + + + <_SharedFrameworkAssembly Include="$(LibrariesSharedFrameworkBinArtifactsPath)*.dll" /> + <_SharedFrameworkAssembly Include="$(CoreCLRArtifactsPath)IL/System.Private.CoreLib.dll" /> + + + + + + + + + + - - $(CoreCLRArtifactsPath)/$(BuildArchitecture)/crossgen2 - - - $(MicrosoftNetCoreAppRuntimePackRidLibTfmDir) - - - $(MicrosoftNetCoreAppRuntimePackNativeDir) - - - $(MicrosoftNetCoreAppRefPackRefDir) - - - $(CoreCLRArtifactsPath) - - - $(TargetArchitecture) - - - $(TargetOS) - - - $(CoreCLRConfiguration) - + + + diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs index 9bde75896d70a5..fc25e2a448c02a 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCases/R2RTestSuites.cs @@ -29,7 +29,7 @@ public R2RTestSuites(ITestOutputHelper output) _output = output; } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void BasicCrossModuleInlining() { var inlineableLib = new CompiledAssembly @@ -62,7 +62,7 @@ static void Validate(ReadyToRunReader reader) } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsWasmTarget))] public void WasmWebcilModule() { var wasmWebcilModule = new CompiledAssembly @@ -77,13 +77,6 @@ public void WasmWebcilModule() new(nameof(WasmWebcilModule), [new CrossgenAssembly(wasmWebcilModule)]) { OutputFileExtension = ".wasm", - AdditionalArgs = - { - "--targetarch", - "wasm", - "--targetos", - "browser", - }, Validate = Validate, }, ])); @@ -128,7 +121,7 @@ static void Validate(ReadyToRunReader reader) } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsWasmTarget))] public void WasmSimdModule() { var wasmSimdModule = new CompiledAssembly @@ -143,13 +136,6 @@ public void WasmSimdModule() new(nameof(WasmSimdModule), [new CrossgenAssembly(wasmSimdModule)]) { OutputFileExtension = ".wasm", - AdditionalArgs = - { - "--targetarch", - "wasm", - "--targetos", - "browser", - }, Validate = Validate, }, ])); @@ -209,7 +195,7 @@ static WebcilImageReader.WasmFunctionInfo ResolveWasmBody( } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void RuntimeFunctionsSectionSizeExcludesSentinel() { var lib = new CompiledAssembly @@ -242,7 +228,7 @@ static void Validate(ReadyToRunReader reader) } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsArmTarget))] public void ArmThumbBitRelocationTargets() { var inlineableLib = new CompiledAssembly @@ -266,7 +252,6 @@ public void ArmThumbBitRelocationTargets() new CrossgenAssembly(inlineableLib) { Kind = Crossgen2InputKind.Reference }, ]) { - Options = [Crossgen2Option.TargetArchArm], Validate = Validate, }, ])); @@ -279,7 +264,7 @@ static void Validate(ReadyToRunReader reader) } // JitStressProcedureSplitting is only available in Debug/Checked JIT builds. - [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotReleaseCoreCLR))] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotReleaseCoreCLR), nameof(TestPaths.IsArmTarget))] public void ArmThumbBitHotColdRuntimeFunctions() { var hotColdSplitting = new CompiledAssembly @@ -295,7 +280,6 @@ public void ArmThumbBitHotColdRuntimeFunctions() { Options = [ - Crossgen2Option.TargetArchArm, Crossgen2Option.Optimize, Crossgen2Option.HotColdSplitting, ], @@ -315,7 +299,7 @@ static void Validate(ReadyToRunReader reader) } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void TransitiveReferences() { var externalLib = new CompiledAssembly() @@ -358,7 +342,7 @@ public void TransitiveReferences() ])); } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void AsyncCrossModuleInlining() { var asyncInlineableLib = new CompiledAssembly @@ -398,7 +382,7 @@ static void Validate(ReadyToRunReader reader) } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeBasic() { var compositeLib = new CompiledAssembly @@ -434,7 +418,7 @@ static void Validate(ReadyToRunReader reader) } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeManifestAssemblyMvidsAreAligned() { var compositeLib = new CompiledAssembly @@ -470,9 +454,11 @@ static void Validate(ReadyToRunReader reader) } } - public static bool IsWindows => System.OperatingSystem.IsWindows(); - - [ConditionalFact(nameof(IsWindows))] + /// + /// Requires a Windows host for --pdb (see ), and a + /// Windows target because the padding being verified is in the composite PE image. + /// + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsWindowsHost), nameof(TestPaths.IsWindowsTarget))] public void CompositeManifestAssemblyMvidsArePaddedWhenPdbPresent() { var compositeLib = new CompiledAssembly @@ -522,7 +508,7 @@ static void Validate(ReadyToRunReader reader) /// boundary. When they landed on an unaligned RVA the runtime faulted on ARM32 (which does not /// permit unaligned multi-word loads) during coreclr_initialize; x64/arm64 tolerated it. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeManifestSectionsAreAligned() { var compositeLib = new CompiledAssembly @@ -561,10 +547,11 @@ static void Validate(ReadyToRunReader reader) /// /// Complements using the same trigger as the /// MVID-table test: --pdb emits an odd-sized debug directory section that shifts the manifest - /// sections off a 4-byte boundary without the fix. Windows-only because it relies on Windows PDB - /// generation. + /// sections off a 4-byte boundary without the fix. Requires a Windows host for --pdb + /// (see ), and a Windows target because the padding being + /// verified is in the composite PE image. /// - [ConditionalFact(nameof(IsWindows))] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsWindowsHost), nameof(TestPaths.IsWindowsTarget))] public void CompositeManifestSectionsArePaddedWhenPdbPresent() { var compositeLib = new CompiledAssembly @@ -601,7 +588,7 @@ static void Validate(ReadyToRunReader reader) } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void RuntimeAsyncMethodEmission() { var runtimeAsyncMethodEmission = new CompiledAssembly @@ -639,7 +626,7 @@ static void Validate(ReadyToRunReader reader) /// It must also strip a non-async Task-returning method whose async variant has already been /// compiled, since the IL is no longer needed at runtime. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void RuntimeAsyncStripILBodiesPreservesTaskReturningIL() { var stripILBodies = new CompiledAssembly @@ -659,7 +646,6 @@ public void RuntimeAsyncStripILBodiesPreservesTaskReturningIL() new(nameof(RuntimeAsyncStripILBodiesPreservesTaskReturningIL), [new CrossgenAssembly(stripILBodies)]) { Options = [Crossgen2Option.Composite, Crossgen2Option.Optimize, Crossgen2Option.StripILBodies], - AdditionalArgs = ["--targetarch:x64"], Validate = Validate, }, ])); @@ -695,7 +681,7 @@ static void Validate(ReadyToRunReader reader) } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsIosArm64Target))] public void AppleMobileStripILBodiesUsesFixedInstructionSet() { var stripILBodies = new CompiledAssembly @@ -715,7 +701,6 @@ public void AppleMobileStripILBodiesUsesFixedInstructionSet() new(nameof(AppleMobileStripILBodiesUsesFixedInstructionSet), [new CrossgenAssembly(stripILBodies)]) { Options = [Crossgen2Option.Composite, Crossgen2Option.Optimize, Crossgen2Option.StripILBodies], - AdditionalArgs = ["--targetos:ios", "--targetarch:arm64"], Validate = Validate, }, ])); @@ -744,7 +729,7 @@ static void Validate(ReadyToRunReader reader) /// produce ContinuationLayout fixups encoding the GC ref map. /// PR #124203: Resumption stubs for methods with suspension points. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void RuntimeAsyncContinuationLayout() { var runtimeAsyncContinuationLayout = new CompiledAssembly @@ -783,7 +768,7 @@ static void Validate(ReadyToRunReader reader) /// PR #125420: [ASYNC] variant generation for devirtualizable async call patterns /// (sealed class and interface dispatch through AsyncAwareVirtualMethodResolutionAlgorithm). /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void RuntimeAsyncDevirtualize() { var runtimeAsyncDevirtualize = new CompiledAssembly @@ -818,7 +803,7 @@ static void Validate(ReadyToRunReader reader) /// PR #124203: Async methods without yield points may omit resumption stubs. /// Validates that no-yield async methods still produce [ASYNC] variants. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void RuntimeAsyncNoYield() { var runtimeAsyncNoYield = new CompiledAssembly @@ -855,7 +840,7 @@ static void Validate(ReadyToRunReader reader) /// --determinism-stress), each compiled method should have exactly one /// ResumptionStubEntryPoint fixup. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void RuntimeAsyncResumptionStubFixupDedup() { var asm = new CompiledAssembly @@ -898,7 +883,7 @@ static void Validate(ReadyToRunReader reader) /// PR #121679: MutableModule async references + cross-module inlining /// of runtime-async methods with cross-module dependency. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void RuntimeAsyncCrossModule() { var asyncDepLib = new CompiledAssembly @@ -957,7 +942,7 @@ static void Validate(ReadyToRunReader reader) /// Validates that inlining info (CrossModuleInlineInfo or InliningInfo2) is /// properly populated (CompositeBasic only validates ManifestRef). /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeCrossModuleInlining() { var inlineableLib = new CompiledAssembly @@ -999,7 +984,7 @@ static void Validate(ReadyToRunReader reader) /// assemblies does NOT produce a CrossModuleInlineInfo section. CrossModuleInlineInfo only records /// inlining where the inlinee module is outside the compiled image's version bubble /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeDoesNotProduceCrossModuleInliningInfo() { var inlineableLib = new CompiledAssembly @@ -1046,7 +1031,7 @@ static void Validate(ReadyToRunReader reader) /// comes from an assembly outside the version bubble (passed as a Reference with /// --opt-cross-module). /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeProducesCrossModuleInliningInfoForExternalReference() { var inlineableLib = new CompiledAssembly @@ -1098,7 +1083,7 @@ static void Validate(ReadyToRunReader reader) /// Composite mode with runtime-async methods in both assemblies. /// Validates async variants exist in composite output. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeAsync() { var asyncCompositeLib = new CompiledAssembly @@ -1143,7 +1128,7 @@ static void Validate(ReadyToRunReader reader) /// Verifies that, in composite mode, awaitless async candidates ARE inlined into /// their callers. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeAsyncInliningMatrix() { var asyncInlineCandidatesLib = new CompiledAssembly @@ -1193,7 +1178,7 @@ static void Validate(ReadyToRunReader reader) /// https://github.com/dotnet/runtime/pull/126904 added support for ensuring the OwningType signature modifier is emitted /// for these methods. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeAsyncGenericTypes() { var asyncGenericTypeLib = new CompiledAssembly @@ -1258,7 +1243,7 @@ static void Validate(ReadyToRunReader reader) /// captures GC refs across await points. Validates that ContinuationLayout /// fixups correctly reference cross-module types via MutableModule tokens. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void AsyncCrossModuleContinuation() { var asyncDepLibCont = new CompiledAssembly @@ -1313,7 +1298,7 @@ static void Validate(ReadyToRunReader reader) /// Two-step compilation: composite A+B, then non-composite C referencing A. /// Exercises the multi-compilation model. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void MultiStepCompositeAndNonComposite() { var libA = new CompiledAssembly @@ -1378,7 +1363,7 @@ public void MultiStepCompositeAndNonComposite() /// Composite + runtime-async + cross-module devirtualization. /// Interface defined in AsyncInterfaceLib, call sites in CompositeAsyncDevirtMain. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeAsyncDevirtualize() { var asyncInterfaceLib = new CompiledAssembly @@ -1426,7 +1411,7 @@ static void Validate(ReadyToRunReader reader) /// devirtualizes to a sealed receiver. Resolving the callee's async-variant thunk must unwrap it /// to the underlying EcmaMethod. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeAsyncDevirtNonAsyncCallee() { // Compiled WITHOUT runtime-async so the awaited virtuals get synthesized async-variant thunks. @@ -1473,7 +1458,7 @@ static void Validate(ReadyToRunReader reader) /// Composite with 3 assemblies in A→B→C transitive chain. /// Validates manifest refs for all three and transitive inlining. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeTransitive() { var externalLib = new CompiledAssembly @@ -1521,7 +1506,7 @@ static void Validate(ReadyToRunReader reader) /// Non-composite runtime-async + transitive cross-module inlining. /// Chain: AsyncTransitiveMain → AsyncTransitiveLib → AsyncExternalLib. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void AsyncCrossModuleTransitive() { var asyncExternalLib = new CompiledAssembly @@ -1582,7 +1567,7 @@ static void Validate(ReadyToRunReader reader) /// Composite + runtime-async + transitive (3 assemblies). /// Full combination of composite, async, and transitive references. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CompositeAsyncTransitive() { var asyncExternalLib = new CompiledAssembly @@ -1641,7 +1626,7 @@ static void Validate(ReadyToRunReader reader) /// Step 1: Composite of async libs. Step 2: Non-composite consumer /// with cross-module inlining of async methods. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void MultiStepCompositeAndNonCompositeAsync() { var asyncDepLib = new CompiledAssembly @@ -1712,7 +1697,7 @@ public void MultiStepCompositeAndNonCompositeAsync() /// CrossModuleInlineInfo section, exercising the absolute-index encoding /// (not delta-encoded) for cross-module inliner entries. /// - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void CrossModuleGenericMultiInliner() { var crossModuleGenericLib = new CompiledAssembly @@ -1758,7 +1743,7 @@ static void Validate(ReadyToRunReader reader) } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void VirtualMethodGenericsNonGVM() { var nonGvmLib = new CompiledAssembly @@ -1803,7 +1788,7 @@ static void Validate(ReadyToRunReader reader) } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void VirtualMethodGenericsGVM() { var gvmLib = new CompiledAssembly @@ -1848,7 +1833,7 @@ static void Validate(ReadyToRunReader reader) } } - [Fact] + [ConditionalFact(typeof(TestPaths), nameof(TestPaths.IsNotWasmTarget))] public void VirtualMethodGenericsGenericLookup() { var genericLookupLib = new CompiledAssembly diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RDriver.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RDriver.cs index c1da793302ad01..059f522b6d0f34 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RDriver.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RDriver.cs @@ -32,7 +32,6 @@ internal enum Crossgen2Option InputBubble, HotColdSplitting, Optimize, - TargetArchArm, StripILBodies, } @@ -59,7 +58,6 @@ internal static class Crossgen2OptionsExtensions Crossgen2Option.InputBubble => $"--input-bubble", Crossgen2Option.HotColdSplitting => $"--hot-cold-splitting", Crossgen2Option.Optimize => $"--optimize", - Crossgen2Option.TargetArchArm => $"--targetarch:arm", Crossgen2Option.StripILBodies => $"--strip-il-bodies", _ => throw new ArgumentOutOfRangeException(nameof(kind)), }; @@ -83,29 +81,23 @@ internal sealed class R2RDriver { private static readonly TimeSpan ProcessTimeout = TimeSpan.FromMinutes(2); private readonly ITestOutputHelper _output; - private readonly TestPaths _paths; - public R2RDriver(ITestOutputHelper output, TestPaths paths) + public R2RDriver(ITestOutputHelper output) { _output = output; - _paths = paths; - - if (!File.Exists(_paths.Crossgen2Exe)) - throw new FileNotFoundException($"crossgen2 executable not found at {_paths.Crossgen2Exe}"); } /// - /// Runs crossgen2 with the given arguments. + /// Runs the crossgen2 that compiles for this build's target RID with the given arguments. /// public R2RCompilationResult Compile(List args) { - var fullArgs = new List(args); - return RunCrossgen2(fullArgs); + return RunCrossgen2(TestPaths.Crossgen2Exe, new List(args)); } - private R2RCompilationResult RunCrossgen2(List crossgen2Args) + private R2RCompilationResult RunCrossgen2(string crossgen2Exe, List crossgen2Args) { - var psi = new ProcessStartInfo(_paths.Crossgen2Exe, crossgen2Args) + var psi = new ProcessStartInfo(crossgen2Exe, crossgen2Args) { RedirectStandardOutput = true, RedirectStandardError = true, @@ -119,7 +111,7 @@ private R2RCompilationResult RunCrossgen2(List crossgen2Args) psi.Environment[envVar] = null; } - string commandLine = $"{_paths.Crossgen2Exe} {string.Join(" ", crossgen2Args)}"; + string commandLine = $"{crossgen2Exe} {string.Join(" ", crossgen2Args)}"; _output.WriteLine($" crossgen2 command: {commandLine}"); using var process = Process.Start(psi)!; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs index 68fd1d518bd545..522472920c4f1d 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RResultChecker.cs @@ -1186,11 +1186,15 @@ public static bool MethodILIsPresent(string msilFilePath, string declaringType, /// internal sealed class SimpleAssemblyResolver : IAssemblyResolver { - private readonly TestPaths _paths; + private readonly Dictionary _assemblyPaths; - public SimpleAssemblyResolver(TestPaths paths) + public SimpleAssemblyResolver(IEnumerable referencePaths) { - _paths = paths; + _assemblyPaths = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (string referencePath in referencePaths) + { + _assemblyPaths[Path.GetFileNameWithoutExtension(referencePath)] = referencePath; + } } public IAssemblyMetadata? FindAssembly(MetadataReader metadataReader, AssemblyReferenceHandle assemblyReferenceHandle, string parentFile) @@ -1209,10 +1213,12 @@ public SimpleAssemblyResolver(TestPaths paths) string candidate = Path.Combine(dir, simpleName + ".dll"); if (!File.Exists(candidate)) - candidate = Path.Combine(_paths.RuntimePackDir, simpleName + ".dll"); + { + if (!_assemblyPaths.TryGetValue(simpleName, out string? referencePath) || referencePath is null) + return null; - if (!File.Exists(candidate)) - return null; + candidate = referencePath; + } return new SimpleAssemblyMetadata(candidate); } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestCaseCompiler.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestCaseCompiler.cs index 7bd12c8887fe59..476ac89c09ce6e 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestCaseCompiler.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestCaseCompiler.cs @@ -19,26 +19,13 @@ internal sealed class R2RTestCaseCompiler { private readonly List _frameworkReferences; - public R2RTestCaseCompiler(TestPaths paths) + public R2RTestCaseCompiler(List references) { _frameworkReferences = new List(); - // Add reference assemblies from the ref pack (needed for Roslyn compilation) - string refPackDir = paths.RefPackDir; - if (Directory.Exists(refPackDir)) + foreach (string refPath in references) { - foreach (string refPath in Directory.EnumerateFiles(refPackDir, "*.dll")) - { - _frameworkReferences.Add(MetadataReference.CreateFromFile(refPath)); - } - } - else - { - // Fallback to runtime pack implementation assemblies - foreach (string refPath in paths.GetFrameworkReferencePaths()) - { - _frameworkReferences.Add(MetadataReference.CreateFromFile(refPath)); - } + _frameworkReferences.Add(MetadataReference.CreateFromFile(refPath)); } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs index f466fd20d336e7..4fdb38bc20efbf 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/R2RTestRunner.cs @@ -180,12 +180,10 @@ public void SetOutputDir(string outputDir) internal sealed class R2RTestRunner { private readonly ITestOutputHelper _output; - private readonly TestPaths _paths; public R2RTestRunner(ITestOutputHelper output) { _output = output; - _paths = new TestPaths(output); } /// @@ -208,19 +206,19 @@ public void Run(R2RTestCase testCase) var assemblyPaths = CompileAllAssemblies(assembliesToCompile); // Step 2: Run each crossgen2 compilation and validate - var driver = new R2RDriver(_output, _paths); - var refPaths = BuildReferencePaths(); + var driver = new R2RDriver(_output); + List refPaths = BuildReferencePaths(); foreach(var compilation in testCase.Compilations) { string outputPath = RunCrossgenCompilation( - testCase.Name, compilation, driver, compilation.FilePath, refPaths, assemblyPaths); + testCase.Name, compilation, driver, compilation.FilePath, assemblyPaths); if (compilation.Validate is not null) { Assert.True(File.Exists(outputPath), $"R2R image not found: {outputPath}"); _output.WriteLine($" Validating R2R image: {outputPath}"); - var reader = new ReadyToRunReader(new SimpleAssemblyResolver(_paths), outputPath); + var reader = new ReadyToRunReader(new SimpleAssemblyResolver(refPaths), outputPath); compilation.Validate(reader); } } @@ -238,9 +236,10 @@ public void Run(R2RTestCase testCase) private Dictionary CompileAllAssemblies( IEnumerable assemblies) { - var compiler = new R2RTestCaseCompiler(_paths); var paths = new Dictionary(); + var defaultReferences = BuildReferencePaths(); + var compiler = new R2RTestCaseCompiler(defaultReferences); foreach (var asm in assemblies) { var sources = asm.SourceResourceNames @@ -256,7 +255,7 @@ private Dictionary CompileAllAssemblies( additionalReferences: asm.References.Select(r => r.FilePath).ToList(), features: asm.Features.Count > 0 ? asm.Features : null); paths[asm.AssemblyName] = ilPath; - _output.WriteLine($" Roslyn compiled '{asm.AssemblyName}' -> {ilPath}"); + _output.WriteLine($"Roslyn compiled '{asm.AssemblyName}' -> {ilPath}"); } return paths; @@ -275,7 +274,6 @@ private static string RunCrossgenCompilation( CrossgenCompilation compilation, R2RDriver driver, string outputFile, - List refPaths, Dictionary assemblyPaths) { var args = new List(); @@ -311,11 +309,13 @@ private static string RunCrossgenCompilation( foreach (var option in compilation.Options) args.Add(option.ToArg()); + args.AddRange(["--targetos", TestPaths.TargetOS, "--targetarch", TestPaths.TargetArchitecture]); + // Caller-supplied raw args (for options that take values, e.g. --determinism-stress=N) args.AddRange(compilation.AdditionalArgs); - // Global refs (runtime pack + System.Private.CoreLib) - AddRefArgs(args, refPaths); + // Global refs (shared framework + System.Private.CoreLib) + AddRefArgs(args); EnsureDirectoryExists(Path.GetDirectoryName(outputFile)); @@ -330,27 +330,28 @@ private static string RunCrossgenCompilation( return outputFile; } - private static void AddRefArgs(List args, List refPaths) + /// + /// Adds the shared framework references for crossgen2 as a single directory wildcard. + /// + private static void AddRefArgs(List args) { - foreach (string refPath in refPaths) - { - args.Add("-r"); - args.Add(refPath); - } + args.Add("-r"); + args.Add(Path.Combine(TestPaths.LibrariesDir, "*.dll")); } - private List BuildReferencePaths() + /// + /// Builds the explicit reference paths used for Roslyn compilation and for resolving assemblies + /// when reading back an R2R image, from the shared framework IL assemblies staged for this + /// build's target RID. crossgen2 takes the same assemblies as a wildcard; see . + /// + private static List BuildReferencePaths() { - var paths = new List(); - - paths.Add(Path.Combine(_paths.RuntimePackDir, "*.dll")); + string librariesDir = TestPaths.LibrariesDir; - string spcl = _paths.SystemPrivateCoreLibPath; - Assert.True(File.Exists(spcl), - $"System.Private.CoreLib.dll not found at '{spcl}'. " + - $"Searched RuntimePackNativeDir='{_paths.RuntimePackNativeDir}' and " + - $"CoreCLRArtifactsDir='{_paths.CoreCLRArtifactsDir}'"); - paths.Add(spcl); + List paths = [.. Directory.GetFiles(librariesDir, "*.dll")]; + Assert.True( + paths.Exists(p => Path.GetFileName(p) == "System.Private.CoreLib.dll"), + $"System.Private.CoreLib.dll not found in staged references: {librariesDir}"); return paths; } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/TestPaths.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/TestPaths.cs index f028b442cf8e86..8df61102255e4f 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/TestPaths.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/TestCasesRunner/TestPaths.cs @@ -2,225 +2,83 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; -using System.Text.RegularExpressions; -using Xunit.Abstractions; namespace ILCompiler.ReadyToRun.Tests.TestCasesRunner; /// -/// Provides paths to build artifacts needed by the test infrastructure. -/// All paths come from RuntimeHostConfigurationOption items in the csproj. +/// Provides paths to build artifacts needed by the test infrastructure, and the target and host +/// predicates that gate test cases. /// -internal sealed class TestPaths +internal static class TestPaths { - private readonly ITestOutputHelper _output; - - public TestPaths(ITestOutputHelper output) - { - _output = output; - } - private static string GetRequiredConfig(string key) { return AppContext.GetData(key) as string ?? throw new InvalidOperationException($"Missing RuntimeHostConfigurationOption '{key}'. Was the project built with the correct properties?"); } - /// - /// Tries to find an existing directory by swapping the build configuration path segment - /// (Debug, Release, Checked) in the path. Returns the first match, or the original - /// path if no fallback exists. - /// - private string ProbeConfigFallback(string dir) - { - if (Directory.Exists(dir)) - return dir; + private static string Crossgen2ExeName => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "crossgen2.exe" : "crossgen2"; - foreach (string fallbackConfig in new[] { "Release", "Checked", "Debug" }) - { - string fallback = Regex.Replace( - dir, @"(?<=[/\\])(Debug|Release|Checked)(?=[/\\])", fallbackConfig); - if (fallback != dir && Directory.Exists(fallback)) - { - _output.WriteLine($"[TestPaths] '{dir}' not found; falling back to '{fallback}'"); - return fallback; - } - } + public static string SystemPrivateCoreLibPath => Path.Combine(LibrariesDir, "System.Private.CoreLib.dll"); - return dir; - } + public static string TargetOS => GetRequiredConfig("R2RTest.TargetOS"); + public static string TargetArchitecture => GetRequiredConfig("R2RTest.TargetArchitecture"); - /// - /// Like but for paths where the configuration name - /// is embedded in a dot-delimited segment (e.g. linux.x64.Checked). - /// - private string ProbeDottedConfigFallback(string dir) - { - if (Directory.Exists(dir)) - return dir; + private static string TargetRid => $"{TargetOS}-{TargetArchitecture}"; - foreach (string fallbackConfig in new[] { "Checked", "Release", "Debug" }) - { - string fallback = Regex.Replace( - dir, @"\.(Debug|Release|Checked)([/\\])", $".{fallbackConfig}$2"); - if (fallback != dir && Directory.Exists(fallback)) - { - _output.WriteLine($"[TestPaths] '{dir}' not found; falling back to '{fallback}'"); - return fallback; - } - } + public static bool IsWasmTarget => TargetArchitecture == "wasm"; - return dir; - } + public static bool IsNotWasmTarget => !IsWasmTarget; - /// - /// Path to the crossgen2 output directory (contains the self-contained crossgen2 executable and clrjit). - /// e.g. artifacts/bin/coreclr/linux.x64.Checked/x64/crossgen2/ - /// Falls back to Checked or Release if the configured path doesn't exist. - /// - public string Crossgen2Dir - { - get - { - string dir = GetRequiredConfig("R2RTest.Crossgen2Dir"); - if (!File.Exists(Path.Combine(dir, Crossgen2ExeName))) - { - string fallback = ProbeDottedConfigFallback(dir); - if (File.Exists(Path.Combine(fallback, Crossgen2ExeName))) - return fallback; - } + public static bool IsArmTarget => TargetArchitecture is "arm" or "armel"; - return dir; - } - } + public static bool IsWindowsTarget => TargetOS is "windows" or "win"; - private static string Crossgen2ExeName => - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "crossgen2.exe" : "crossgen2"; + public static bool IsIosArm64Target => TargetOS is "ios" && TargetArchitecture is "arm64"; - /// - /// Path to the self-contained crossgen2 executable (from crossgen2_inbuild). - /// - public string Crossgen2Exe => Path.Combine(Crossgen2Dir, Crossgen2ExeName); + public static bool IsWindowsHost => OperatingSystem.IsWindows(); /// - /// Path to the runtime pack managed assemblies directory. - /// e.g. artifacts/bin/microsoft.netcore.app.runtime.linux-x64/Release/runtimes/linux-x64/lib/net11.0/ - /// Falls back to a different build configuration if the path doesn't exist. + /// Path to the crossgen2 that compiles for this build's target. /// - public string RuntimePackDir + public static string Crossgen2Exe { get { - string dir = GetRequiredConfig("R2RTest.RuntimePackDir"); - return ProbeConfigFallback(dir); - } - } - - /// - /// Path to the runtime pack native directory (contains System.Private.CoreLib.dll and native runtime). - /// e.g. artifacts/bin/microsoft.netcore.app.runtime.linux-x64/Release/runtimes/linux-x64/native/ - /// Falls back to a different build configuration if the path doesn't exist. - /// - public string RuntimePackNativeDir - { - get - { - string dir = GetRequiredConfig("R2RTest.RuntimePackNativeDir"); - return ProbeConfigFallback(dir); - } - } - - /// - /// Path to System.Private.CoreLib.dll. It lives in the runtime pack native/ dir in full builds - /// (placed by externals.csproj BinPlace during libs.pretest), but partial builds that skip - /// libs.pretest only have it in the CoreCLR artifacts directory. - /// - public string SystemPrivateCoreLibPath - { - get - { - string path = Path.Combine(RuntimePackNativeDir, "System.Private.CoreLib.dll"); - if (!File.Exists(path)) + string exe = Path.Combine(AppContext.BaseDirectory, "crossgen2", Crossgen2ExeName); + if (!File.Exists(exe)) { - string fallback = Path.Combine(CoreCLRArtifactsDir, "System.Private.CoreLib.dll"); - if (File.Exists(fallback)) - { - _output.WriteLine($"[TestPaths] '{path}' not found; falling back to '{fallback}'"); - return fallback; - } + throw new FileNotFoundException( + $"No crossgen2 staged for {TargetRid} at '{exe}'. Build the clr and libs subsets for " + + $"{TargetRid}, then rebuild this test project."); } - return path; - } - } - - /// - /// Path to the CoreCLR artifacts directory (contains native bits like corerun). - /// e.g. artifacts/bin/coreclr/linux.x64.Checked/ - /// Falls back to Checked or Release if the configured path doesn't exist. - /// - public string CoreCLRArtifactsDir - { - get - { - string dir = GetRequiredConfig("R2RTest.CoreCLRArtifactsDir"); - return ProbeDottedConfigFallback(dir); + return exe; } } - public static string TargetArchitecture => GetRequiredConfig("R2RTest.TargetArchitecture"); - public static string TargetOS => GetRequiredConfig("R2RTest.TargetOS"); - public static string CoreCLRConfiguration => GetRequiredConfig("R2RTest.CoreCLRConfiguration"); - public static bool IsReleaseCoreCLR => string.Equals(CoreCLRConfiguration, "Release", StringComparison.OrdinalIgnoreCase); - public static bool IsNotReleaseCoreCLR => !IsReleaseCoreCLR; - /// - /// Path to the reference assembly pack (for Roslyn compilation). - /// e.g. artifacts/bin/microsoft.netcore.app.ref/ref/net11.0/ + /// Directory holding the shared framework IL assemblies crossgen2 compiles against. /// - public string RefPackDir + public static string LibrariesDir { get { - string dir = GetRequiredConfig("R2RTest.RefPackDir"); + string dir = Path.Combine(AppContext.BaseDirectory, "libraries"); if (!Directory.Exists(dir)) { - // Try the artifacts/bin/ref/net* fallback - string artifactsBin = Path.GetFullPath(Path.Combine(CoreCLRArtifactsDir, "..", "..")); - string refDir = Path.Combine(artifactsBin, "ref"); - if (Directory.Exists(refDir)) - { - foreach (string subDir in Directory.GetDirectories(refDir, "net*")) - { - if (File.Exists(Path.Combine(subDir, "System.Runtime.dll"))) - { - _output.WriteLine($"[TestPaths] '{dir}' not found; falling back to '{subDir}'"); - return subDir; - } - } - } + throw new DirectoryNotFoundException( + $"No shared framework assemblies staged for {TargetRid} at '{dir}'. Build the clr and " + + $"libs subsets for {TargetRid}, then rebuild this test project."); } return dir; } } - /// - /// Returns the target triple string for crossgen2 (e.g. "linux-x64"). - /// - public static string TargetTriple => $"{TargetOS.ToLowerInvariant()}-{TargetArchitecture.ToLowerInvariant()}"; - - /// - /// Returns all framework reference assembly paths (*.dll in the runtime pack). - /// - public IEnumerable GetFrameworkReferencePaths() - { - if (!Directory.Exists(RuntimePackDir)) - throw new DirectoryNotFoundException($"Runtime pack directory not found: {RuntimePackDir}"); - - return Directory.EnumerateFiles(RuntimePackDir, "*.dll"); - } + public static string CoreCLRConfiguration => GetRequiredConfig("R2RTest.CoreCLRConfiguration"); + public static bool IsReleaseCoreCLR => string.Equals(CoreCLRConfiguration, "Release", StringComparison.OrdinalIgnoreCase); + public static bool IsNotReleaseCoreCLR => !IsReleaseCoreCLR; } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/WasmArgumentLayoutTests.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/WasmArgumentLayoutTests.cs index 2629202df34758..ec327918b2f1ef 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/WasmArgumentLayoutTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun.Tests/WasmArgumentLayoutTests.cs @@ -26,8 +26,12 @@ namespace ILCompiler.ReadyToRun.Tests; /// /// Unit tests for the wasm argument layout crossgen2 computes. These drive the compiler's type -/// system directly, so they need neither a wasm JIT nor a runtime to execute against. +/// system directly, so they need neither a wasm JIT nor a runtime to execute against. They do +/// need a wasm System.Private.CoreLib, though: the type system context they build is always a +/// wasm one, but the corelib it reads comes from whatever the outer build targets, so on any +/// other target they would be computing wasm layouts from the wrong assembly. /// +[ConditionalClass(typeof(TestPaths), nameof(TestPaths.IsWasmTarget))] public class WasmArgumentLayoutTests { private const string Vector128OfT = "Vector128`1"; @@ -548,7 +552,7 @@ private static MethodSignature MakeProbeSignature(ReadyToRunCompilerContext cont /// private ReadyToRunCompilerContext CreateWasmContext() { - string coreLibPath = new TestPaths(_output).SystemPrivateCoreLibPath; + string coreLibPath = TestPaths.SystemPrivateCoreLibPath; Assert.True(File.Exists(coreLibPath), $"System.Private.CoreLib.dll not found at '{coreLibPath}'"); InstructionSetSupport instructionSetSupport = new(default, default, TargetArchitecture.Wasm32);