diff --git a/NuGet.config b/NuGet.config index 0dff023e179ae..961d774f91d77 100644 --- a/NuGet.config +++ b/NuGet.config @@ -10,6 +10,16 @@ + + + + + + + + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b02016197ce7b..8c6dbdb2bf4f9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -99,14 +99,14 @@ 2674f580a4b1d27322914df8488498065e71a3f2 - + https://github.com/dotnet/source-build-reference-packages - 6ed73280a6d70f7e7ac39c86f2abe8c10983f0bb + 30ed464acd37779c64e9dc652d4460543ebf9966 - + https://github.com/dotnet/source-build-externals - 4f2151df120194f0268944f1b723c14820738fc8 + fb970eccb0a9cae3092464e29cbabda0d4115049 @@ -185,57 +185,57 @@ https://github.com/dotnet/arcade c9efa535175049eb9cba06cae1f8c3d5dbe768a9 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 https://github.com/dotnet/llvm-project @@ -354,13 +354,13 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 67613417f5e1af250e6ddfba79f8f2885d8e90fb - + https://github.com/dotnet/hotreload-utils - 9fd9805b21b21e16d1c81f0ffabd6ee81fe3e8a2 + 907017dae648b642c122f9a34573bd88ea0d9730 - + https://github.com/dotnet/runtime-assets - 20ef600733c107d19f57de4955dfb025d39b99e3 + 50994571d2f8b4b689c7a0b96c96356fc444b406 https://github.com/dotnet/roslyn diff --git a/eng/Versions.props b/eng/Versions.props index c8639af14c99a..195b4176144e2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -145,20 +145,20 @@ 4.5.0 8.0.0-rc.1.23406.6 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 - 8.0.0-beta.24270.1 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 + 8.0.0-beta.24362.2 1.0.0-prerelease.23566.3 1.0.0-prerelease.23566.3 @@ -188,7 +188,7 @@ 8.0.0-prerelease.24229.2 8.0.0-prerelease.24229.2 8.0.0-prerelease.24229.2 - 8.0.0-alpha.0.24365.1 + 8.0.0-alpha.0.24402.1 2.4.2 1.0.0 2.4.5 diff --git a/eng/pipelines/coreclr/templates/helix-queues-setup.yml b/eng/pipelines/coreclr/templates/helix-queues-setup.yml index 378396bc323a3..8f1d99396b463 100644 --- a/eng/pipelines/coreclr/templates/helix-queues-setup.yml +++ b/eng/pipelines/coreclr/templates/helix-queues-setup.yml @@ -48,7 +48,7 @@ jobs: # Android x64 - ${{ if in(parameters.platform, 'android_x64') }}: - - Ubuntu.1804.Amd64.Android.29.Open + - Ubuntu.2004.Amd64.Android.29.Open # Browser wasm - ${{ if eq(parameters.platform, 'browser_wasm') }}: @@ -74,28 +74,28 @@ jobs: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - (Ubuntu.2204.Arm64.Open)Ubuntu.2204.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8 - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - (Ubuntu.1804.Arm64)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-arm64v8 + - (Ubuntu.2204.Arm64)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8 # Linux musl x64 - ${{ if eq(parameters.platform, 'linux_musl_x64') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - (Alpine.317.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.17-helix-amd64 + - (Alpine.318.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.18-helix-amd64 - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - (Alpine.319.Amd64)Ubuntu.2204.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.19-helix-amd64 + - (Alpine.318.Amd64)Ubuntu.2204.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.18-helix-amd64 # Linux musl arm32 - ${{ if eq(parameters.platform, 'linux_musl_arm') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - (Alpine.317.Arm32.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.17-helix-arm32v7 + - (Alpine.318.Arm32.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.18-helix-arm32v7 - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - (Alpine.319.Arm32)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.19-helix-arm32v7 + - (Alpine.318.Arm32)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.18-helix-arm32v7 # Linux musl arm64 - ${{ if eq(parameters.platform, 'linux_musl_arm64') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - (Alpine.317.Arm64.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.17-helix-arm64v8 + - (Alpine.318.Arm64.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.18-helix-arm64v8 - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - (Alpine.319.Arm64)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.19-helix-arm64v8 + - (Alpine.318.Arm64)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.18-helix-arm64v8 # Linux x64 - ${{ if eq(parameters.platform, 'linux_x64') }}: diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-other.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-other.yml index e2e95c6bac573..d394fc8287107 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-other.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-other.yml @@ -93,7 +93,7 @@ jobs: testGroup: innerloop isSingleFile: true nameSuffix: NativeAOT_Libs - buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) /p:TestNativeAot=true /p:ArchiveTests=true + buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) /p:TestNativeAot=true /p:ArchiveTests=true /p:IlcUseServerGc=false timeoutInMinutes: 300 # doesn't normally take this long, but I've seen Helix queues backed up for 160 minutes # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml @@ -122,7 +122,7 @@ jobs: testGroup: innerloop isSingleFile: true nameSuffix: NativeAOT_Checked_Libs - buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true + buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true /p:IlcUseServerGc=false timeoutInMinutes: 360 # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml @@ -151,7 +151,7 @@ jobs: testGroup: innerloop isSingleFile: true nameSuffix: NativeAOT_Checked_Libs_SizeOpt - buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true /p:OptimizationPreference=Size + buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true /p:OptimizationPreference=Size /p:IlcUseServerGc=false timeoutInMinutes: 240 # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml @@ -180,7 +180,7 @@ jobs: testGroup: innerloop isSingleFile: true nameSuffix: NativeAOT_Checked_Libs_SpeedOpt - buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true /p:OptimizationPreference=Speed + buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true /p:OptimizationPreference=Speed /p:IlcUseServerGc=false timeoutInMinutes: 240 # extra steps, run tests extraStepsTemplate: /eng/pipelines/libraries/helix.yml diff --git a/eng/pipelines/libraries/enterprise/linux.yml b/eng/pipelines/libraries/enterprise/linux.yml index ccfda9fcaebe4..40552c1a0e18f 100644 --- a/eng/pipelines/libraries/enterprise/linux.yml +++ b/eng/pipelines/libraries/enterprise/linux.yml @@ -39,7 +39,7 @@ extends: timeoutInMinutes: 120 pool: name: $(DncEngPublicBuildPool) - demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open + demands: ImageOverride -equals Build.Ubuntu.2204.Amd64.Open steps: - bash: | cd $(enterpriseTestsSetup) diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index d3d7e7b2e64f8..dcfa5a119db38 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -28,7 +28,7 @@ jobs: # Linux arm - ${{ if eq(parameters.platform, 'linux_arm') }}: - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Debian.11.Arm32.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-arm32v7 + - (Debian.12.Arm32.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-arm32v7 # Linux armv6 - ${{ if eq(parameters.platform, 'linux_armv6') }}: @@ -42,18 +42,18 @@ jobs: - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - (Ubuntu.1804.Arm64.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-arm64v8 - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Debian.11.Arm64.Open)Ubuntu.2204.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-arm64v8 + - (Debian.12.Arm64.Open)Ubuntu.2204.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-arm64v8 # Linux musl x64 - ${{ if eq(parameters.platform, 'linux_musl_x64') }}: - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Alpine.317.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.17-helix-amd64 + - (Alpine.318.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.18-helix-amd64 - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Alpine.319.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.19-helix-amd64 + - (Alpine.318.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.18-helix-amd64 # Linux musl arm64 - ${{ if and(eq(parameters.platform, 'linux_musl_arm64'), or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true))) }}: - - (Alpine.317.Arm64.Open)ubuntu.2204.armarch.open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.17-helix-arm64v8 + - (Alpine.318.Arm64.Open)ubuntu.2204.armarch.open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.18-helix-arm64v8 - (Alpine.319.Arm64.Open)ubuntu.2204.armarch.open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.19-helix-arm64v8 # Linux x64 @@ -64,22 +64,22 @@ jobs: - (Centos.9.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9-helix - (Fedora.39.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-39-helix - (Ubuntu.2204.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-amd64 - - (Debian.11.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-amd64 + - (Debian.12.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 - ${{ if or(ne(parameters.jobParameters.testScope, 'outerloop'), ne(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - SLES.15.Amd64.Open - (Fedora.39.Amd64.Open)Ubuntu.2204.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-39-helix - Ubuntu.2204.Amd64.Open - - (Debian.11.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-amd64 + - (Debian.12.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 - (Mariner.2.0.Amd64.Open)Ubuntu.2204.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-helix-amd64 - (openSUSE.15.2.Amd64.Open)Ubuntu.2204.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:opensuse-15.2-helix-amd64 - ${{ if or(ne(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - (Centos.9.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9-helix - - (Debian.11.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-amd64 - - Ubuntu.1804.Amd64.Open + - (Debian.12.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 + - Ubuntu.2004.Amd64.Open - ${{ if or(eq(parameters.jobParameters.interpreter, 'true'), eq(parameters.jobParameters.isSingleFile, true)) }}: # Limiting interp runs as we don't need as much coverage. - - (Debian.11.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-amd64 + - (Debian.12.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 # Linux s390x - ${{ if eq(parameters.platform, 'linux_s390x') }}: @@ -99,7 +99,7 @@ jobs: # Android - ${{ if in(parameters.platform, 'android_x86', 'android_x64', 'linux_bionic_x64') }}: - - Ubuntu.1804.Amd64.Android.29.Open + - Ubuntu.2004.Amd64.Android.29.Open - ${{ if in(parameters.platform, 'android_arm', 'android_arm64', 'linux_bionic_arm64') }}: - Windows.11.Amd64.Android.Open @@ -175,11 +175,11 @@ jobs: # Browser WebAssembly - ${{ if eq(parameters.platform, 'browser_wasm') }}: - - (Ubuntu.1804.Amd64)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-webassembly + - (Ubuntu.2204.Amd64)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly # Browser WebAssembly Firefox - ${{ if eq(parameters.platform, 'browser_wasm_firefox') }}: - - (Ubuntu.1804.Amd64)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-webassembly + - (Ubuntu.2204.Amd64)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly # Browser WebAssembly windows - ${{ if in(parameters.platform, 'browser_wasm_win', 'wasi_wasm_win') }}: diff --git a/eng/pipelines/libraries/stress/http.yml b/eng/pipelines/libraries/stress/http.yml index 68bfcef6c5081..f29a41fcd0a7e 100644 --- a/eng/pipelines/libraries/stress/http.yml +++ b/eng/pipelines/libraries/stress/http.yml @@ -38,7 +38,7 @@ extends: DUMPS_SHARE_MOUNT_ROOT: "/dumps-share" pool: name: $(DncEngPublicBuildPool) - demands: ImageOverride -equals 1es-ubuntu-1804-open + demands: ImageOverride -equals 1es-ubuntu-2204-open steps: - checkout: self diff --git a/eng/pipelines/libraries/stress/ssl.yml b/eng/pipelines/libraries/stress/ssl.yml index a70a18e828f04..1e8cddf228bcb 100644 --- a/eng/pipelines/libraries/stress/ssl.yml +++ b/eng/pipelines/libraries/stress/ssl.yml @@ -37,7 +37,7 @@ extends: timeoutInMinutes: 120 pool: name: $(DncEngPublicBuildPool) - demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open + demands: ImageOverride -equals Build.Ubuntu.2204.Amd64.Open steps: - checkout: self diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml index 7cadf6a800f67..eb3d2c79eb7e6 100644 --- a/eng/pipelines/runtime-official.yml +++ b/eng/pipelines/runtime-official.yml @@ -442,9 +442,9 @@ extends: buildConfig: release platforms: - linux_x64 - - linux_musl_x64 + # - linux_musl_x64 - linux_arm64 - - linux_musl_arm64 + # - linux_musl_arm64 jobParameters: templatePath: 'templates-official' buildArgs: -s mono+packs -c $(_BuildConfig) diff --git a/eng/testing/scenarios/BuildWasmAppsJobsList.txt b/eng/testing/scenarios/BuildWasmAppsJobsList.txt index e16c74fe4f075..9bb06b872bb6c 100644 --- a/eng/testing/scenarios/BuildWasmAppsJobsList.txt +++ b/eng/testing/scenarios/BuildWasmAppsJobsList.txt @@ -43,3 +43,5 @@ Wasm.Build.Tests.WasmTemplateTests Wasm.Build.Tests.WorkloadTests Wasm.Build.Tests.TestAppScenarios.ModuleConfigTests Wasm.Build.Tests.MT.Blazor.SimpleMultiThreadedTests +Wasm.Build.Tests.TestAppScenarios.WasmSdkDebugLevelTests +Wasm.Build.Tests.TestAppScenarios.WasmAppBuilderDebugLevelTests diff --git a/eng/testing/tests.wasm.targets b/eng/testing/tests.wasm.targets index 4dc6b71005449..9e0fdaf3289e6 100644 --- a/eng/testing/tests.wasm.targets +++ b/eng/testing/tests.wasm.targets @@ -15,10 +15,7 @@ But we do want to set it for Configuration=Debug . --> -1 - - reset-to-zero + 0 full true diff --git a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/InMemoryAssemblyLoader.cs b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/InMemoryAssemblyLoader.cs index dc8d8ccb4c7cc..55e4227481724 100644 --- a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/InMemoryAssemblyLoader.cs +++ b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/InMemoryAssemblyLoader.cs @@ -49,7 +49,7 @@ private static unsafe void LoadInMemoryAssemblyInContextWhenSupported(IntPtr mod /// /// The native module handle for the assembly. /// The path to the assembly (as a pointer to a UTF-16 C string). - /// Load context (currently must be IntPtr.Zero) + /// Load context (currently must be either IntPtr.Zero for default ALC or -1 for isolated ALC) [UnmanagedCallersOnly] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "The same C++/CLI feature switch applies to LoadInMemoryAssembly and this function. We rely on the warning from LoadInMemoryAssembly.")] @@ -58,9 +58,12 @@ public static unsafe void LoadInMemoryAssemblyInContext(IntPtr moduleHandle, Int if (!IsSupported) throw new NotSupportedException(SR.NotSupported_CppCli); - ArgumentOutOfRangeException.ThrowIfNotEqual(loadContext, IntPtr.Zero); + if ((loadContext != IntPtr.Zero) && (loadContext != -1)) + { + throw new ArgumentOutOfRangeException(nameof(loadContext)); + } - LoadInMemoryAssemblyInContextImpl(moduleHandle, assemblyPath, AssemblyLoadContext.Default); + LoadInMemoryAssemblyInContextImpl(moduleHandle, assemblyPath, (loadContext == IntPtr.Zero) ? AssemblyLoadContext.Default : null); } [RequiresUnreferencedCode("C++/CLI is not trim-compatible", Url = "https://aka.ms/dotnet-illink/nativehost")] diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index 1cf604da8a87b..81229e9cdab86 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -21595,10 +21595,13 @@ int gc_heap::generation_to_condemn (int n_initial, } #ifdef USE_REGIONS - if (!try_get_new_free_region()) + if (!check_only_p) { - dprintf (GTC_LOG, ("can't get an empty region -> full compacting")); - last_gc_before_oom = TRUE; + if (!try_get_new_free_region()) + { + dprintf (GTC_LOG, ("can't get an empty region -> full compacting")); + last_gc_before_oom = TRUE; + } } #endif //USE_REGIONS diff --git a/src/coreclr/hosts/corerun/corerun.cpp b/src/coreclr/hosts/corerun/corerun.cpp index 4e506b95c9746..858f72297f6bd 100644 --- a/src/coreclr/hosts/corerun/corerun.cpp +++ b/src/coreclr/hosts/corerun/corerun.cpp @@ -472,6 +472,7 @@ static void display_usage() W(" -p, --property - Property to pass to runtime during initialization.\n") W(" If a property value contains spaces, quote the entire argument.\n") W(" May be supplied multiple times. Format: =.\n") + W(" -l, --preload - path to shared library to load before loading the CLR.\n") W(" -d, --debug - causes corerun to wait for a debugger to attach before executing.\n") W(" -e, --env - path to a .env file with environment variables that corerun should set.\n") W(" -?, -h, --help - show this help.\n") @@ -569,6 +570,22 @@ static bool parse_args( config.user_defined_keys.push_back(std::move(key)); config.user_defined_values.push_back(std::move(value)); } + else if (pal::strcmp(option, W("l")) == 0 || (pal::strcmp(option, W("preload")) == 0)) + { + i++; + if (i >= argc) + { + pal::fprintf(stderr, W("Option %s: missing shared library path\n"), arg); + break; + } + + string_t library = argv[i]; + pal::mod_t hMod; + if (!pal::try_load_library(library, hMod)) + { + break; + } + } else if (pal::strcmp(option, W("d")) == 0 || (pal::strcmp(option, W("debug")) == 0)) { config.wait_to_debug = true; diff --git a/src/coreclr/hosts/corerun/corerun.hpp b/src/coreclr/hosts/corerun/corerun.hpp index f0e51a668fe22..567d7b9dc5062 100644 --- a/src/coreclr/hosts/corerun/corerun.hpp +++ b/src/coreclr/hosts/corerun/corerun.hpp @@ -224,6 +224,17 @@ namespace pal return hMod != nullptr; } + inline bool try_load_library(const pal::string_t& path, pal::mod_t& hMod) + { + hMod = (pal::mod_t)::LoadLibraryExW(path.c_str(), nullptr, 0); + if (hMod == nullptr) + { + pal::fprintf(stderr, W("Failed to load: '%s'. Error: 0x%08x\n"), path.c_str(), ::GetLastError()); + return false; + } + return true; + } + inline bool try_load_coreclr(const pal::string_t& core_root, pal::mod_t& hMod) { pal::string_t coreclr_path = core_root; @@ -602,6 +613,18 @@ namespace pal return hMod != nullptr; } + inline bool try_load_library(const pal::string_t& path, pal::mod_t& hMod) + { + hMod = (pal::mod_t)dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); + if (hMod == nullptr) + { + pal::fprintf(stderr, W("Failed to load: '%s'. Error: %s\n"), path.c_str(), dlerror()); + return false; + } + return true; + } + + inline bool try_load_coreclr(const pal::string_t& core_root, pal::mod_t& hMod) { pal::string_t coreclr_path = core_root; diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index 7b356b0744399..13962a2060905 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -342,6 +342,8 @@ CONFIG_STRING_INFO(INTERNAL_TailCallMax, W("TailCallMax"), "") RETAIL_CONFIG_STRING_INFO(EXTERNAL_TailCallOpt, W("TailCallOpt"), "") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TailCallLoopOpt, W("TailCallLoopOpt"), 1, "Convert recursive tail calls to loops") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Jit_NetFx40PInvokeStackResilience, W("NetFx40_PInvokeStackResilience"), (DWORD)-1, "Makes P/Invoke resilient against mismatched signature and calling convention (significant perf penalty).") +RETAIL_CONFIG_DWORD_INFO(EXTERNAL_DisableOptimizedThreadStaticAccess, W("DisableOptimizedThreadStaticAccess"), (DWORD)0, "Disable the OptimizedThreadStaticAccess feature.") +CONFIG_DWORD_INFO(EXTERNAL_AssertNotStaticTlsResolver, W("AssertNotStaticTlsResolver"), (DWORD)0, "Assert if we attempt to use the static tls resolver path.") // AltJitAssertOnNYI should be 0 on targets where JIT is under development or bring up stage, so as to facilitate fallback to main JIT on hitting a NYI. #if defined(TARGET_X86) diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index dad1df9ffcfb7..8f3150e7e7b18 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -8292,7 +8292,7 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* parentNode, GenTre return false; } - return parentNode->OperIsEmbBroadcastCompatible(); + return parentNode->OperIsEmbBroadcastCompatible() && comp->canUseEvexEncoding(); } default: diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index 89dab80461c35..f766b9691278e 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -1035,4 +1035,18 @@ LEAF_ENTRY GetThreadStaticsVariableOffset, _TEXT EPILOG_RETURN LEAF_END GetThreadStaticsVariableOffset, _TEXT // ------------------------------------------------------------------ + +// ------------------------------------------------------------------ +// size_t GetTLSResolverAddress() + +// Helper to get the TLS resolver address. This will be then used to determine if we have a static or dynamic resolver. +LEAF_ENTRY GetTLSResolverAddress, _TEXT + PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -32 + adrp x0, :tlsdesc:t_ThreadStatics + ldr x1, [x0, #:tlsdesc_lo12:t_ThreadStatics] + mov x0, x1 + EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 32 + EPILOG_RETURN +LEAF_END GetTLSResolverAddress, _TEXT +// ------------------------------------------------------------------ #endif // !TARGET_OSX diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 31c4467b7982a..a8f23fcb2ac49 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -2268,15 +2268,7 @@ DWORD NDirectStubLinker::EmitProfilerBeginTransitionCallback(ILCodeStream* pcsEm EmitLoadStubContext(pcsEmit, dwStubFlags); } - if (SF_IsForwardStub(dwStubFlags)) - { - pcsEmit->EmitLDLOC(GetThreadLocalNum()); - } - else - { - // we use a null pThread to indicate reverse interop - pcsEmit->EmitLoadNullPtr(); - } + pcsEmit->EmitLDLOC(GetThreadLocalNum()); // In the unmanaged delegate case, we need the "this" object to retrieve the MD // in StubHelpers::ProfilerEnterCallback(). diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index 0f1de4d4fe788..37a89224617ce 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -112,6 +112,7 @@ HRESULT EEConfig::Init() fJitFramed = false; fJitMinOpts = false; fJitEnableOptionalRelocs = false; + fDisableOptimizedThreadStaticAccess = false; fPInvokeRestoreEsp = (DWORD)-1; fNgenBindOptimizeNonGac = false; @@ -548,6 +549,8 @@ HRESULT EEConfig::sync() iJitOptimizeType = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitOptimizeType); if (iJitOptimizeType > OPT_RANDOM) iJitOptimizeType = OPT_DEFAULT; + fDisableOptimizedThreadStaticAccess = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DisableOptimizedThreadStaticAccess) != 0; + #ifdef TARGET_X86 fPInvokeRestoreEsp = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Jit_NetFx40PInvokeStackResilience); #endif diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h index 6394f1b998c0f..3614e54320295 100644 --- a/src/coreclr/vm/eeconfig.h +++ b/src/coreclr/vm/eeconfig.h @@ -77,6 +77,7 @@ class EEConfig bool JitFramed(void) const {LIMITED_METHOD_CONTRACT; return fJitFramed; } bool JitMinOpts(void) const {LIMITED_METHOD_CONTRACT; return fJitMinOpts; } bool JitEnableOptionalRelocs(void) const {LIMITED_METHOD_CONTRACT; return fJitEnableOptionalRelocs; } + bool DisableOptimizedThreadStaticAccess(void) const {LIMITED_METHOD_CONTRACT; return fDisableOptimizedThreadStaticAccess; } // Tiered Compilation config #if defined(FEATURE_TIERED_COMPILATION) @@ -480,6 +481,7 @@ class EEConfig bool fJitFramed; // Enable/Disable EBP based frames bool fJitMinOpts; // Enable MinOpts for all jitted methods bool fJitEnableOptionalRelocs; // Allow optional relocs + bool fDisableOptimizedThreadStaticAccess; // Disable OptimizedThreadStatic access unsigned iJitOptimizeType; // 0=Blended,1=SmallCode,2=FastCode, default is 0=Blended diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index 9fe9376fd58ef..6d8e3a426bbaa 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -5336,6 +5336,10 @@ DefaultCatchHandler(PEXCEPTION_POINTERS pExceptionPointers, FlushLogging(); // Flush any logging output GCPROTECT_END(); +#ifdef HOST_WINDOWS + CreateCrashDumpIfEnabled(); +#endif + #ifdef _DEBUG // Do not care about lock check for unhandled exception. while (unbreakableLockCount) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 67e127bf91ea6..01ab9aae94463 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1463,6 +1463,10 @@ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* EE_TO_JIT_TRANSITION_LEAF(); } +#if !defined(TARGET_OSX) && defined(TARGET_UNIX) && defined(TARGET_ARM64) +extern "C" size_t GetTLSResolverAddress(); +#endif // !TARGET_OSX && TARGET_UNIX && TARGET_ARM64 + /*********************************************************************/ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, @@ -1567,14 +1571,46 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; pResult->helper = getSharedStaticsHelper(pField, pFieldMT); + + bool optimizeThreadStaticAccess = false; #if defined(TARGET_ARM) // Optimization is disabled for linux/windows arm #elif !defined(TARGET_WINDOWS) && defined(TARGET_X86) // Optimization is disabled for linux/x86 #elif defined(TARGET_LINUX_MUSL) && defined(TARGET_ARM64) // Optimization is disabled for linux musl arm64 +#elif !defined(TARGET_OSX) && defined(TARGET_UNIX) && defined(TARGET_ARM64) + // Optimization is enabled for linux/arm64 only for static resolver. + // For static resolver, the TP offset is same for all threads. + // For dynamic resolver, TP offset returned is for the current thread and + // will be different for the other threads. + uint32_t* resolverAddress = reinterpret_cast(GetTLSResolverAddress()); + int ip = 0; + if ((resolverAddress[ip] == 0xd503201f) || (resolverAddress[ip] == 0xd503241f)) + { + // nop might not be present in older resolver, so skip it. + + // nop or hint 32 + ip++; + } + + if ( + // ldr x0, [x0, #8] + (resolverAddress[ip] == 0xf9400400) && + // ret + (resolverAddress[ip + 1] == 0xd65f03c0) + ) + { + optimizeThreadStaticAccess = true; +#ifdef _DEBUG + if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_AssertNotStaticTlsResolver) != 0) + { + _ASSERTE(!"Detected static resolver in use when not expected"); + } +#endif + } #else - bool optimizeThreadStaticAccess = true; + optimizeThreadStaticAccess = true; #if !defined(TARGET_OSX) && defined(TARGET_UNIX) && defined(TARGET_AMD64) // For linux/x64, check if compiled coreclr as .so file and not single file. // For single file, the `tls_index` might not be accurate. @@ -1582,6 +1618,11 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, optimizeThreadStaticAccess = GetTlsIndexObjectAddress() != nullptr; #endif // !TARGET_OSX && TARGET_UNIX && TARGET_AMD64 + if (g_pConfig->DisableOptimizedThreadStaticAccess()) + { + optimizeThreadStaticAccess = false; + } + if (optimizeThreadStaticAccess) { // For windows x64/x86/arm64, linux x64/arm64/loongarch64/riscv64: @@ -3898,8 +3939,18 @@ uint32_t CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd) if (pMT->IsByRefLike()) ret |= CORINFO_FLG_BYREF_LIKE; - if (pClass->IsUnsafeValueClass()) + // In Reverse P/Invoke stubs, we are generating the code + // and we are not generating the code patterns that the GS checks + // are meant to catch. + // As a result, we can skip setting this flag. + // We do this as the GS checks (emitted when this flag is set) + // can break C++/CLI's copy-constructor semantics by missing copies. + if (pClass->IsUnsafeValueClass() + && !(m_pMethodBeingCompiled->IsILStub() + && dac_cast(m_pMethodBeingCompiled)->GetILStubType() == DynamicMethodDesc::StubNativeToCLRInterop)) + { ret |= CORINFO_FLG_UNSAFE_VALUECLASS; + } } if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverlaidField()) ret |= CORINFO_FLG_OVERLAPPING_FIELDS; diff --git a/src/coreclr/vm/readytoruninfo.cpp b/src/coreclr/vm/readytoruninfo.cpp index e75373db8855a..fbf49abe88a8e 100644 --- a/src/coreclr/vm/readytoruninfo.cpp +++ b/src/coreclr/vm/readytoruninfo.cpp @@ -1945,7 +1945,7 @@ bool ReadyToRun_TypeGenericInfoMap::HasVariance(mdTypeDef input, bool *foundResu bool ReadyToRun_TypeGenericInfoMap::HasConstraints(mdTypeDef input, bool *foundResult) const { ReadyToRunTypeGenericInfo typeGenericInfo = GetTypeGenericInfo(input, foundResult); - return !!((uint8_t)typeGenericInfo & (uint8_t)ReadyToRunTypeGenericInfo::HasVariance); + return !!((uint8_t)typeGenericInfo & (uint8_t)ReadyToRunTypeGenericInfo::HasConstraints); } bool ReadyToRun_MethodIsGenericMap::IsGeneric(mdMethodDef input, bool *foundResult) const diff --git a/src/coreclr/vm/stubhelpers.cpp b/src/coreclr/vm/stubhelpers.cpp index 9988a912967cf..2fa6aecb1c1fe 100644 --- a/src/coreclr/vm/stubhelpers.cpp +++ b/src/coreclr/vm/stubhelpers.cpp @@ -552,6 +552,7 @@ FCIMPL3(SIZE_T, StubHelpers::ProfilerBeginTransitionCallback, SIZE_T pSecretPara } { + _ASSERTE(pThread != nullptr); GCX_PREEMP_THREAD_EXISTS(pThread); ProfilerManagedToUnmanagedTransitionMD(pRealMD, COR_PRF_TRANSITION_CALL); @@ -582,6 +583,7 @@ FCIMPL2(void, StubHelpers::ProfilerEndTransitionCallback, MethodDesc* pRealMD, T // and the transition requires us to set up a HMF. HELPER_METHOD_FRAME_BEGIN_0(); { + _ASSERTE(pThread != nullptr); GCX_PREEMP_THREAD_EXISTS(pThread); ProfilerUnmanagedToManagedTransitionMD(pRealMD, COR_PRF_TRANSITION_RETURN); diff --git a/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-debian.proj b/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-debian.proj index be0713f05f750..f48ee38a1d78c 100644 --- a/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-debian.proj +++ b/src/installer/pkg/sfx/installers/dotnet-runtime-deps/dotnet-runtime-deps-debian.proj @@ -6,9 +6,9 @@ - + - \ No newline at end of file + diff --git a/src/installer/tests/HostActivation.Tests/NativeHosting/Ijwhost.cs b/src/installer/tests/HostActivation.Tests/NativeHosting/Ijwhost.cs index e7efe5eaafff8..062e6bcc58130 100644 --- a/src/installer/tests/HostActivation.Tests/NativeHosting/Ijwhost.cs +++ b/src/installer/tests/HostActivation.Tests/NativeHosting/Ijwhost.cs @@ -27,7 +27,7 @@ public void LoadLibrary() { string [] args = { "ijwhost", - sharedState.IjwLibraryPath, + sharedState.IjwApp.AppDll, "NativeEntryPoint" }; CommandResult result = sharedState.CreateNativeHostCommand(args, sharedState.RepoDirectories.BuiltDotnet) @@ -38,6 +38,41 @@ public void LoadLibrary() .And.HaveStdOutContaining("[C++/CLI] ManagedClass: AssemblyLoadContext = \"Default\" System.Runtime.Loader.DefaultAssemblyLoadContext"); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void LoadLibrary_ContextConfig(bool load_isolated) + { + // make a copy of a portion of the shared state because we will modify it + using (var app = sharedState.IjwApp.Copy()) + { + string[] args = { + "ijwhost", + app.AppDll, + "NativeEntryPoint" + }; + + RuntimeConfig.FromFile(app.RuntimeConfigJson) + .WithProperty("System.Runtime.InteropServices.CppCLI.LoadComponentInIsolatedContext", load_isolated.ToString()) + .Save(); + + CommandResult result = sharedState.CreateNativeHostCommand(args, sharedState.RepoDirectories.BuiltDotnet) + .Execute(); + + result.Should().Pass() + .And.HaveStdOutContaining("[C++/CLI] NativeEntryPoint: calling managed class"); + + if (load_isolated) // Assembly should be loaded in an isolated context + { + result.Should().HaveStdOutContaining("[C++/CLI] ManagedClass: AssemblyLoadContext = \"IsolatedComponentLoadContext"); + } + else // Assembly should be loaded in the default context + { + result.Should().HaveStdOutContaining("[C++/CLI] ManagedClass: AssemblyLoadContext = \"Default\" System.Runtime.Loader.DefaultAssemblyLoadContext"); + } + } + } + [Theory] [InlineData(true)] [InlineData(false)] @@ -45,7 +80,7 @@ public void ManagedHost(bool selfContained) { string [] args = { "ijwhost", - sharedState.IjwLibraryPath, + sharedState.IjwApp.AppDll, "NativeEntryPoint" }; TestProjectFixture fixture = selfContained ? sharedState.ManagedHostFixture_SelfContained : sharedState.ManagedHostFixture_FrameworkDependent; @@ -63,7 +98,7 @@ public void ManagedHost(bool selfContained) public class SharedTestState : SharedTestStateBase { - public string IjwLibraryPath { get; } + public TestApp IjwApp {get;} public TestProjectFixture ManagedHostFixture_FrameworkDependent { get; } public TestProjectFixture ManagedHostFixture_SelfContained { get; } @@ -71,7 +106,7 @@ public class SharedTestState : SharedTestStateBase public SharedTestState() { string folder = Path.Combine(BaseDirectory, "ijw"); - Directory.CreateDirectory(folder); + IjwApp = new TestApp(folder, "ijw"); // Copy over ijwhost string ijwhostName = "ijwhost.dll"; @@ -79,8 +114,7 @@ public SharedTestState() // Copy over the C++/CLI test library string ijwLibraryName = "ijw.dll"; - IjwLibraryPath = Path.Combine(folder, ijwLibraryName); - File.Copy(Path.Combine(RepoDirectories.HostTestArtifacts, ijwLibraryName), IjwLibraryPath); + File.Copy(Path.Combine(RepoDirectories.HostTestArtifacts, ijwLibraryName), Path.Combine(folder, ijwLibraryName)); // Create a runtimeconfig.json for the C++/CLI test library new RuntimeConfig(Path.Combine(folder, "ijw.runtimeconfig.json")) diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs index 77b80634bd0ce..4e8659b5653b7 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs @@ -217,7 +217,8 @@ internal static ArraySegment RentEncodeSubjectPublicKeyInfo(SafeEvpPKeyHan [LibraryImport(Libraries.CryptoNative, StringMarshalling = StringMarshalling.Utf8)] private static partial SafeEvpPKeyHandle CryptoNative_LoadPrivateKeyFromEngine( string engineName, - string keyName); + string keyName, + [MarshalAs(UnmanagedType.Bool)] out bool haveEngine); internal static SafeEvpPKeyHandle LoadPrivateKeyFromEngine( string engineName, @@ -226,7 +227,13 @@ internal static SafeEvpPKeyHandle LoadPrivateKeyFromEngine( Debug.Assert(engineName is not null); Debug.Assert(keyName is not null); - SafeEvpPKeyHandle pkey = CryptoNative_LoadPrivateKeyFromEngine(engineName, keyName); + SafeEvpPKeyHandle pkey = CryptoNative_LoadPrivateKeyFromEngine(engineName, keyName, out bool haveEngine); + + if (!haveEngine) + { + pkey.Dispose(); + throw new CryptographicException(SR.Cryptography_EnginesNotSupported); + } if (pkey.IsInvalid) { @@ -240,7 +247,8 @@ internal static SafeEvpPKeyHandle LoadPrivateKeyFromEngine( [LibraryImport(Libraries.CryptoNative, StringMarshalling = StringMarshalling.Utf8)] private static partial SafeEvpPKeyHandle CryptoNative_LoadPublicKeyFromEngine( string engineName, - string keyName); + string keyName, + [MarshalAs(UnmanagedType.Bool)] out bool haveEngine); internal static SafeEvpPKeyHandle LoadPublicKeyFromEngine( string engineName, @@ -249,7 +257,13 @@ internal static SafeEvpPKeyHandle LoadPublicKeyFromEngine( Debug.Assert(engineName is not null); Debug.Assert(keyName is not null); - SafeEvpPKeyHandle pkey = CryptoNative_LoadPublicKeyFromEngine(engineName, keyName); + SafeEvpPKeyHandle pkey = CryptoNative_LoadPublicKeyFromEngine(engineName, keyName, out bool haveEngine); + + if (!haveEngine) + { + pkey.Dispose(); + throw new CryptographicException(SR.Cryptography_EnginesNotSupported); + } if (pkey.IsInvalid) { diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs index 1b570872d06d9..6a166b298cd51 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Windows.cs @@ -25,6 +25,7 @@ public static partial class PlatformDetection public static bool IsWindows8xOrLater => IsWindowsVersionOrLater(6, 2); public static bool IsWindows10OrLater => IsWindowsVersionOrLater(10, 0); public static bool IsWindowsServer2019 => IsWindows && IsNotWindowsNanoServer && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildVersion() == 17763; + public static bool IsWindowsServer2022 => IsWindows && IsNotWindowsNanoServer && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildVersion() == 20348; public static bool IsWindowsNanoServer => IsWindows && (IsNotWindowsIoTCore && GetWindowsInstallationType().Equals("Nano Server", StringComparison.OrdinalIgnoreCase)); public static bool IsWindowsServerCore => IsWindows && GetWindowsInstallationType().Equals("Server Core", StringComparison.OrdinalIgnoreCase); public static int WindowsVersion => IsWindows ? (int)GetWindowsVersion() : -1; diff --git a/src/libraries/System.Diagnostics.EventLog/src/System.Diagnostics.EventLog.csproj b/src/libraries/System.Diagnostics.EventLog/src/System.Diagnostics.EventLog.csproj index 96deaca0a27dd..5bf9cee3c8725 100644 --- a/src/libraries/System.Diagnostics.EventLog/src/System.Diagnostics.EventLog.csproj +++ b/src/libraries/System.Diagnostics.EventLog/src/System.Diagnostics.EventLog.csproj @@ -3,6 +3,8 @@ $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);$(NetCoreAppPrevious)-windows;$(NetCoreAppPrevious);$(NetCoreAppMinimum)-windows;$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true true + true + 1 Provides the System.Diagnostics.EventLog class, which allows the applications to use the Windows event log service. Commonly Used Types: diff --git a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/NativeWrapper.cs b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/NativeWrapper.cs index e4cebc7c2e1da..557ff992004ce 100644 --- a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/NativeWrapper.cs +++ b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/NativeWrapper.cs @@ -482,7 +482,8 @@ internal static EventLogHandle EvtGetPublisherMetadataPropertyHandle(EventLogHan public static string EvtFormatMessage(EventLogHandle handle, uint msgId) { int bufferNeeded; - bool status = UnsafeNativeMethods.EvtFormatMessage(handle, EventLogHandle.Zero, msgId, 0, null, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageId, 0, null, out bufferNeeded); + Span emptyBuffer = [ '\0' ]; // issue: https://github.com/dotnet/runtime/issues/100198 + bool status = UnsafeNativeMethods.EvtFormatMessage(handle, EventLogHandle.Zero, msgId, 0, null, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageId, 0, emptyBuffer, out bufferNeeded); int error = Marshal.GetLastWin32Error(); // ERROR_EVT_UNRESOLVED_VALUE_INSERT and its cousins are commonly returned for raw message text. @@ -933,7 +934,8 @@ public static IList EvtRenderBufferWithContextUserOrValues(EventLogHandl public static string EvtFormatMessageRenderName(EventLogHandle pmHandle, EventLogHandle eventHandle, UnsafeNativeMethods.EvtFormatMessageFlags flag) { int bufferNeeded; - bool status = UnsafeNativeMethods.EvtFormatMessage(pmHandle, eventHandle, 0, 0, null, flag, 0, null, out bufferNeeded); + Span emptyBuffer = [ '\0' ]; // issue: https://github.com/dotnet/runtime/issues/100198 + bool status = UnsafeNativeMethods.EvtFormatMessage(pmHandle, eventHandle, 0, 0, null, flag, 0, emptyBuffer, out bufferNeeded); int error = Marshal.GetLastWin32Error(); if (!status && error != UnsafeNativeMethods.ERROR_EVT_UNRESOLVED_VALUE_INSERT @@ -985,11 +987,12 @@ public static IEnumerable EvtFormatMessageRenderKeywords(EventLogHandle { IntPtr buffer = IntPtr.Zero; int bufferNeeded; + Span emptyBuffer = [ '\0' ]; // issue: https://github.com/dotnet/runtime/issues/100198 try { List keywordsList = new List(); - bool status = UnsafeNativeMethods.EvtFormatMessageBuffer(pmHandle, eventHandle, 0, 0, IntPtr.Zero, flag, 0, IntPtr.Zero, out bufferNeeded); + bool status = UnsafeNativeMethods.EvtFormatMessage(pmHandle, eventHandle, 0, 0, null, flag, 0, emptyBuffer, out bufferNeeded); int error = Marshal.GetLastWin32Error(); if (!status) @@ -1071,6 +1074,7 @@ public static string EvtRenderBookmark(EventLogHandle eventHandle) public static string EvtFormatMessageFormatDescription(EventLogHandle handle, EventLogHandle eventHandle, string[] values) { int bufferNeeded; + Span emptyBuffer = [ '\0' ]; // issue: https://github.com/dotnet/runtime/issues/100198 UnsafeNativeMethods.EvtStringVariant[] stringVariants = new UnsafeNativeMethods.EvtStringVariant[values.Length]; for (int i = 0; i < values.Length; i++) @@ -1079,7 +1083,7 @@ public static string EvtFormatMessageFormatDescription(EventLogHandle handle, Ev stringVariants[i].StringVal = values[i]; } - bool status = UnsafeNativeMethods.EvtFormatMessage(handle, eventHandle, 0xffffffff, values.Length, stringVariants, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageEvent, 0, null, out bufferNeeded); + bool status = UnsafeNativeMethods.EvtFormatMessage(handle, eventHandle, 0xffffffff, values.Length, stringVariants, UnsafeNativeMethods.EvtFormatMessageFlags.EvtFormatMessageEvent, 0, emptyBuffer, out bufferNeeded); int error = Marshal.GetLastWin32Error(); if (!status && error != UnsafeNativeMethods.ERROR_EVT_UNRESOLVED_VALUE_INSERT diff --git a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs index 21ce94d0c423f..ef2d1b8726e36 100644 --- a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs +++ b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/UnsafeNativeMethods.cs @@ -762,7 +762,7 @@ internal static partial bool EvtFormatMessage( EvtStringVariant[] values, EvtFormatMessageFlags flags, int bufferSize, - [Out] char[]? buffer, + Span buffer, out int bufferUsed); [LibraryImport(Interop.Libraries.Wevtapi, EntryPoint = "EvtFormatMessage", SetLastError = true)] diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj b/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj index 4e4b50727b7fa..8959c43540ca1 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj @@ -4,7 +4,7 @@ true true true - true + false 2 Provides a message handler for HttpClient based on the WinHTTP interface of Windows. While similar to HttpClientHandler, it provides developers more granular control over the application's HTTP communication than the HttpClientHandler. diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs index ce79f20ad4efe..540bf4152a995 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs @@ -22,9 +22,9 @@ public BidirectionStreamingTest(ITestOutputHelper output) : base(output) // Build number suggested by the WinHttp team. // It can be reduced if bidirectional streaming is backported. - public static bool OsSupportsWinHttpBidirectionalStreaming => Environment.OSVersion.Version >= new Version(10, 0, 22357, 0); + public static bool OsSupportsWinHttpBidirectionalStreaming => Environment.OSVersion.Version >= new Version(10, 0, 22357, 0) || PlatformDetection.IsWindowsServer2022; - public static bool TestsEnabled => OsSupportsWinHttpBidirectionalStreaming && PlatformDetection.SupportsAlpn; + public static bool TestsEnabled => OsSupportsWinHttpBidirectionalStreaming && PlatformDetection.SupportsAlpn && !PlatformDetection.IsWindowsServer2022; public static bool TestsBackwardsCompatibilityEnabled => !OsSupportsWinHttpBidirectionalStreaming && PlatformDetection.SupportsAlpn; diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index fae7c1b441457..194b2b35f2b45 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -262,17 +262,12 @@ public static explicit operator Half(Int128 value) /// is not representable by . public static explicit operator checked short(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - return checked((short)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((short)value._lower); + return checked((short)lower); } /// Explicitly converts a 128-bit signed integer to a value. @@ -286,17 +281,12 @@ public static explicit operator checked short(Int128 value) /// is not representable by . public static explicit operator checked int(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - return checked((int)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((int)value._lower); + return checked((int)lower); } /// Explicitly converts a 128-bit signed integer to a value. @@ -310,17 +300,12 @@ public static explicit operator checked int(Int128 value) /// is not representable by . public static explicit operator checked long(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - return lower; - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((long)value._lower); + return lower; } /// Explicitly converts a 128-bit signed integer to a value. @@ -334,17 +319,12 @@ public static explicit operator checked long(Int128 value) /// is not representable by . public static explicit operator checked nint(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - return checked((nint)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((nint)value._lower); + return checked((nint)lower); } /// Explicitly converts a 128-bit signed integer to a value. @@ -360,17 +340,12 @@ public static explicit operator checked nint(Int128 value) [CLSCompliant(false)] public static explicit operator checked sbyte(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - return checked((sbyte)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((sbyte)value._lower); + return checked((sbyte)lower); } /// Explicitly converts a 128-bit signed integer to a value. diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs index 2524b4fd53606..ea0ece02e33b3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs @@ -220,6 +220,10 @@ public AdjustmentRule[] GetAdjustmentRules() return rulesList.ToArray(); } + private string NameLookupId => + HasIanaId ? Id : + (_equivalentZones is not null && _equivalentZones.Count > 0 ? _equivalentZones[0].Id : (GetAlternativeId(Id, out _) ?? Id)); + private string? PopulateDisplayName() { if (IsUtcAlias(Id)) @@ -231,7 +235,7 @@ public AdjustmentRule[] GetAdjustmentRules() if (GlobalizationMode.Invariant) return displayName; - GetFullValueForDisplayNameField(Id, BaseUtcOffset, ref displayName); + GetFullValueForDisplayNameField(NameLookupId, BaseUtcOffset, ref displayName); return displayName; } @@ -245,7 +249,7 @@ public AdjustmentRule[] GetAdjustmentRules() if (GlobalizationMode.Invariant) return standardDisplayName; - GetStandardDisplayName(Id, ref standardDisplayName); + GetStandardDisplayName(NameLookupId, ref standardDisplayName); return standardDisplayName; } @@ -259,7 +263,7 @@ public AdjustmentRule[] GetAdjustmentRules() if (GlobalizationMode.Invariant) return daylightDisplayName; - GetDaylightDisplayName(Id, ref daylightDisplayName); + GetDaylightDisplayName(NameLookupId, ref daylightDisplayName); return daylightDisplayName; } diff --git a/src/libraries/System.Runtime/tests/System/Int128Tests.cs b/src/libraries/System.Runtime/tests/System/Int128Tests.cs index 26fba082e64a8..19c8b5d593fdb 100644 --- a/src/libraries/System.Runtime/tests/System/Int128Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int128Tests.cs @@ -107,6 +107,51 @@ public static void EqualsTest(Int128 i1, object obj, bool expected) Assert.Equal(expected, i1.Equals(obj)); } + [Fact] + public static void CheckedConvertToInt64() + { + Assert.Equal(123L, checked((long)new Int128(0, 123))); + Assert.Equal(-123L, checked((long)(Int128)(-123))); + Assert.Throws(() => checked((long)new Int128(1, 1))); + Assert.Throws(() => checked((long)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToInt32() + { + Assert.Equal(123, checked((int)new Int128(0, 123))); + Assert.Equal(-123, checked((int)(Int128)(-123))); + Assert.Throws(() => checked((int)new Int128(1, 1))); + Assert.Throws(() => checked((int)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToInt16() + { + Assert.Equal((short)123, checked((short)new Int128(0, 123))); + Assert.Equal((short)(-123), checked((short)(Int128)(-123))); + Assert.Throws(() => checked((short)new Int128(1, 1))); + Assert.Throws(() => checked((short)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToSByte() + { + Assert.Equal((sbyte)123, checked((sbyte)new Int128(0, 123))); + Assert.Equal((sbyte)(-123), checked((sbyte)(Int128)(-123))); + Assert.Throws(() => checked((sbyte)new Int128(1, 1))); + Assert.Throws(() => checked((sbyte)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToIntPtr() + { + Assert.Equal((nint)123, checked((nint)new Int128(0, 123))); + Assert.Equal((nint)(-123), checked((nint)(Int128)(-123))); + Assert.Throws(() => checked((nint)new Int128(1, 1))); + Assert.Throws(() => checked((nint)new Int128(ulong.MaxValue, 42))); + } + public static IEnumerable ToString_TestData() { foreach (NumberFormatInfo defaultFormat in new[] { null, NumberFormatInfo.CurrentInfo }) diff --git a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs index 286e18ba3410c..92353c676b64d 100644 --- a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs +++ b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs @@ -3211,6 +3211,32 @@ public static void TestCustomTimeZonesWithNullNames() Assert.Equal(string.Empty, custom.DisplayName); } + [InlineData("Eastern Standard Time", "America/New_York")] + [InlineData("Central Standard Time", "America/Chicago")] + [InlineData("Mountain Standard Time", "America/Denver")] + [InlineData("Pacific Standard Time", "America/Los_Angeles")] + [ConditionalTheory(nameof(SupportICUAndRemoteExecution))] + public static void TestTimeZoneNames(string windowsId, string ianaId) + { + RemoteExecutor.Invoke(static (wId, iId) => + { + TimeZoneInfo info1, info2; + if (PlatformDetection.IsWindows) + { + info1 = TimeZoneInfo.FindSystemTimeZoneById(iId); + info2 = TimeZoneInfo.FindSystemTimeZoneById(wId); + } + else + { + info1 = TimeZoneInfo.FindSystemTimeZoneById(wId); + info2 = TimeZoneInfo.FindSystemTimeZoneById(iId); + } + Assert.Equal(info1.StandardName, info2.StandardName); + Assert.Equal(info1.DaylightName, info2.DaylightName); + Assert.Equal(info1.DisplayName, info2.DisplayName); + }, windowsId, ianaId).Dispose(); + } + private static bool IsEnglishUILanguage => CultureInfo.CurrentUICulture.Name.Length == 0 || CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "en"; private static bool IsEnglishUILanguageAndRemoteExecutorSupported => IsEnglishUILanguage && RemoteExecutor.IsSupported; diff --git a/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx index 4bcfdcfd3454f..5cc5cce830a35 100644 --- a/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography/src/Resources/Strings.resx @@ -327,6 +327,9 @@ {0} unexpectedly produced a ciphertext with the incorrect length. + + OpenSSL ENGINE is not available on this platform. + The total number of bytes extracted cannot exceed UInt32.MaxValue * hash length. diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index a550e9cf9cc82..efcc5c27e4acc 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -418,6 +418,10 @@ + + + diff --git a/src/mono/mono/eventpipe/ep-rt-mono-runtime-provider.c b/src/mono/mono/eventpipe/ep-rt-mono-runtime-provider.c index 4ab963643d4c3..8f3b104466e24 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono-runtime-provider.c +++ b/src/mono/mono/eventpipe/ep-rt-mono-runtime-provider.c @@ -815,7 +815,7 @@ get_module_event_data ( module_data->module_flags = MODULE_FLAGS_MANIFEST_MODULE; if (image && image->dynamic) module_data->module_flags |= MODULE_FLAGS_DYNAMIC_MODULE; - if (image && image->aot_module) + if (image && image->aot_module && (image->aot_module != AOT_MODULE_NOT_FOUND)) module_data->module_flags |= MODULE_FLAGS_NATIVE_MODULE; module_data->module_il_path = NULL; @@ -905,7 +905,7 @@ fire_assembly_events ( if (assembly->dynamic) assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY; - if (assembly->image && assembly->image->aot_module) { + if (assembly->image && assembly->image->aot_module && (assembly->image->aot_module != AOT_MODULE_NOT_FOUND)) { assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY; } @@ -2154,7 +2154,7 @@ get_assembly_event_data ( if (assembly->dynamic) assembly_data->assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY; - if (assembly->image && assembly->image->aot_module) + if (assembly->image && assembly->image->aot_module && (assembly->image->aot_module != AOT_MODULE_NOT_FOUND)) assembly_data->assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY; assembly_data->assembly_name = mono_stringify_assembly_name (&assembly->aname); diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index 86c70dba38862..1a2a4670437ad 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -1795,7 +1795,7 @@ init_amodule_got (MonoAotModule *amodule, gboolean preinit) if (mono_defaults.corlib) { MonoAotModule *mscorlib_amodule = mono_defaults.corlib->aot_module; - if (mscorlib_amodule) + if (mscorlib_amodule && (mscorlib_amodule != AOT_MODULE_NOT_FOUND)) amodule->shared_got [i] = mscorlib_amodule->got; } else { amodule->shared_got [i] = amodule->got; @@ -2053,6 +2053,7 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer g_free (aot_name); } #endif + assembly->image->aot_module = AOT_MODULE_NOT_FOUND; return; } } @@ -2104,7 +2105,7 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer mono_dl_close (sofile, close_error); mono_error_cleanup (close_error); } - assembly->image->aot_module = NULL; + assembly->image->aot_module = AOT_MODULE_NOT_FOUND; return; } @@ -2487,7 +2488,7 @@ load_container_amodule (MonoAssemblyLoadContext *alc) load_aot_module(alc, assm, NULL, error); mono_memory_barrier (); - g_assert (assm->image->aot_module); + g_assert (assm->image->aot_module && (assm->image->aot_module != AOT_MODULE_NOT_FOUND)); container_amodule = assm->image->aot_module; } @@ -2561,7 +2562,7 @@ mono_aot_get_method_from_vt_slot (MonoVTable *vtable, int slot, MonoError *error error_init (error); - if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || m_class_get_rank (klass) || !amodule) + if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || m_class_get_rank (klass) || !amodule || (amodule == AOT_MODULE_NOT_FOUND)) return NULL; info = &amodule->blob [mono_aot_get_offset (amodule->class_info_offsets, mono_metadata_token_index (m_class_get_type_token (klass)) - 1)]; @@ -2597,7 +2598,7 @@ mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res) guint8 *p; gboolean err; - if (m_class_get_rank (klass) || !m_class_get_type_token (klass) || !amodule) + if (m_class_get_rank (klass) || !m_class_get_type_token (klass) || !amodule || (amodule == AOT_MODULE_NOT_FOUND)) return FALSE; p = (guint8*)&amodule->blob [mono_aot_get_offset (amodule->class_info_offsets, mono_metadata_token_index (m_class_get_type_token (klass)) - 1)]; @@ -2637,7 +2638,7 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch uint32_t debug_hash; #endif - if (!amodule || !amodule->class_name_table) + if (!amodule || (amodule == AOT_MODULE_NOT_FOUND) || !amodule->class_name_table) return FALSE; amodule_lock (amodule); @@ -2746,7 +2747,7 @@ mono_aot_get_weak_field_indexes (MonoImage *image) { MonoAotModule *amodule = image->aot_module; - if (!amodule) + if (!amodule || (amodule == AOT_MODULE_NOT_FOUND)) return NULL; #if ENABLE_WEAK_ATTR @@ -3437,7 +3438,7 @@ mono_aot_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len) amodule = ji->d.aot_info; else amodule = m_class_get_image (jinfo_get_method (ji)->klass)->aot_module; - g_assert (amodule); + g_assert (amodule && (amodule != AOT_MODULE_NOT_FOUND)); g_assert (ji->from_aot); if (!amodule_contains_code_addr (amodule, code)) { @@ -3574,7 +3575,7 @@ mono_aot_find_jit_info (MonoImage *image, gpointer addr) int methods_len; gboolean async; - if (!amodule) + if (!amodule || (amodule == AOT_MODULE_NOT_FOUND)) return NULL; addr = MINI_FTNPTR_TO_ADDR (addr); @@ -4468,7 +4469,7 @@ find_aot_method_in_amodule (MonoAotModule *code_amodule, MonoMethod *method, gui // the caching breaking. The solution seems to be to cache using the "metadata" amodule. MonoAotModule *metadata_amodule = m_class_get_image (method->klass)->aot_module; - if (!metadata_amodule || metadata_amodule->out_of_date || !code_amodule || code_amodule->out_of_date) + if (!metadata_amodule || (metadata_amodule == AOT_MODULE_NOT_FOUND) || metadata_amodule->out_of_date || !code_amodule || code_amodule->out_of_date) return 0xffffff; table = code_amodule->extra_method_table; @@ -4638,7 +4639,7 @@ find_aot_method (MonoMethod *method, MonoAotModule **out_amodule) /* Try the method's module first */ *out_amodule = m_class_get_image (method->klass)->aot_module; - index = find_aot_method_in_amodule (m_class_get_image (method->klass)->aot_module, method, hash); + index = find_aot_method_in_amodule (*out_amodule, method, hash); if (index != 0xffffff) return index; @@ -4873,14 +4874,37 @@ mono_aot_get_method (MonoMethod *method, MonoError *error) MonoClass *klass = method->klass; MonoMethod *orig_method = method; guint32 method_index; - MonoAotModule *amodule = m_class_get_image (klass)->aot_module; + MonoImage *image = m_class_get_image (klass); + guint8 *code; gboolean cache_result = FALSE; ERROR_DECL (inner_error); error_init (error); - if (!amodule) + if (!(image->aot_module)) { + // aot_module was uninitialized + MonoMethodHeader *header = mono_method_get_header_checked (method, inner_error); + mono_error_cleanup (inner_error); + if (!header) { + return NULL; + } else if (header->code_size != 0) { + return NULL; + } else { + // IL code for the method body doesn't exist. Try waiting for aot_module to be loaded probably by another thread + int count = 0; + while (!(image->aot_module) && (count < 10)) { // The threshold of count should never be removed to prevent deadlock. + g_usleep (100); + count++; + } + if (!(image->aot_module)) + return NULL; + } + } + + MonoAotModule *amodule = image->aot_module; + + if (amodule == AOT_MODULE_NOT_FOUND) return NULL; if (amodule->out_of_date) @@ -5094,7 +5118,7 @@ mono_aot_get_method_from_token (MonoImage *image, guint32 token, MonoError *erro error_init (error); - if (!aot_module) + if (!aot_module || aot_module == AOT_MODULE_NOT_FOUND) return NULL; method_index = mono_metadata_token_index (token) - 1; @@ -5596,7 +5620,7 @@ get_mscorlib_aot_module (void) MonoAotModule *amodule; image = mono_defaults.corlib; - if (image && image->aot_module) + if (image && image->aot_module && (image->aot_module != AOT_MODULE_NOT_FOUND)) amodule = image->aot_module; else amodule = mscorlib_aot_module; @@ -6048,7 +6072,7 @@ ui16_idx_comparer (const void *key, const void *member) static gboolean aot_is_slim_amodule (MonoAotModule *amodule) { - if (!amodule) + if (!amodule || amodule == AOT_MODULE_NOT_FOUND) return FALSE; /* "slim" only applies to mscorlib.dll */ @@ -6086,7 +6110,7 @@ mono_aot_get_unbox_trampoline (MonoMethod *method, gpointer addr) } else amodule = m_class_get_image (method->klass)->aot_module; - if (amodule == NULL || method_index == 0xffffff || aot_is_slim_amodule (amodule)) { + if (!amodule || amodule == AOT_MODULE_NOT_FOUND || method_index == 0xffffff || aot_is_slim_amodule (amodule)) { /* couldn't find unbox trampoline specifically generated for that * method. this should only happen when an unbox trampoline is needed * for `fullAOT code -> native-to-interp -> interp` transition if diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 2942fb23d3f82..5328d982af6f0 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -3362,9 +3362,6 @@ interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *e return (gpointer)no_llvmonly_interp_method_pointer; } - if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) - return imethod; - #ifndef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE /* * Interp in wrappers get the argument in the rgctx register. If diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index bdb2b3f45eaf0..da1d0c31e086d 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -1231,7 +1231,8 @@ mono_interp_jit_call_supported (MonoMethod *method, MonoMethodSignature *sig) if (!interp_jit_call_can_be_supported (method, sig, mono_llvm_only)) return FALSE; - if (mono_aot_only && m_class_get_image (method->klass)->aot_module && !(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) { + MonoAotModule *amodule = m_class_get_image (method->klass)->aot_module; + if (mono_aot_only && amodule && (amodule != AOT_MODULE_NOT_FOUND) && !(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) { ERROR_DECL (error); mono_class_init_internal (method->klass); gpointer addr = mono_aot_get_method (method, error); diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index e03b142feef1f..881f491343af9 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -3034,7 +3034,8 @@ emit_call (MonoCompile *cfg, MonoCallInst *call, guint8 *code, MonoJitICallId ji MonoMethod* const method = call->method; - if (m_class_get_image (method->klass)->aot_module) + MonoAotModule *amodule = m_class_get_image (method->klass)->aot_module; + if (amodule && (amodule != AOT_MODULE_NOT_FOUND)) /* The callee might be an AOT method */ near_call = FALSE; if (method->dynamic) diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index d075623de8cf7..0318c3d1689bc 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -2558,7 +2558,18 @@ compile_special (MonoMethod *method, MonoError *error) } else { MonoMethod *nm = mono_marshal_get_native_wrapper (method, TRUE, mono_aot_only); compiled_method = mono_jit_compile_method_jit_only (nm, error); - return_val_if_nok (error, NULL); + if (!compiled_method && mono_aot_only && mono_use_interpreter) { + // We failed to find wrapper in aot images, try interpreting it instead + mono_error_cleanup (error); + error_init_reuse (error); + nm = mono_marshal_get_native_wrapper (method, TRUE, FALSE); + compiled_method = mono_jit_compile_method (nm, error); + return_val_if_nok (error, NULL); + code = mono_get_addr_from_ftnptr (compiled_method); + return code; + } else { + return_val_if_nok (error, NULL); + } } code = mono_get_addr_from_ftnptr (compiled_method); diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index eee8fd39bd5a5..f6a8ded6e7c55 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -423,6 +423,8 @@ struct MonoSpillInfo { int offset; }; +#define AOT_MODULE_NOT_FOUND GINT_TO_POINTER (-1) + /* * Information about a call site for the GC map creation code */ diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 324f36cad7957..b13b13a02bcff 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -212,9 +212,6 @@ Copyright (c) .NET Foundation. All rights reserved. <_BlazorWebAssemblyStartupMemoryCache>$(BlazorWebAssemblyStartupMemoryCache) <_BlazorWebAssemblyJiterpreter>$(BlazorWebAssemblyJiterpreter) <_BlazorWebAssemblyRuntimeOptions>$(BlazorWebAssemblyRuntimeOptions) - <_WasmDebugLevel>$(WasmDebugLevel) - <_WasmDebugLevel Condition="'$(_WasmDebugLevel)' == ''">0 - <_WasmDebugLevel Condition="'$(_WasmDebugLevel)' == '0' and ('$(DebuggerSupport)' == 'true' or '$(Configuration)' == 'Debug')">-1 $(OutputPath)$(PublishDirName)\ @@ -373,7 +370,7 @@ Copyright (c) .NET Foundation. All rights reserved. AssemblyPath="@(IntermediateAssembly)" Resources="@(_WasmOutputWithHash)" DebugBuild="true" - DebugLevel="$(_WasmDebugLevel)" + DebugLevel="$(WasmDebugLevel)" LinkerEnabled="false" CacheBootResources="$(BlazorCacheBootResources)" OutputPath="$(_WasmBuildBootJsonPath)" @@ -389,7 +386,8 @@ Copyright (c) .NET Foundation. All rights reserved. Extensions="@(WasmBootConfigExtension)" TargetFrameworkVersion="$(TargetFrameworkVersion)" ModuleAfterConfigLoaded="@(WasmModuleAfterConfigLoaded)" - ModuleAfterRuntimeReady="@(WasmModuleAfterRuntimeReady)" /> + ModuleAfterRuntimeReady="@(WasmModuleAfterRuntimeReady)" + IsPublish="false" /> @@ -566,7 +564,7 @@ Copyright (c) .NET Foundation. All rights reserved. AssemblyPath="@(IntermediateAssembly)" Resources="@(_WasmPublishBootResourceWithHash)" DebugBuild="false" - DebugLevel="$(_WasmDebugLevel)" + DebugLevel="$(WasmDebugLevel)" LinkerEnabled="$(PublishTrimmed)" CacheBootResources="$(BlazorCacheBootResources)" OutputPath="$(IntermediateOutputPath)blazor.publish.boot.json" @@ -582,7 +580,8 @@ Copyright (c) .NET Foundation. All rights reserved. Extensions="@(WasmBootConfigExtension)" TargetFrameworkVersion="$(TargetFrameworkVersion)" ModuleAfterConfigLoaded="@(WasmModuleAfterConfigLoaded)" - ModuleAfterRuntimeReady="@(WasmModuleAfterRuntimeReady)" /> + ModuleAfterRuntimeReady="@(WasmModuleAfterRuntimeReady)" + IsPublish="true" /> diff --git a/src/mono/nuget/mono-packages.proj b/src/mono/nuget/mono-packages.proj index 438ec97ace3e1..beebe7690cfad 100644 --- a/src/mono/nuget/mono-packages.proj +++ b/src/mono/nuget/mono-packages.proj @@ -28,7 +28,7 @@ - + diff --git a/src/mono/wasi/build/WasiApp.targets b/src/mono/wasi/build/WasiApp.targets index 099ba8c3ebea2..c403cd718f55c 100644 --- a/src/mono/wasi/build/WasiApp.targets +++ b/src/mono/wasi/build/WasiApp.targets @@ -368,6 +368,11 @@ + + <_WasmOutputSymbolsToAppBundle Condition="'$(CopyOutputSymbolsToPublishDirectory)' == 'true' and '$(_IsPublishing)' == 'true'">true + <_WasmOutputSymbolsToAppBundle Condition="'$(_WasmOutputSymbolsToAppBundle)' == ''">false + + diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs index 1d13051dd7344..dbf0e848f7513 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs @@ -75,6 +75,10 @@ public string CreateBlazorWasmTemplateProject(string id) if (options.ExpectSuccess && options.AssertAppBundle) { + // Because we do relink in Release publish by default + if (options.Config == "Release") + options = options with { ExpectedFileType = NativeFilesType.Relinked }; + AssertBundle(res.Output, options with { IsPublish = true }); } diff --git a/src/mono/wasm/Wasm.Build.Tests/BrowserRunner.cs b/src/mono/wasm/Wasm.Build.Tests/BrowserRunner.cs index d72a844abf1e7..19da797813a60 100644 --- a/src/mono/wasm/Wasm.Build.Tests/BrowserRunner.cs +++ b/src/mono/wasm/Wasm.Build.Tests/BrowserRunner.cs @@ -41,7 +41,9 @@ public async Task RunAsync( bool headless = true, Action? onConsoleMessage = null, Action? onError = null, - Func? modifyBrowserUrl = null) + Func? modifyBrowserUrl = null, + int timeout = 10000, + int maxRetries = 3) { TaskCompletionSource urlAvailable = new(); Action outputHandler = msg => @@ -89,17 +91,33 @@ public async Task RunAsync( Playwright = await Microsoft.Playwright.Playwright.CreateAsync(); string[] chromeArgs = new[] { $"--explicitly-allowed-ports={url.Port}" }; _testOutput.WriteLine($"Launching chrome ('{s_chromePath.Value}') via playwright with args = {string.Join(',', chromeArgs)}"); - Browser = await Playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions{ - ExecutablePath = s_chromePath.Value, - Headless = headless, - Args = chromeArgs - }); - + int attempt = 0; + while (attempt < maxRetries) + { + try + { + Browser = await Playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions{ + ExecutablePath = s_chromePath.Value, + Headless = headless, + Args = chromeArgs, + Timeout = timeout + }); + break; + } + catch (System.TimeoutException ex) + { + attempt++; + _testOutput.WriteLine($"Attempt {attempt} failed with TimeoutException: {ex.Message}"); + } + } + if (attempt == maxRetries) + throw new Exception($"Failed to launch browser after {maxRetries} attempts"); + string browserUrl = urlAvailable.Task.Result; if (modifyBrowserUrl != null) browserUrl = modifyBrowserUrl(browserUrl); - IPage page = await Browser.NewPageAsync(); + IPage page = await Browser!.NewPageAsync(); if (onConsoleMessage is not null) page.Console += (_, msg) => onConsoleMessage(msg); diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppSettingsTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppSettingsTests.cs index 96f2c4ebd6a1b..5d028cc238909 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppSettingsTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppSettingsTests.cs @@ -28,7 +28,7 @@ public async Task LoadAppSettingsBasedOnApplicationEnvironment(string applicatio CopyTestAsset("WasmBasicTestApp", "AppSettingsTests"); PublishProject("Debug"); - var result = await RunSdkStyleApp(new( + var result = await RunSdkStyleAppForPublish(new( Configuration: "Debug", TestScenario: "AppSettingsTest", BrowserQueryString: new Dictionary { ["applicationEnvironment"] = applicationEnvironment } diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs index dc6fb9b490e7f..3b3baf581c185 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/AppTestBase.cs @@ -36,15 +36,15 @@ protected void CopyTestAsset(string assetName, string generatedProjectNamePrefix _projectDir = Path.Combine(_projectDir!, "App"); } - protected void BuildProject(string configuration) + protected void BuildProject(string configuration, bool assertAppBundle = true, params string[] extraArgs) { - (CommandResult result, _) = BlazorBuild(new BlazorBuildOptions(Id, configuration)); + (CommandResult result, _) = BlazorBuild(new BlazorBuildOptions(Id, configuration, AssertAppBundle: assertAppBundle), extraArgs); result.EnsureSuccessful(); } - protected void PublishProject(string configuration) + protected void PublishProject(string configuration, bool assertAppBundle = true, params string[] extraArgs) { - (CommandResult result, _) = BlazorPublish(new BlazorBuildOptions(Id, configuration)); + (CommandResult result, _) = BlazorPublish(new BlazorBuildOptions(Id, configuration, AssertAppBundle: assertAppBundle), extraArgs); result.EnsureSuccessful(); } @@ -52,7 +52,13 @@ protected void PublishProject(string configuration) .WithWorkingDirectory(_projectDir!) .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir); - protected async Task RunSdkStyleApp(RunOptions options) + protected Task RunSdkStyleAppForBuild(RunOptions options) + => RunSdkStyleApp(options, BlazorRunHost.DotnetRun); + + protected Task RunSdkStyleAppForPublish(RunOptions options) + => RunSdkStyleApp(options, BlazorRunHost.WebServer); + + private async Task RunSdkStyleApp(RunOptions options, BlazorRunHost host = BlazorRunHost.DotnetRun) { string queryString = "?test=" + options.TestScenario; if (options.BrowserQueryString != null) @@ -67,9 +73,10 @@ protected async Task RunSdkStyleApp(RunOptions options) CheckCounter: false, Config: options.Configuration, OnConsoleMessage: OnConsoleMessage, - QueryString: queryString); + QueryString: queryString, + Host: host); - await BlazorRunForBuildWithDotnetRun(blazorRunOptions); + await BlazorRunTest(blazorRunOptions); void OnConsoleMessage(IConsoleMessage msg) { diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/DebugLevelTestsBase.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/DebugLevelTestsBase.cs new file mode 100644 index 0000000000000..219b8b2ed6714 --- /dev/null +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/DebugLevelTestsBase.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +#nullable enable + +namespace Wasm.Build.Tests.TestAppScenarios; + +public abstract class DebugLevelTestsBase : AppTestBase +{ + public DebugLevelTestsBase(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + : base(output, buildContext) + { + } + + protected void AssertDebugLevel(RunResult result, int value) + { + Assert.Collection( + result.TestOutput, + m => Assert.Equal($"WasmDebugLevel: {value}", m) + ); + } + + protected abstract void SetupProject(string projectId); + protected abstract Task RunForBuild(string configuration); + protected abstract Task RunForPublish(string configuration); + + [Theory] + [InlineData("Debug")] + [InlineData("Release")] + public async Task BuildWithDefaultLevel(string configuration) + { + SetupProject($"DebugLevelTests_BuildWithDefaultLevel_{configuration}"); + BuildProject(configuration, assertAppBundle: false); + + var result = await RunForBuild(configuration); + AssertDebugLevel(result, -1); + } + + [Theory] + [InlineData("Debug", 1)] + [InlineData("Release", 1)] + [InlineData("Debug", 0)] + [InlineData("Release", 0)] + public async Task BuildWithExplicitValue(string configuration, int debugLevel) + { + SetupProject($"DebugLevelTests_BuildWithExplicitValue_{configuration}"); + BuildProject(configuration, assertAppBundle: false, extraArgs: $"-p:WasmDebugLevel={debugLevel}"); + + var result = await RunForBuild(configuration); + AssertDebugLevel(result, debugLevel); + } + + [Theory] + [InlineData("Debug")] + [InlineData("Release")] + public async Task PublishWithDefaultLevel(string configuration) + { + SetupProject($"DebugLevelTests_PublishWithDefaultLevel_{configuration}"); + PublishProject(configuration, assertAppBundle: false); + + var result = await RunForPublish(configuration); + AssertDebugLevel(result, 0); + } + + [Theory] + [InlineData("Debug", 1)] + [InlineData("Release", 1)] + [InlineData("Debug", -1)] + [InlineData("Release", -1)] + public async Task PublishWithExplicitValue(string configuration, int debugLevel) + { + SetupProject($"DebugLevelTests_PublishWithExplicitValue_{configuration}"); + PublishProject(configuration, assertAppBundle: false, extraArgs: $"-p:WasmDebugLevel={debugLevel}"); + + var result = await RunForPublish(configuration); + AssertDebugLevel(result, debugLevel); + } +} \ No newline at end of file diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs index 8f37a47e18860..cf16a0536a38d 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LazyLoadingTests.cs @@ -26,7 +26,7 @@ public async Task LoadLazyAssemblyBeforeItIsNeeded() CopyTestAsset("WasmBasicTestApp", "LazyLoadingTests"); PublishProject("Debug"); - var result = await RunSdkStyleApp(new(Configuration: "Debug", TestScenario: "LazyLoadingTest")); + var result = await RunSdkStyleAppForPublish(new(Configuration: "Debug", TestScenario: "LazyLoadingTest")); Assert.True(result.TestOutput.Any(m => m.Contains("FirstName")), "The lazy loading test didn't emit expected message with JSON"); } @@ -36,7 +36,7 @@ public async Task FailOnMissingLazyAssembly() CopyTestAsset("WasmBasicTestApp", "LazyLoadingTests"); PublishProject("Debug"); - var result = await RunSdkStyleApp(new( + var result = await RunSdkStyleAppForPublish(new( Configuration: "Debug", TestScenario: "LazyLoadingTest", BrowserQueryString: new Dictionary { ["loadRequiredAssembly"] = "false" }, diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LibraryInitializerTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LibraryInitializerTests.cs index 6f68a96ad1d61..e985ad23d89a0 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LibraryInitializerTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/LibraryInitializerTests.cs @@ -29,7 +29,7 @@ public async Task LoadLibraryInitializer() CopyTestAsset("WasmBasicTestApp", "LibraryInitializerTests_LoadLibraryInitializer"); PublishProject("Debug"); - var result = await RunSdkStyleApp(new(Configuration: "Debug", TestScenario: "LibraryInitializerTest")); + var result = await RunSdkStyleAppForPublish(new(Configuration: "Debug", TestScenario: "LibraryInitializerTest")); Assert.Collection( result.TestOutput, m => Assert.Equal("LIBRARY_INITIALIZER_TEST = 1", m) @@ -42,7 +42,7 @@ public async Task AbortStartupOnError() CopyTestAsset("WasmBasicTestApp", "LibraryInitializerTests_AbortStartupOnError"); PublishProject("Debug"); - var result = await RunSdkStyleApp(new( + var result = await RunSdkStyleAppForPublish(new( Configuration: "Debug", TestScenario: "LibraryInitializerTest", BrowserQueryString: new Dictionary { ["throwError"] = "true" }, diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/ModuleConfigTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/ModuleConfigTests.cs index 1b8c43ecea77b..bc2b5631d2373 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/ModuleConfigTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/ModuleConfigTests.cs @@ -28,7 +28,7 @@ public async Task DownloadProgressFinishes(bool failAssemblyDownload) CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_DownloadProgressFinishes_{failAssemblyDownload}"); PublishProject("Debug"); - var result = await RunSdkStyleApp(new( + var result = await RunSdkStyleAppForPublish(new( Configuration: "Debug", TestScenario: "DownloadResourceProgressTest", BrowserQueryString: new Dictionary { ["failAssemblyDownload"] = failAssemblyDownload.ToString().ToLowerInvariant() } @@ -54,24 +54,4 @@ public async Task DownloadProgressFinishes(bool failAssemblyDownload) : "The download progress test did emit unexpected message about failing download" ); } - - [Fact] - public async Task OutErrOverrideWorks() - { - CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_OutErrOverrideWorks"); - PublishProject("Debug"); - - var result = await RunSdkStyleApp(new( - Configuration: "Debug", - TestScenario: "OutErrOverrideWorks" - )); - Assert.True( - result.ConsoleOutput.Any(m => m.Contains("Emscripten out override works!")), - "Emscripten out override doesn't work" - ); - Assert.True( - result.ConsoleOutput.Any(m => m.Contains("Emscripten err override works!")), - "Emscripten err override doesn't work" - ); - } } diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs index 31dcb65582869..2088e1522ad73 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs @@ -29,7 +29,7 @@ public async Task LoadSatelliteAssembly() CopyTestAsset("WasmBasicTestApp", "SatelliteLoadingTests"); BuildProject("Debug"); - var result = await RunSdkStyleApp(new(Configuration: "Debug", TestScenario: "SatelliteAssembliesTest")); + var result = await RunSdkStyleAppForBuild(new(Configuration: "Debug", TestScenario: "SatelliteAssembliesTest")); Assert.Collection( result.TestOutput, m => Assert.Equal("default: hello", m), diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmAppBuilderDebugLevelTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmAppBuilderDebugLevelTests.cs new file mode 100644 index 0000000000000..60fb3d86f7d0e --- /dev/null +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmAppBuilderDebugLevelTests.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +#nullable enable + +namespace Wasm.Build.Tests.TestAppScenarios; + +public class WasmAppBuilderDebugLevelTests : DebugLevelTestsBase +{ + public WasmAppBuilderDebugLevelTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + : base(output, buildContext) + { + } + + protected override void SetupProject(string projectId) + { + Id = $"{projectId}_{GetRandomId()}"; + string projectfile = CreateWasmTemplateProject(Id, "wasmconsole", extraArgs: "-f net8.0"); + string projectDir = Path.GetDirectoryName(projectfile)!; + string mainJs = Path.Combine(projectDir, "main.mjs"); + string mainJsContent = File.ReadAllText(mainJs); + mainJsContent = mainJsContent + .Replace("await dotnet.run()", "console.log('TestOutput -> WasmDebugLevel: ' + config.debugLevel); exit(0)"); + File.WriteAllText(mainJs, mainJsContent); + } + + protected override Task RunForBuild(string configuration) + { + CommandResult res = new RunCommand(s_buildEnv, _testOutput) + .WithWorkingDirectory(_projectDir!) + .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {configuration}"); + + return Task.FromResult(ProcessRunOutput(res)); + } + + private RunResult ProcessRunOutput(CommandResult res) + { + var output = res.Output.Split(Environment.NewLine); + _testOutput.WriteLine($"DEBUG: parsed lines '{String.Join(", ", output)}'"); + + var prefix = "[] TestOutput -> "; + var testOutput = output + .Where(l => l.StartsWith(prefix)) + .Select(l => l.Substring(prefix.Length)) + .ToArray(); + + _testOutput.WriteLine($"DEBUG: testOutput '{String.Join(", ", testOutput)}'"); + return new RunResult(res.ExitCode, testOutput, output); + } + + protected override Task RunForPublish(string configuration) + { + // WasmAppBuilder does publish to the same folder as build (it overrides the output), + // and thus using dotnet run work correctly for publish as well. + CommandResult res = new RunCommand(s_buildEnv, _testOutput) + .WithWorkingDirectory(_projectDir!) + .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {configuration}"); + + return Task.FromResult(ProcessRunOutput(res)); + } +} diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmSdkDebugLevelTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmSdkDebugLevelTests.cs new file mode 100644 index 0000000000000..f88bb3c7239c9 --- /dev/null +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmSdkDebugLevelTests.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +#nullable enable + +namespace Wasm.Build.Tests.TestAppScenarios; + +public class WasmSdkDebugLevelTests : DebugLevelTestsBase +{ + public WasmSdkDebugLevelTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + : base(output, buildContext) + { + } + + protected override void SetupProject(string projectId) => CopyTestAsset("WasmBasicTestApp", projectId); + + protected override Task RunForBuild(string configuration) => RunSdkStyleAppForBuild(new( + Configuration: configuration, + TestScenario: "DebugLevelTest" + )); + + protected override Task RunForPublish(string configuration) => RunSdkStyleAppForPublish(new( + Configuration: configuration, + TestScenario: "DebugLevelTest" + )); + + [Theory] + [InlineData("Debug")] + [InlineData("Release")] + public async Task PublishWithDefaultLevelAndPdbs(string configuration) + { + SetupProject($"DebugLevelTests_PublishWithDefaultLevelAndPdbs_{configuration}"); + PublishProject(configuration, extraArgs: $"-p:CopyOutputSymbolsToPublishDirectory=true"); + + var result = await RunForPublish(configuration); + AssertDebugLevel(result, -1); + } +} diff --git a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs index a7ae3fba70ed3..1cc70d823ef14 100644 --- a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs @@ -21,7 +21,7 @@ protected WasmTemplateTestBase(ITestOutputHelper output, SharedBuildPerTestClass _provider.BundleDirName = "AppBundle"; } - public string CreateWasmTemplateProject(string id, string template = "wasmbrowser", string extraArgs = "", bool runAnalyzers = true) + public string CreateWasmTemplateProject(string id, string template = "wasmbrowser", string extraArgs = "", bool runAnalyzers = true, string? extraProperties = null) { InitPaths(id); InitProjectDir(_projectDir, addNuGetSourceForLocalPackages: true); @@ -42,7 +42,9 @@ public string CreateWasmTemplateProject(string id, string template = "wasmbrowse .EnsureSuccessful(); string projectfile = Path.Combine(_projectDir!, $"{id}.csproj"); - string extraProperties = string.Empty; + if (extraProperties == null) + extraProperties = string.Empty; + extraProperties += "true"; if (runAnalyzers) extraProperties += "true"; diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets index a640a128b2504..bc92659fa3479 100644 --- a/src/mono/wasm/build/WasmApp.targets +++ b/src/mono/wasm/build/WasmApp.targets @@ -142,9 +142,6 @@ false - - -1 - true .wasm @@ -210,7 +207,7 @@ + Properties="_WasmInNestedPublish_UniqueProperty_XYZ=true;;WasmBuildingForNestedPublish=true;DeployOnBuild=;_IsPublishing=;_WasmIsPublishing=$(_IsPublishing)"> @@ -420,6 +417,7 @@ <_WasmAppIncludeThreadsWorker Condition="'$(WasmEnableThreads)' == 'true' or '$(MonoWasmBuildVariant)' == 'multithread'">true <_WasmPThreadPoolSize Condition="'$(_WasmPThreadPoolSize)' == ''">-1 + <_WasmIsPublishing Condition="'$(_WasmIsPublishing)' == '' and '$(_IsPublishing)' != ''">$(_IsPublishing) @@ -445,6 +443,7 @@ ExtraConfig="@(WasmExtraConfig)" NativeAssets="@(WasmNativeAsset)" DebugLevel="$(WasmDebugLevel)" + IsPublish="$(_WasmIsPublishing)" IncludeThreadsWorker="$(_WasmAppIncludeThreadsWorker)" PThreadPoolSize="$(_WasmPThreadPoolSize)" UseWebcil="$(WasmEnableWebcil)" diff --git a/src/mono/wasm/runtime/lazyLoading.ts b/src/mono/wasm/runtime/lazyLoading.ts index 55bcfd67101e8..85058f89819b7 100644 --- a/src/mono/wasm/runtime/lazyLoading.ts +++ b/src/mono/wasm/runtime/lazyLoading.ts @@ -26,7 +26,7 @@ export async function loadLazyAssembly(assemblyNameToLoad: string): Promise debugBuild=true & debugLevel=-1 => -1 - // - Build (release) => debugBuild=true & debugLevel=0 => 0 - // - Publish (debug) => debugBuild=false & debugLevel=-1 => 0 - // - Publish (release) => debugBuild=false & debugLevel=0 => 0 - config.debugLevel = hasDebuggingEnabled(config) ? config.debugLevel : 0; - if (config.diagnosticTracing === undefined && BuildConfiguration === "Debug") { config.diagnosticTracing = true; } @@ -264,14 +257,13 @@ export async function mono_wasm_load_config(module: DotnetModuleInternal): Promi } } -export function hasDebuggingEnabled(config: MonoConfigInternal): boolean { +export function isDebuggingSupported(): boolean { // Copied from blazor MonoDebugger.ts/attachDebuggerHotkey if (!globalThis.navigator) { return false; } - const hasReferencedPdbs = !!config.resources!.pdb; - return (hasReferencedPdbs || config.debugLevel != 0) && (loaderHelpers.isChromium || loaderHelpers.isFirefox); + return loaderHelpers.isChromium || loaderHelpers.isFirefox; } async function loadBootConfig(module: DotnetModuleInternal): Promise { diff --git a/src/mono/wasm/runtime/loader/globals.ts b/src/mono/wasm/runtime/loader/globals.ts index 88b0d472de3ca..0bd081ed8a82c 100644 --- a/src/mono/wasm/runtime/loader/globals.ts +++ b/src/mono/wasm/runtime/loader/globals.ts @@ -12,7 +12,7 @@ import { assertIsControllablePromise, createPromiseController, getPromiseControl import { mono_download_assets, resolve_single_asset_path, retrieve_asset_download } from "./assets"; import { setup_proxy_console } from "./logging"; import { invokeLibraryInitializers } from "./libraryInitializers"; -import { hasDebuggingEnabled } from "./config"; +import { isDebuggingSupported } from "./config"; import { logDownloadStatsToConsole, purgeUnusedCacheEntriesAsync } from "./assetsCache"; export const ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string"; @@ -102,9 +102,9 @@ export function setLoaderGlobals( logDownloadStatsToConsole, purgeUnusedCacheEntriesAsync, - hasDebuggingEnabled, retrieve_asset_download, invokeLibraryInitializers, + isDebuggingSupported, // from wasm-feature-detect npm package exceptions, diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index 324bdc78b0435..6efa969a953a8 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -548,7 +548,7 @@ async function mono_wasm_before_memory_snapshot() { if (runtimeHelpers.config.browserProfilerOptions) mono_wasm_init_browser_profiler(runtimeHelpers.config.browserProfilerOptions); - mono_wasm_load_runtime("unused", runtimeHelpers.config.debugLevel); + mono_wasm_load_runtime(); // we didn't have snapshot yet and the feature is enabled. Take snapshot now. if (runtimeHelpers.config.startupMemoryCache) { @@ -561,17 +561,21 @@ async function mono_wasm_before_memory_snapshot() { endMeasure(mark, MeasuredBlock.memorySnapshot); } -export function mono_wasm_load_runtime(unused?: string, debugLevel?: number): void { +export function mono_wasm_load_runtime(): void { mono_log_debug("mono_wasm_load_runtime"); try { const mark = startMeasure(); + let debugLevel = runtimeHelpers.config.debugLevel; if (debugLevel == undefined) { debugLevel = 0; if (runtimeHelpers.config.debugLevel) { debugLevel = 0 + debugLevel; } } - cwraps.mono_wasm_load_runtime(unused || "unused", debugLevel); + if (!loaderHelpers.isDebuggingSupported() || !runtimeHelpers.config.resources!.pdb) { + debugLevel = 0; + } + cwraps.mono_wasm_load_runtime("unused", debugLevel); endMeasure(mark, MeasuredBlock.loadRuntime); } catch (err: any) { diff --git a/src/mono/wasm/runtime/types/internal.ts b/src/mono/wasm/runtime/types/internal.ts index c43443a48da6b..c0b14b72abe5d 100644 --- a/src/mono/wasm/runtime/types/internal.ts +++ b/src/mono/wasm/runtime/types/internal.ts @@ -145,7 +145,6 @@ export type LoaderHelpers = { out(message: string): void; err(message: string): void; - hasDebuggingEnabled(config: MonoConfig): boolean, retrieve_asset_download(asset: AssetEntry): Promise; onDownloadResourceProgress?: (resourcesLoaded: number, totalResources: number) => void; logDownloadStatsToConsole: () => void; @@ -155,6 +154,7 @@ export type LoaderHelpers = { invokeLibraryInitializers: (functionName: string, args: any[]) => Promise, libraryInitializers?: { scriptName: string, exports: any }[]; + isDebuggingSupported(): boolean, isChromium: boolean, isFirefox: boolean diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/LazyLoadingTest.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/LazyLoadingTest.cs index 5aba6b1ee48a0..797956d23f8e4 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/LazyLoadingTest.cs +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/LazyLoadingTest.cs @@ -4,6 +4,7 @@ using Library; using System; using System.Text.Json; +using System.Text.Json.Serialization; using System.Runtime.InteropServices.JavaScript; public partial class LazyLoadingTest @@ -13,7 +14,12 @@ public static void Run() { // System.Text.Json is marked as lazy loaded in the csproj ("BlazorWebAssemblyLazyLoad"), this method can be called only after the assembly is lazy loaded // In the test case it is done in the JS before call to this method - var text = JsonSerializer.Serialize(new Person("John", "Doe")); + var text = JsonSerializer.Serialize(new Person("John", "Doe"), PersonJsonSerializerContext.Default.Person); TestOutput.WriteLine(text); } } + +[JsonSerializable(typeof(Person))] +public partial class PersonJsonSerializerContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js index 8e3485bc2e67c..5092e4cb945b7 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js @@ -33,6 +33,8 @@ switch (testCase) { Math.floor(Math.random() * 5) + 5, Math.floor(Math.random() * 5) + 10 ]; + console.log(`Failing test at assembly indexes [${failAtAssemblyNumbers.join(", ")}]`); + let alreadyFailed = []; dotnet.withDiagnosticTracing(true).withResourceLoader((type, name, defaultUri, integrity, behavior) => { if (type === "dotnetjs") { // loadBootResource could return string with unqualified name of resource. @@ -45,9 +47,10 @@ switch (testCase) { } assemblyCounter++; - if (!failAtAssemblyNumbers.includes(assemblyCounter)) + if (!failAtAssemblyNumbers.includes(assemblyCounter) || alreadyFailed.includes(defaultUri)) return defaultUri; + alreadyFailed.push(defaultUri); testOutput("Throw error instead of downloading resource"); const error = new Error("Simulating a failed fetch"); error.silent = true; @@ -106,6 +109,10 @@ try { case "DownloadResourceProgressTest": exit(0); break; + case "DebugLevelTest": + testOutput("WasmDebugLevel: " + config.debugLevel); + exit(0); + break; case "OutErrOverrideWorks": dotnet.run(); break; diff --git a/src/native/corehost/ijwhost/ijwhost.cpp b/src/native/corehost/ijwhost/ijwhost.cpp index 7f1684cca6263..c2e1d22a32cc5 100644 --- a/src/native/corehost/ijwhost/ijwhost.cpp +++ b/src/native/corehost/ijwhost/ijwhost.cpp @@ -20,7 +20,7 @@ #define IJW_API SHARED_API #endif // _WIN32 -pal::hresult_t get_load_in_memory_assembly_delegate(pal::dll_t handle, load_in_memory_assembly_fn* delegate) +pal::hresult_t get_load_in_memory_assembly_delegate(pal::dll_t handle, load_in_memory_assembly_fn* delegate, void **load_context) { get_function_pointer_fn get_function_pointer; int status = load_fxr_and_get_delegate( @@ -40,7 +40,17 @@ pal::hresult_t get_load_in_memory_assembly_delegate(pal::dll_t handle, load_in_m return StatusCode::Success; }, - [](pal::dll_t fxr, hostfxr_handle context){ }, + [load_context](pal::dll_t fxr, hostfxr_handle context) + { + *load_context = nullptr; // default load context + auto get_runtime_property_value = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_get_runtime_property_value")); + const pal::char_t* value; + if (get_runtime_property_value(context, _X("System.Runtime.InteropServices.CppCLI.LoadComponentInIsolatedContext"), &value) == StatusCode::Success + && pal::strcasecmp(value, _X("true")) == 0) + { + *load_context = ISOLATED_CONTEXT; // Isolated load context + } + }, reinterpret_cast(&get_function_pointer) ); if (status != StatusCode::Success) diff --git a/src/native/corehost/ijwhost/ijwhost.h b/src/native/corehost/ijwhost/ijwhost.h index c3698a4d4acb6..adfd52f71a99c 100644 --- a/src/native/corehost/ijwhost/ijwhost.h +++ b/src/native/corehost/ijwhost/ijwhost.h @@ -15,8 +15,10 @@ bool are_thunks_installed_for_module(HMODULE instance); using load_in_memory_assembly_fn = void(STDMETHODCALLTYPE*)(pal::dll_t handle, const pal::char_t* path, void* load_context); -pal::hresult_t get_load_in_memory_assembly_delegate(pal::dll_t handle, load_in_memory_assembly_fn* delegate); +pal::hresult_t get_load_in_memory_assembly_delegate(pal::dll_t handle, load_in_memory_assembly_fn* delegate, void **load_context); extern HANDLE g_heapHandle; +#define ISOLATED_CONTEXT (void*)-1 + #endif diff --git a/src/native/corehost/ijwhost/ijwthunk.cpp b/src/native/corehost/ijwhost/ijwthunk.cpp index eeddf10fd931c..2c24f4d6f9207 100644 --- a/src/native/corehost/ijwhost/ijwthunk.cpp +++ b/src/native/corehost/ijwhost/ijwthunk.cpp @@ -119,7 +119,9 @@ extern "C" std::uintptr_t __stdcall start_runtime_and_get_target_address(std::ui bootstrap_thunk *pThunk = bootstrap_thunk::get_thunk_from_cookie(cookie); load_in_memory_assembly_fn loadInMemoryAssembly; pal::dll_t moduleHandle = pThunk->get_dll_handle(); - pal::hresult_t status = get_load_in_memory_assembly_delegate(moduleHandle, &loadInMemoryAssembly); + + void* load_context = nullptr; + pal::hresult_t status = get_load_in_memory_assembly_delegate(moduleHandle, &loadInMemoryAssembly, &load_context); if (status != StatusCode::Success) { @@ -145,7 +147,7 @@ extern "C" std::uintptr_t __stdcall start_runtime_and_get_target_address(std::ui #pragma warning (pop) } - loadInMemoryAssembly(moduleHandle, app_path.c_str(), nullptr); + loadInMemoryAssembly(moduleHandle, app_path.c_str(), load_context); std::uintptr_t thunkAddress = *(pThunk->get_slot_address()); diff --git a/src/native/libs/System.Security.Cryptography.Native/configure.cmake b/src/native/libs/System.Security.Cryptography.Native/configure.cmake index 74ed49f5d1916..4a70e70899c5e 100644 --- a/src/native/libs/System.Security.Cryptography.Native/configure.cmake +++ b/src/native/libs/System.Security.Cryptography.Native/configure.cmake @@ -1,8 +1,10 @@ include(CheckLibraryExists) include(CheckFunctionExists) +include(CheckSourceCompiles) set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY} ${OPENSSL_SSL_LIBRARY}) +set(CMAKE_REQUIRED_DEFINITIONS -DOPENSSL_API_COMPAT=0x10100000L) check_function_exists( EC_GF2m_simple_method @@ -22,6 +24,11 @@ check_function_exists( HAVE_OPENSSL_SHA3 ) +check_source_compiles(C " +#include +int main(void) { ENGINE_init(NULL); return 1; }" +HAVE_OPENSSL_ENGINE) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/pal_crypto_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/pal_crypto_config.h) diff --git a/src/native/libs/System.Security.Cryptography.Native/opensslshim.h b/src/native/libs/System.Security.Cryptography.Native/opensslshim.h index 57ba6a6809649..3d6d77895b64f 100644 --- a/src/native/libs/System.Security.Cryptography.Native/opensslshim.h +++ b/src/native/libs/System.Security.Cryptography.Native/opensslshim.h @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -46,6 +45,11 @@ #include #endif +#if HAVE_OPENSSL_ENGINE +// Some Linux distributions build without engine support. +#include +#endif + #if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_1_RTM #define HAVE_OPENSSL_SET_CIPHERSUITES 1 #else @@ -168,6 +172,24 @@ const EVP_MD *EVP_shake256(void); int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md, size_t len); #endif +#if !HAVE_OPENSSL_ENGINE +#undef HAVE_OPENSSL_ENGINE +#define HAVE_OPENSSL_ENGINE 1 + +ENGINE *ENGINE_by_id(const char *id); +int ENGINE_init(ENGINE *e); +int ENGINE_finish(ENGINE *e); +ENGINE *ENGINE_new(void); +int ENGINE_free(ENGINE *e); +typedef EVP_PKEY *(*ENGINE_LOAD_KEY_PTR)(ENGINE *, const char *, + UI_METHOD *ui_method, + void *callback_data); +EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id, + UI_METHOD *ui_method, void *callback_data); +EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id, + UI_METHOD *ui_method, void *callback_data); +#endif + #define API_EXISTS(fn) (fn != NULL) // List of all functions from the libssl that are used in the System.Security.Cryptography.Native. @@ -298,12 +320,12 @@ int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md, size_t len); REQUIRED_FUNCTION(EC_POINT_mul) \ REQUIRED_FUNCTION(EC_POINT_new) \ REQUIRED_FUNCTION(EC_POINT_set_affine_coordinates_GFp) \ - REQUIRED_FUNCTION(ENGINE_by_id) \ - REQUIRED_FUNCTION(ENGINE_finish) \ - REQUIRED_FUNCTION(ENGINE_free) \ - REQUIRED_FUNCTION(ENGINE_init) \ - REQUIRED_FUNCTION(ENGINE_load_public_key) \ - REQUIRED_FUNCTION(ENGINE_load_private_key) \ + LIGHTUP_FUNCTION(ENGINE_by_id) \ + LIGHTUP_FUNCTION(ENGINE_finish) \ + LIGHTUP_FUNCTION(ENGINE_free) \ + LIGHTUP_FUNCTION(ENGINE_init) \ + LIGHTUP_FUNCTION(ENGINE_load_public_key) \ + LIGHTUP_FUNCTION(ENGINE_load_private_key) \ REQUIRED_FUNCTION(ERR_clear_error) \ REQUIRED_FUNCTION(ERR_error_string_n) \ REQUIRED_FUNCTION(ERR_get_error) \ diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_crypto_config.h.in b/src/native/libs/System.Security.Cryptography.Native/pal_crypto_config.h.in index d7aef5a7d1b67..30d1219eb98b0 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_crypto_config.h.in +++ b/src/native/libs/System.Security.Cryptography.Native/pal_crypto_config.h.in @@ -4,3 +4,4 @@ #cmakedefine01 HAVE_OPENSSL_ALPN #cmakedefine01 HAVE_OPENSSL_CHACHA20POLY1305 #cmakedefine01 HAVE_OPENSSL_SHA3 +#cmakedefine01 HAVE_OPENSSL_ENGINE diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c index 80183b97a77c9..dea4f277b8969 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c @@ -511,41 +511,72 @@ int32_t CryptoNative_EncodeSubjectPublicKeyInfo(EVP_PKEY* pkey, uint8_t* buf) return i2d_PUBKEY(pkey, &buf); } +#if HAVE_OPENSSL_ENGINE static EVP_PKEY* LoadKeyFromEngine( const char* engineName, const char* keyName, - ENGINE_LOAD_KEY_PTR load_func) + ENGINE_LOAD_KEY_PTR load_func, + int32_t* haveEngine) { + assert(haveEngine); ERR_clear_error(); - EVP_PKEY* ret = NULL; - ENGINE* engine = NULL; + if (API_EXISTS(ENGINE_by_id) && API_EXISTS(ENGINE_init) && API_EXISTS(ENGINE_finish) && API_EXISTS(ENGINE_free)) + { + *haveEngine = 1; + EVP_PKEY* ret = NULL; + ENGINE* engine = NULL; - // Per https://github.com/openssl/openssl/discussions/21427 - // using EVP_PKEY after freeing ENGINE is correct. - engine = ENGINE_by_id(engineName); + // Per https://github.com/openssl/openssl/discussions/21427 + // using EVP_PKEY after freeing ENGINE is correct. + engine = ENGINE_by_id(engineName); - if (engine != NULL) - { - if (ENGINE_init(engine)) + if (engine != NULL) { - ret = load_func(engine, keyName, NULL, NULL); + if (ENGINE_init(engine)) + { + ret = load_func(engine, keyName, NULL, NULL); + + ENGINE_finish(engine); + } - ENGINE_finish(engine); + ENGINE_free(engine); } - ENGINE_free(engine); + return ret; } - return ret; + *haveEngine = 0; + return NULL; } +#endif -EVP_PKEY* CryptoNative_LoadPrivateKeyFromEngine(const char* engineName, const char* keyName) +EVP_PKEY* CryptoNative_LoadPrivateKeyFromEngine(const char* engineName, const char* keyName, int32_t* haveEngine) { - return LoadKeyFromEngine(engineName, keyName, ENGINE_load_private_key); +#if HAVE_OPENSSL_ENGINE + if (API_EXISTS(ENGINE_load_private_key)) + { + return LoadKeyFromEngine(engineName, keyName, ENGINE_load_private_key, haveEngine); + } +#endif + (void)engineName; + (void)keyName; + (void)haveEngine; + *haveEngine = 0; + return NULL; } -EVP_PKEY* CryptoNative_LoadPublicKeyFromEngine(const char* engineName, const char* keyName) +EVP_PKEY* CryptoNative_LoadPublicKeyFromEngine(const char* engineName, const char* keyName, int32_t* haveEngine) { - return LoadKeyFromEngine(engineName, keyName, ENGINE_load_public_key); +#if HAVE_OPENSSL_ENGINE + if (API_EXISTS(ENGINE_load_private_key)) + { + return LoadKeyFromEngine(engineName, keyName, ENGINE_load_public_key, haveEngine); + } +#endif + (void)engineName; + (void)keyName; + (void)haveEngine; + *haveEngine = 0; + return NULL; } diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h index 64d289dc6f488..e4d5f85d4b9ec 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h +++ b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h @@ -93,12 +93,14 @@ PALEXPORT int32_t CryptoNative_EncodeSubjectPublicKeyInfo(EVP_PKEY* pkey, uint8_ Load a named key, via ENGINE_load_private_key, from the named engine. Returns a valid EVP_PKEY* on success, NULL on failure. +haveEngine is 1 if OpenSSL ENGINE's are supported, otherwise 0. */ -PALEXPORT EVP_PKEY* CryptoNative_LoadPrivateKeyFromEngine(const char* engineName, const char* keyName); +PALEXPORT EVP_PKEY* CryptoNative_LoadPrivateKeyFromEngine(const char* engineName, const char* keyName, int32_t* haveEngine); /* Load a named key, via ENGINE_load_public_key, from the named engine. Returns a valid EVP_PKEY* on success, NULL on failure. +haveEngine is 1 if OpenSSL ENGINE's are supported, otherwise 0. */ -PALEXPORT EVP_PKEY* CryptoNative_LoadPublicKeyFromEngine(const char* engineName, const char* keyName); +PALEXPORT EVP_PKEY* CryptoNative_LoadPublicKeyFromEngine(const char* engineName, const char* keyName, int32_t* haveEngine); diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonBuilderHelper.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonBuilderHelper.cs index 07c05113ac843..748283e74e673 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonBuilderHelper.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonBuilderHelper.cs @@ -10,7 +10,7 @@ namespace Microsoft.NET.Sdk.WebAssembly { - public class BootJsonBuilderHelper(TaskLoggingHelper Log) + public class BootJsonBuilderHelper(TaskLoggingHelper Log, string DebugLevel, bool IsPublish) { public void ComputeResourcesHash(BootJsonData bootConfig) { @@ -73,5 +73,35 @@ static void AddDictionary(StringBuilder sb, Dictionary? res) return null; } + + public int GetDebugLevel(bool hasPdb) + { + int? debugLevel = ParseOptionalInt(DebugLevel); + + // If user didn't give us a value, check if we have any PDB. + if (debugLevel == null && hasPdb) + debugLevel = -1; + + // Fallback to -1 for build, or 0 for publish + debugLevel ??= IsPublish ? 0 : -1; + + return debugLevel.Value; + } + + public bool? ParseOptionalBool(string value) + { + if (string.IsNullOrEmpty(value) || !bool.TryParse(value, out var boolValue)) + return null; + + return boolValue; + } + + public int? ParseOptionalInt(string value) + { + if (string.IsNullOrEmpty(value) || !int.TryParse(value, out var intValue)) + return null; + + return intValue; + } } } diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs index ef42b6fa952f1..3f12c54e07f9c 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs @@ -71,6 +71,8 @@ public class GenerateWasmBootJson : Task public ITaskItem[] LazyLoadedAssemblies { get; set; } + public bool IsPublish { get; set; } + public override bool Execute() { using var fileStream = File.Create(OutputPath); @@ -91,17 +93,16 @@ public override bool Execute() // Internal for tests public void WriteBootJson(Stream output, string entryAssemblyName) { - var helper = new BootJsonBuilderHelper(Log); + var helper = new BootJsonBuilderHelper(Log, DebugLevel, IsPublish); var result = new BootJsonData { resources = new ResourcesData(), - startupMemoryCache = ParseOptionalBool(StartupMemoryCache), + startupMemoryCache = helper.ParseOptionalBool(StartupMemoryCache), }; if (IsTargeting80OrLater()) { - result.debugLevel = ParseOptionalInt(DebugLevel) ?? (DebugBuild ? 1 : 0); result.mainAssemblyName = entryAssemblyName; result.globalizationMode = GetGlobalizationMode().ToString().ToLowerInvariant(); @@ -127,7 +128,7 @@ public void WriteBootJson(Stream output, string entryAssemblyName) result.runtimeOptions = runtimeOptions; } - bool? jiterpreter = ParseOptionalBool(Jiterpreter); + bool? jiterpreter = helper.ParseOptionalBool(Jiterpreter); if (jiterpreter != null) { var runtimeOptions = result.runtimeOptions?.ToHashSet() ?? new HashSet(3); @@ -329,6 +330,20 @@ public void WriteBootJson(Stream output, string entryAssemblyName) } } + if (IsTargeting80OrLater()) + { + int? debugLevel = helper.ParseOptionalInt(DebugLevel); + + // If user didn't give us a value, check if we have any PDB. + if (debugLevel == null && result.resources?.pdb?.Count > 0) + debugLevel = -1; + + // Fallback to -1 for build, or 0 for publish + debugLevel ??= IsPublish ? 0 : -1; + + result.debugLevel = debugLevel.Value; + } + if (ConfigurationFiles != null) { foreach (var configFile in ConfigurationFiles) @@ -394,22 +409,6 @@ private GlobalizationMode GetGlobalizationMode() return GlobalizationMode.Sharded; } - private static bool? ParseOptionalBool(string value) - { - if (string.IsNullOrEmpty(value) || !bool.TryParse(value, out var boolValue)) - return null; - - return boolValue; - } - - private static int? ParseOptionalInt(string value) - { - if (string.IsNullOrEmpty(value) || !int.TryParse(value, out var intValue)) - return null; - - return intValue; - } - private void AddToAdditionalResources(ITaskItem resource, Dictionary additionalResources, string resourceName, string behavior) { if (!additionalResources.ContainsKey(resourceName)) diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs index 9c7d8a6799134..d5e2aa53e1486 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs @@ -27,6 +27,8 @@ public class WasmAppBuilder : WasmAppBuilderBaseTask public bool WasmIncludeFullIcuData { get; set; } public string? WasmIcuDataFileName { get; set; } public string? RuntimeAssetsLocation { get; set; } + public string? DebugLevel { get; set; } + public bool IsPublish { get; set; } // // Extra json elements to add to _framework/blazor.boot.json @@ -83,7 +85,7 @@ private GlobalizationMode GetGlobalizationMode() protected override bool ExecuteInternal() { - var helper = new BootJsonBuilderHelper(Log); + var helper = new BootJsonBuilderHelper(Log, DebugLevel!, IsPublish); if (!ValidateArguments()) return false; @@ -115,6 +117,8 @@ protected override bool ExecuteInternal() if (UseWebcil) Log.LogMessage(MessageImportance.Normal, "Converting assemblies to Webcil"); + int baseDebugLevel = helper.GetDebugLevel(false); + foreach (var assembly in _assemblies) { if (UseWebcil) @@ -133,7 +137,7 @@ protected override bool ExecuteInternal() { FileCopyChecked(assembly, Path.Combine(runtimeAssetsPath, Path.GetFileName(assembly)), "Assemblies"); } - if (DebugLevel != 0) + if (baseDebugLevel != 0) { var pdb = assembly; pdb = Path.ChangeExtension(pdb, ".pdb"); @@ -191,7 +195,7 @@ protected override bool ExecuteInternal() } bootConfig.resources.assembly[Path.GetFileName(assemblyPath)] = Utils.ComputeIntegrity(bytes); - if (DebugLevel != 0) + if (baseDebugLevel != 0) { var pdb = Path.ChangeExtension(assembly, ".pdb"); if (File.Exists(pdb)) @@ -205,7 +209,7 @@ protected override bool ExecuteInternal() } } - bootConfig.debugLevel = DebugLevel; + bootConfig.debugLevel = helper.GetDebugLevel(bootConfig.resources.pdb?.Count > 0); ProcessSatelliteAssemblies(args => { diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilderBaseTask.cs b/src/tasks/WasmAppBuilder/WasmAppBuilderBaseTask.cs index c533e404c4173..feee565ad4f6c 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilderBaseTask.cs +++ b/src/tasks/WasmAppBuilder/WasmAppBuilderBaseTask.cs @@ -36,7 +36,6 @@ public abstract class WasmAppBuilderBaseTask : Task // https://github.com/dotnet/icu/tree/maint/maint-67/icu-filters public string[] IcuDataFileNames { get; set; } = Array.Empty(); - public int DebugLevel { get; set; } public ITaskItem[] SatelliteAssemblies { get; set; } = Array.Empty(); public bool HybridGlobalization { get; set; } public bool InvariantGlobalization { get; set; } diff --git a/src/tasks/WasmAppBuilder/wasi/WasiAppBuilder.cs b/src/tasks/WasmAppBuilder/wasi/WasiAppBuilder.cs index 0974904e6627b..521284dd56c77 100644 --- a/src/tasks/WasmAppBuilder/wasi/WasiAppBuilder.cs +++ b/src/tasks/WasmAppBuilder/wasi/WasiAppBuilder.cs @@ -11,6 +11,7 @@ namespace Microsoft.WebAssembly.Build.Tasks; public class WasiAppBuilder : WasmAppBuilderBaseTask { public bool IsSingleFileBundle { get; set; } + public bool OutputSymbolsToAppBundle { get; set; } protected override bool ValidateArguments() { @@ -53,7 +54,7 @@ protected override bool ExecuteInternal() { FileCopyChecked(assembly, Path.Combine(asmRootPath, Path.GetFileName(assembly)), "Assemblies"); - if (DebugLevel != 0) + if (OutputSymbolsToAppBundle) { string pdb = Path.ChangeExtension(assembly, ".pdb"); if (File.Exists(pdb)) diff --git a/src/tests/JIT/Directed/tls/CMakeLists.txt b/src/tests/JIT/Directed/tls/CMakeLists.txt new file mode 100644 index 0000000000000..3eaf0d3b22a0c --- /dev/null +++ b/src/tests/JIT/Directed/tls/CMakeLists.txt @@ -0,0 +1,8 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. + +include_directories(${INC_PLATFORM_DIR}) + +add_library(usetls SHARED testtls.cpp) + +install (TARGETS usetls DESTINATION bin) diff --git a/src/tests/JIT/Directed/tls/TestTLSWithLoadedDlls.cs b/src/tests/JIT/Directed/tls/TestTLSWithLoadedDlls.cs new file mode 100644 index 0000000000000..18385bb14cd61 --- /dev/null +++ b/src/tests/JIT/Directed/tls/TestTLSWithLoadedDlls.cs @@ -0,0 +1,130 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + + +// This test is verifying that the runtime properly handles the cases where the TLS infra in the runtime is forced +// to use a dynamic resolver. This is done by means of a private config variable to validate the behavior on Linux Arm64 +// and a set of multithreaded tasks, that has been known to cause the runtime to crash when this is handled incorrectly. + +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Loader; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace TestTLSWithLoadedDlls +{ + static class TLSWithLoadedDlls + { + private const int CountOfLibTlsToLoad = 40; + + static async Task DoLotsOfAsyncWork(int loopCount) + { + for (int i = 0; i < loopCount; i++) + { + Console.WriteLine("Starting a new batch of tasks..."); + var tasks = Enumerable.Range(1, 100).Select(i => Task.Run(async () => + { + await Task.Delay(1); + })).ToArray(); + + await Task.WhenAll(tasks); + + Console.WriteLine("Batch of tasks completed. Main loop sleeping for 20 ms..."); + await Task.Delay(20); + } + } + + static int Main(string[] args) + { + if ((args.Length == 1) && (args[0] == "RunLotsOfTasks")) + { + DoLotsOfAsyncWork(100).GetAwaiter().GetResult(); + return 100; + } + + int CountOfLibTlsToLoad = 60; + + if (OperatingSystem.IsWindows()) // Windows does not have a really long command line length limit, and doesn't have a problem with many TLS using images used + CountOfLibTlsToLoad = 10; + + StringBuilder arguments = new(); + + (string prefix, string suffix) = GetSharedLibraryPrefixSuffix(); + + string UseTlsFileName = GetSharedLibraryFileNameForCurrentPlatform("usetls"); + string testDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + string UseTlsFilePath = Path.Combine(testDirectory, UseTlsFileName); + + for (int i = 0; i < CountOfLibTlsToLoad; i++) + { + string tlsNumberSpecificPath = Path.Combine(testDirectory, i.ToString()); + string finalUseTlsPath = Path.Combine(tlsNumberSpecificPath, prefix + "usetls" + suffix); + + Directory.CreateDirectory(tlsNumberSpecificPath); + if (!File.Exists(finalUseTlsPath)) + { + File.Copy( + UseTlsFilePath, + finalUseTlsPath); + } + + arguments.Append(" -l "); + arguments.Append(finalUseTlsPath); + } + + arguments.Append(' '); + arguments.Append(System.Reflection.Assembly.GetExecutingAssembly().Location); + arguments.Append(" RunLotsOfTasks"); + + Process process = new Process(); + process.StartInfo.FileName = GetCorerunPath(); + process.StartInfo.Arguments = arguments.ToString(); + process.StartInfo.UseShellExecute = false; + process.StartInfo.EnvironmentVariables["DOTNET_AssertNotStaticTlsResolver"] = "1"; + + Console.WriteLine($"Launching {process.StartInfo.FileName} {process.StartInfo.Arguments}"); + + process.Start(); + process.WaitForExit(); + return process.ExitCode; + } + + private static string GetCorerunPath() + { + string corerunName; + if (OperatingSystem.IsWindows()) + { + corerunName = "CoreRun.exe"; + } + else + { + corerunName = "corerun"; + } + + return Path.Combine(Environment.GetEnvironmentVariable("CORE_ROOT"), corerunName); + } + + public static (string, string) GetSharedLibraryPrefixSuffix() + { + if (OperatingSystem.IsWindows()) + return (string.Empty, ".dll"); + + if (OperatingSystem.IsMacOS()) + return ("lib", ".dylib"); + + return ("lib", ".so"); + } + + public static string GetSharedLibraryFileNameForCurrentPlatform(string libraryName) + { + (string prefix, string suffix) = GetSharedLibraryPrefixSuffix(); + return prefix + libraryName + suffix; + } + } +} diff --git a/src/tests/JIT/Directed/tls/TestTLSWithLoadedDlls.csproj b/src/tests/JIT/Directed/tls/TestTLSWithLoadedDlls.csproj new file mode 100644 index 0000000000000..c17a210af0c9d --- /dev/null +++ b/src/tests/JIT/Directed/tls/TestTLSWithLoadedDlls.csproj @@ -0,0 +1,16 @@ + + + 0 + true + false + true + + + PdbOnly + True + + + + + + diff --git a/src/tests/JIT/Directed/tls/testtls.cpp b/src/tests/JIT/Directed/tls/testtls.cpp new file mode 100644 index 0000000000000..24dfbe5d0af2c --- /dev/null +++ b/src/tests/JIT/Directed/tls/testtls.cpp @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifdef _MSC_VER +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT __attribute__((visibility("default"))) +#endif // _MSC_VER + +thread_local int tls0; +thread_local int tls1; +thread_local int tls2; +thread_local int tls3; +thread_local int tls4; +thread_local int tls5; +thread_local int tls6; +thread_local int tls7; +thread_local int tls8; +thread_local int tls9; +thread_local int tls10; +thread_local int tls11; +thread_local int tls12; +thread_local int tls13; +thread_local int tls14; +thread_local int tls15; +thread_local int tls16; + +extern "C" DLLEXPORT void initializeTLS() { + tls0=0; + tls1=0; + tls2=0; + tls3=0; + tls4=0; + tls5=0; + tls6=0; + tls7=0; + tls8=0; + tls9=0; + tls10=0; + tls11=0; + tls12=0; + tls13=0; + tls14=0; + tls15=0; + tls16=0; +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_96156/Runtime_96156.cs b/src/tests/JIT/Regression/JitBlue/Runtime_96156/Runtime_96156.cs new file mode 100644 index 0000000000000..15fe1b0f93842 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_96156/Runtime_96156.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_96156 +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe static Vector128 BroadcastScalarToVector128(float value) + { + return Avx.BroadcastScalarToVector128(&value); + } + + [Fact] + public static void TestEntryPoint() + { + if (Avx.IsSupported) + { + Vector128 c = Vector128.Create(1.0f); + Vector128 r = Problem(2.0f, 0.5f, c); + Assert.Equal(Vector128.Create(4.0f), r); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector128 Problem(float a, float b, Vector128 c) + { + return Avx.Multiply(c, BroadcastScalarToVector128(a / b)); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_96156/Runtime_96156.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_96156/Runtime_96156.csproj new file mode 100644 index 0000000000000..37d1a42b02dbe --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_96156/Runtime_96156.csproj @@ -0,0 +1,13 @@ + + + True + True + + + + + + + + + diff --git a/src/tests/profiler/native/profiler.def b/src/tests/profiler/native/profiler.def index 37a59858dbfe0..11976272a2133 100644 --- a/src/tests/profiler/native/profiler.def +++ b/src/tests/profiler/native/profiler.def @@ -5,4 +5,5 @@ EXPORTS DllCanUnloadNow PRIVATE PassCallbackToProfiler PRIVATE DoPInvoke PRIVATE + DoPInvokeWithCallbackOnOtherThread PRIVATE diff --git a/src/tests/profiler/native/transitions/transitions.cpp b/src/tests/profiler/native/transitions/transitions.cpp index 13984e0837cb2..3966c887440e9 100644 --- a/src/tests/profiler/native/transitions/transitions.cpp +++ b/src/tests/profiler/native/transitions/transitions.cpp @@ -69,6 +69,14 @@ extern "C" EXPORT void STDMETHODCALLTYPE DoPInvoke(int(*callback)(int), int i) printf("PInvoke received i=%d\n", callback(i)); } +extern "C" EXPORT void STDMETHODCALLTYPE DoPInvokeWithCallbackOnOtherThread(int(*callback)(int), int i) +{ + int j = 0; + std::thread t([&j, callback, i] { j = callback(i); }); + t.join(); + printf("PInvoke with callback on other thread received i=%d\n", j); +} + HRESULT Transitions::UnmanagedToManagedTransition(FunctionID functionID, COR_PRF_TRANSITION_REASON reason) { @@ -124,4 +132,4 @@ bool Transitions::FunctionIsTargetFunction(FunctionID functionID, TransitionInst } return true; -} \ No newline at end of file +} diff --git a/src/tests/profiler/transitions/transitions.cs b/src/tests/profiler/transitions/transitions.cs index b513d9c7717de..d0d6a7df67825 100644 --- a/src/tests/profiler/transitions/transitions.cs +++ b/src/tests/profiler/transitions/transitions.cs @@ -32,7 +32,7 @@ private static int DoDelegateReversePInvokeNonBlittable(bool b) public static int BlittablePInvokeToBlittableInteropDelegate() { InteropDelegate del = DoDelegateReversePInvoke; - + DoPInvoke((delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(del), 13); GC.KeepAlive(del); @@ -42,13 +42,23 @@ public static int BlittablePInvokeToBlittableInteropDelegate() public static int NonBlittablePInvokeToNonBlittableInteropDelegate() { InteropDelegateNonBlittable del = DoDelegateReversePInvokeNonBlittable; - + DoPInvokeNonBlitable((delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(del), true); GC.KeepAlive(del); return 100; } + public static int BlittablePInvokeToBlittableInteropDelegateOnOtherThread() + { + InteropDelegate del = DoDelegateReversePInvoke; + + DoPInvokeWithCallbackOnOtherThread((delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(del), 13); + GC.KeepAlive(del); + + return 100; + } + [UnmanagedCallersOnly] private static int DoReversePInvoke(int i) { @@ -61,6 +71,9 @@ private static int DoReversePInvoke(int i) [DllImport("Profiler", EntryPoint = nameof(DoPInvoke))] public static extern void DoPInvokeNonBlitable(delegate* unmanaged callback, bool i); + [DllImport("Profiler")] + public static extern void DoPInvokeWithCallbackOnOtherThread(delegate* unmanaged callback, int i); + public static int BlittablePInvokeToUnmanagedCallersOnly() { DoPInvoke(&DoReversePInvoke, 13); @@ -75,6 +88,13 @@ public static int NonBlittablePInvokeToUnmanagedCallersOnly() return 100; } + public static int BlittablePInvokeToUnmanagedCallersOnlyOnOtherThread() + { + DoPInvokeWithCallbackOnOtherThread(&DoReversePInvoke, 13); + + return 100; + } + public static int Main(string[] args) { if (args.Length > 1 && args[0].Equals("RunTest", StringComparison.OrdinalIgnoreCase)) @@ -89,6 +109,10 @@ public static int Main(string[] args) return NonBlittablePInvokeToUnmanagedCallersOnly(); case nameof(NonBlittablePInvokeToNonBlittableInteropDelegate): return NonBlittablePInvokeToNonBlittableInteropDelegate(); + case nameof(BlittablePInvokeToUnmanagedCallersOnlyOnOtherThread): + return BlittablePInvokeToUnmanagedCallersOnlyOnOtherThread(); + case nameof(BlittablePInvokeToBlittableInteropDelegateOnOtherThread): + return BlittablePInvokeToBlittableInteropDelegateOnOtherThread(); } } @@ -104,12 +128,22 @@ public static int Main(string[] args) if (!RunProfilerTest(nameof(NonBlittablePInvokeToUnmanagedCallersOnly), nameof(DoPInvokeNonBlitable), nameof(DoReversePInvoke))) { - return 101; + return 103; } if (!RunProfilerTest(nameof(NonBlittablePInvokeToNonBlittableInteropDelegate), nameof(DoPInvokeNonBlitable), "Invoke")) { - return 102; + return 104; + } + + if (!RunProfilerTest(nameof(BlittablePInvokeToUnmanagedCallersOnlyOnOtherThread), nameof(DoPInvokeWithCallbackOnOtherThread), nameof(DoReversePInvoke))) + { + return 105; + } + + if (!RunProfilerTest(nameof(BlittablePInvokeToBlittableInteropDelegateOnOtherThread), nameof(DoPInvokeWithCallbackOnOtherThread), "Invoke")) + { + return 106; } return 100;