diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 058644afd46753..3bff7a26fb1843 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "9.0.0-prerelease.25113.3", + "version": "9.0.0-prerelease.25375.3", "commands": [ "xharness" ] diff --git a/.github/workflows/check-no-merge-label.yml b/.github/workflows/check-no-merge-label.yml index d503400b0e154c..a0bb075db84312 100644 --- a/.github/workflows/check-no-merge-label.yml +++ b/.github/workflows/check-no-merge-label.yml @@ -5,7 +5,7 @@ permissions: on: pull_request_target: - types: [opened, reopened, labeled, unlabeled] + types: [opened, edited, reopened, labeled, unlabeled, synchronize] branches: - 'release/**' diff --git a/.github/workflows/check-service-labels.yml b/.github/workflows/check-service-labels.yml index c158ff6f1520d6..f2e800feea5bcf 100644 --- a/.github/workflows/check-service-labels.yml +++ b/.github/workflows/check-service-labels.yml @@ -5,7 +5,7 @@ permissions: on: pull_request_target: - types: [opened, reopened, labeled, unlabeled] + types: [opened, edited, reopened, labeled, unlabeled, synchronize] branches: - 'release/**' diff --git a/NuGet.config b/NuGet.config index deafa2a01414c9..52627ab5e8c7a3 100644 --- a/NuGet.config +++ b/NuGet.config @@ -9,10 +9,12 @@ - + + + + - - + https://github.com/dotnet/cecil - 8debcd23b73a27992a5fdb2229f546e453619d11 + 788a8a7481c01a7d235110cdea2ca5bfb34210d4 - + https://github.com/dotnet/emsdk - 78be8cdf4f0bfd93018fd7a87f8282a41d041298 + dc8e3478c4aa5f6a103329333c2bdbcd07a07741 - + https://github.com/dotnet/emsdk - 78be8cdf4f0bfd93018fd7a87f8282a41d041298 + dc8e3478c4aa5f6a103329333c2bdbcd07a07741 - + https://github.com/dotnet/emsdk - 78be8cdf4f0bfd93018fd7a87f8282a41d041298 + dc8e3478c4aa5f6a103329333c2bdbcd07a07741 - + https://github.com/dotnet/source-build-reference-packages - 1cec3b4a8fb07138136a1ca1e04763bfcf7841db + 9859d82ffce48f49b5e93fa46a38bdddc4ba26be @@ -92,195 +92,195 @@ - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 - + https://github.com/dotnet/llvm-project - f98a0db595fe3f28dac4594acc7114b16281d090 + 5ad97991b0fc050c73bc3d49d425b1a0fbb8d8d2 https://github.com/dotnet/runtime @@ -320,21 +320,21 @@ https://github.com/dotnet/runtime b030c4dfdfa1bf287f10f96006619a06bc2000ae - + https://github.com/dotnet/xharness - edc52ac68c1bf77e3b107fc8a448674a6d058d8a + 604c13925074041a51e4533959477c8b6888dcf5 - + https://github.com/dotnet/xharness - edc52ac68c1bf77e3b107fc8a448674a6d058d8a + 604c13925074041a51e4533959477c8b6888dcf5 - + https://github.com/dotnet/xharness - edc52ac68c1bf77e3b107fc8a448674a6d058d8a + 604c13925074041a51e4533959477c8b6888dcf5 - + https://github.com/dotnet/arcade - f33d9e642f0e68a61312164cd9e0baf4e142a999 + 1a2e280a031aaed0dca606ec8c59c6fe0f9bfc7f https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -352,48 +352,48 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 9d7532585ce71e30ab55f0364d3cecccaf0775d1 - + https://github.com/dotnet/hotreload-utils - fd21b154f1152569e7fa49a4e030927eccbf4aaa + 3eb23e965fcc8cf3f6bec6e3e2543a81e52b6d20 - + https://github.com/dotnet/runtime-assets - 739921bd3405841c06d3f74701c9e6ccfbd19e2e + c77fd5058ea46e9d0b58f5c11b6808d6170e4e32 - + https://github.com/dotnet/roslyn - 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 + 5f78534e8ac55b615a3540e7c1ffedee9ced6e1e - + https://github.com/dotnet/roslyn - 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 + 5f78534e8ac55b615a3540e7c1ffedee9ced6e1e - + https://github.com/dotnet/roslyn - 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 + 5f78534e8ac55b615a3540e7c1ffedee9ced6e1e - + https://github.com/dotnet/roslyn-analyzers 16865ea61910500f1022ad2b96c499e5df02c228 - + https://github.com/dotnet/roslyn-analyzers 16865ea61910500f1022ad2b96c499e5df02c228 - + https://github.com/dotnet/roslyn - 3f5cf9fbbd91f2047e988801a5142ca1cb6bab45 + 5f78534e8ac55b615a3540e7c1ffedee9ced6e1e - + https://github.com/dotnet/sdk - 346d06baea1cf7113e181e779b056b955973c633 + 8128984181a05a7dc0de748ad3371e0a7f153f35 - + https://github.com/dotnet/sdk - 346d06baea1cf7113e181e779b056b955973c633 + 8128984181a05a7dc0de748ad3371e0a7f153f35 diff --git a/eng/Versions.props b/eng/Versions.props index 8ba353723841c2..64002194d43947 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,11 +1,11 @@ - 9.0.4 + 9.0.9 9 0 - 4 + 9 9.0.100 8.0.$([MSBuild]::Add($(PatchVersion),11)) 7.0.20 @@ -36,17 +36,17 @@ - 3.11.0-beta1.25123.3 - 9.0.0-preview.25123.3 + 3.11.0-beta1.25173.3 + 9.0.0-preview.25173.3 - 4.12.0-3.25124.2 - 4.12.0-3.25124.2 - 4.12.0-3.25124.2 + 4.12.0-3.25377.4 + 4.12.0-3.25377.4 + 4.12.0-3.25377.4 - 9.0.104 + 9.0.109 - 9.0.0-beta.25161.4 - 9.0.0-beta.25161.4 - 9.0.0-beta.25161.4 - 9.0.0-beta.25161.4 - 2.9.0-beta.25161.4 - 9.0.0-beta.25161.4 - 2.9.0-beta.25161.4 - 9.0.0-beta.25161.4 - 9.0.0-beta.25161.4 - 9.0.0-beta.25161.4 - 9.0.0-beta.25161.4 - 9.0.0-beta.25161.4 - 9.0.0-beta.25161.4 - 9.0.0-beta.25161.4 - 9.0.0-beta.25161.4 - 9.0.0-beta.25161.4 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 2.9.0-beta.25366.1 + 9.0.0-beta.25366.1 + 2.9.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 + 9.0.0-beta.25366.1 1.4.0 @@ -141,20 +141,20 @@ 8.0.0 8.0.0 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 - 9.0.0-beta.25113.2 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 + 9.0.0-beta.25313.1 1.0.0-prerelease.24462.2 1.0.0-prerelease.24462.2 @@ -184,10 +184,10 @@ 1.4.0 17.4.0-preview-20220707-01 - 9.0.0-prerelease.25113.3 - 9.0.0-prerelease.25113.3 - 9.0.0-prerelease.25113.3 - 9.0.0-alpha.0.25153.2 + 9.0.0-prerelease.25375.3 + 9.0.0-prerelease.25375.3 + 9.0.0-prerelease.25375.3 + 9.0.0-alpha.0.25330.3 3.12.0 4.5.0 6.0.0 @@ -215,55 +215,55 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25112.2 + 0.11.5-alpha.25370.2 9.0.0-rtm.24511.16 - 9.0.0-rtm.25157.1 + 9.0.0-rtm.25371.1 9.0.0-rtm.24466.4 2.4.8 9.0.0-alpha.1.24167.3 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 - 9.0.4-servicing.25157.2 - 9.0.4 + 9.0.9-servicing.25418.4 + 9.0.9 $(MicrosoftNETWorkloadEmscriptenCurrentManifest90100Version) 1.1.87-gba258badda 1.0.0-v3.14.0.5722 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 - 19.1.0-alpha.1.25113.2 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 + 19.1.0-alpha.1.25414.3 3.1.7 1.0.406601 - $(MicrosoftDotNetApiCompatTaskVersion) - + + 9.0.107 9.0.0-alpha.1.24175.1 $(MicrosoftNETRuntimeEmscriptenVersion) $(runtimewinx64MicrosoftNETCoreRuntimeWasmNodeTransportPackageVersion) diff --git a/eng/common/core-templates/job/job.yml b/eng/common/core-templates/job/job.yml index ba53ebfbd51334..abe80a2a0e09c9 100644 --- a/eng/common/core-templates/job/job.yml +++ b/eng/common/core-templates/job/job.yml @@ -134,6 +134,10 @@ jobs: signType: $(_SignType) zipSources: false feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json + ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: + ConnectedPMEServiceName: 6cc74545-d7b9-4050-9dfa-ebefcc8961ea + ${{ else }}: + ConnectedPMEServiceName: 248d384a-b39b-46e3-8ad5-c2c210d5e7ca env: TeamName: $(_TeamName) MicroBuildOutputFolderOverride: '$(Agent.TempDirectory)' diff --git a/eng/common/core-templates/job/source-build.yml b/eng/common/core-templates/job/source-build.yml index c4713c8b6ede8a..d47f09d58fd9a8 100644 --- a/eng/common/core-templates/job/source-build.yml +++ b/eng/common/core-templates/job/source-build.yml @@ -26,6 +26,8 @@ parameters: # Specifies the build script to invoke to perform the build in the repo. The default # './build.sh' should work for typical Arcade repositories, but this is customizable for # difficult situations. + # buildArguments: '' + # Specifies additional build arguments to pass to the build script. # jobProperties: {} # A list of job properties to inject at the top level, for potential extensibility beyond # container and pool. diff --git a/eng/common/core-templates/job/source-index-stage1.yml b/eng/common/core-templates/job/source-index-stage1.yml index 205fb5b3a39563..8b833332b3ee96 100644 --- a/eng/common/core-templates/job/source-index-stage1.yml +++ b/eng/common/core-templates/job/source-index-stage1.yml @@ -1,7 +1,7 @@ parameters: runAsPublic: false - sourceIndexUploadPackageVersion: 2.0.0-20240522.1 - sourceIndexProcessBinlogPackageVersion: 1.0.1-20240522.1 + sourceIndexUploadPackageVersion: 2.0.0-20250425.2 + sourceIndexProcessBinlogPackageVersion: 1.0.1-20250425.2 sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" preSteps: [] diff --git a/eng/common/core-templates/post-build/post-build.yml b/eng/common/core-templates/post-build/post-build.yml index 454fd75c7aff19..a8c0bd3b9214e5 100644 --- a/eng/common/core-templates/post-build/post-build.yml +++ b/eng/common/core-templates/post-build/post-build.yml @@ -44,6 +44,11 @@ parameters: displayName: Publish installers and checksums type: boolean default: true + + - name: requireDefaultChannels + displayName: Fail the build if there are no default channel(s) registrations for the current build + type: boolean + default: false - name: SDLValidationParameters type: object @@ -312,5 +317,6 @@ stages: -PublishingInfraVersion ${{ parameters.publishingInfraVersion }} -AzdoToken '$(System.AccessToken)' -WaitPublishingFinish true + -RequireDefaultChannels ${{ parameters.requireDefaultChannels }} -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}' -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}' diff --git a/eng/common/core-templates/steps/source-build.yml b/eng/common/core-templates/steps/source-build.yml index 2915d29bb7f6e6..37133b55b7541b 100644 --- a/eng/common/core-templates/steps/source-build.yml +++ b/eng/common/core-templates/steps/source-build.yml @@ -79,6 +79,7 @@ steps: ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ --configuration $buildConfig \ --restore --build --pack $publishArgs -bl \ + ${{ parameters.platform.buildArguments }} \ $officialBuildArgs \ $internalRuntimeDownloadArgs \ $internalRestoreArgs \ diff --git a/eng/common/internal/NuGet.config b/eng/common/internal/NuGet.config index 19d3d311b166f5..f70261ed689bce 100644 --- a/eng/common/internal/NuGet.config +++ b/eng/common/internal/NuGet.config @@ -4,4 +4,7 @@ + + + diff --git a/eng/common/post-build/publish-using-darc.ps1 b/eng/common/post-build/publish-using-darc.ps1 index 90b58e32a87bfb..a261517ef90679 100644 --- a/eng/common/post-build/publish-using-darc.ps1 +++ b/eng/common/post-build/publish-using-darc.ps1 @@ -5,7 +5,8 @@ param( [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro.dot.net', [Parameter(Mandatory=$true)][string] $WaitPublishingFinish, [Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters, - [Parameter(Mandatory=$false)][string] $SymbolPublishingAdditionalParameters + [Parameter(Mandatory=$false)][string] $SymbolPublishingAdditionalParameters, + [Parameter(Mandatory=$false)][string] $RequireDefaultChannels ) try { @@ -33,6 +34,10 @@ try { if ("false" -eq $WaitPublishingFinish) { $optionalParams.Add("--no-wait") | Out-Null } + + if ("true" -eq $RequireDefaultChannels) { + $optionalParams.Add("--default-channels-required") | Out-Null + } & $darc add-build-to-channel ` --id $buildId ` diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index a46b6deb75986b..9b3ad8840fdb28 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -42,7 +42,7 @@ [bool]$useInstalledDotNetCli = if (Test-Path variable:useInstalledDotNetCli) { $useInstalledDotNetCli } else { $true } # Enable repos to use a particular version of the on-line dotnet-install scripts. -# default URL: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.ps1 +# default URL: https://builds.dotnet.microsoft.com/dotnet/scripts/v1/dotnet-install.ps1 [string]$dotnetInstallScriptVersion = if (Test-Path variable:dotnetInstallScriptVersion) { $dotnetInstallScriptVersion } else { 'v1' } # True to use global NuGet cache instead of restoring packages to repository-local directory. @@ -262,7 +262,7 @@ function GetDotNetInstallScript([string] $dotnetRoot) { if (!(Test-Path $installScript)) { Create-Directory $dotnetRoot $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit - $uri = "https://dotnet.microsoft.com/download/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.ps1" + $uri = "https://builds.dotnet.microsoft.com/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.ps1" Retry({ Write-Host "GET $uri" @@ -416,7 +416,7 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = # Locate Visual Studio installation or download x-copy msbuild. $vsInfo = LocateVisualStudio $vsRequirements - if ($vsInfo -ne $null) { + if ($vsInfo -ne $null -and $env:ForceUseXCopyMSBuild -eq $null) { # Ensure vsInstallDir has a trailing slash $vsInstallDir = Join-Path $vsInfo.installationPath "\" $vsMajorVersion = $vsInfo.installationVersion.Split('.')[0] diff --git a/eng/common/tools.sh b/eng/common/tools.sh index 1159726a10fd6f..01b09b65796c17 100755 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -54,7 +54,7 @@ warn_as_error=${warn_as_error:-true} use_installed_dotnet_cli=${use_installed_dotnet_cli:-true} # Enable repos to use a particular version of the on-line dotnet-install scripts. -# default URL: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh +# default URL: https://builds.dotnet.microsoft.com/dotnet/scripts/v1/dotnet-install.sh dotnetInstallScriptVersion=${dotnetInstallScriptVersion:-'v1'} # True to use global NuGet cache instead of restoring packages to repository-local directory. @@ -295,7 +295,7 @@ function with_retries { function GetDotNetInstallScript { local root=$1 local install_script="$root/dotnet-install.sh" - local install_script_url="https://dotnet.microsoft.com/download/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.sh" + local install_script_url="https://builds.dotnet.microsoft.com/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.sh" if [[ ! -a "$install_script" ]]; then mkdir -p "$root" diff --git a/eng/pipelines/common/macos-sign-with-entitlements.yml b/eng/pipelines/common/macos-sign-with-entitlements.yml index 72a03b90f340d6..6a20a31481eb9d 100644 --- a/eng/pipelines/common/macos-sign-with-entitlements.yml +++ b/eng/pipelines/common/macos-sign-with-entitlements.yml @@ -30,12 +30,13 @@ steps: - task: EsrpCodeSigning@5 displayName: 'ESRP CodeSigning' inputs: - ConnectedServiceName: 'DotNet-Engineering-Services_KeyVault' - AppRegistrationClientId: '28ec6507-2167-4eaa-a294-34408cf5dd0e' - AppRegistrationTenantId: '72f988bf-86f1-41af-91ab-2d7cd011db47' - AuthAKVName: 'EngKeyVault' - AuthCertName: 'DotNetCore-ESRP-AuthCert' - AuthSignCertName: 'DotNetCore-ESRP-AuthSignCert' + ConnectedServiceName: 'DotNetBuildESRP' + UseMSIAuthentication: true + EsrpClientId: '28ec6507-2167-4eaa-a294-34408cf5dd0e' + AppRegistrationClientId: '0ecbcdb7-8451-4cbe-940a-4ed97b08b955' + AppRegistrationTenantId: '975f013f-7f24-47e8-a7d3-abc4752bf346' + AuthAKVName: 'DotNetEngKeyVault' + AuthSignCertName: 'DotNet-ESRP-AuthSignCert' FolderPath: '$(Build.ArtifactStagingDirectory)/' Pattern: 'mac_entitled_to_sign.zip' UseMinimatch: true diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml index 90851b8d725ee6..b99d425f52b58f 100644 --- a/eng/pipelines/common/templates/pipeline-with-resources.yml +++ b/eng/pipelines/common/templates/pipeline-with-resources.yml @@ -21,11 +21,6 @@ extends: env: ROOTFS_DIR: /crossrootfs/arm - linux_armv6: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-cross-armv6-raspbian-10 - env: - ROOTFS_DIR: /crossrootfs/armv6 - linux_arm64: image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net9.0-cross-arm64 env: @@ -72,20 +67,19 @@ extends: image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04 linux_musl_x64_dev_innerloop: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.19-WithNode + image: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-amd64 linux_x64_sanitizer: image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net9.0-cross-amd64-sanitizer env: ROOTFS_DIR: /crossrootfs/x64 - # We use a CentOS Stream 8 image here to test building from source on CentOS Stream 8. + # We use a CentOS Stream image here to test building from source on CentOS Stream SourceBuild_centos_x64: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8 - + image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9 # AlmaLinux 8 is a RHEL 8 rebuild, so we use it to test building from source on RHEL 8. SourceBuild_linux_x64: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:almalinux-8-source-build + image: mcr.microsoft.com/dotnet-buildtools/prereqs:almalinux-9-source-build-amd64 linux_s390x: image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net9.0-cross-s390x @@ -106,7 +100,7 @@ extends: image: mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-gcc14-amd64 linux_x64_llvmaot: - image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9 browser_wasm: image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net9.0-webassembly-amd64 diff --git a/eng/pipelines/coreclr/templates/helix-queues-setup.yml b/eng/pipelines/coreclr/templates/helix-queues-setup.yml index 815f297ff3060f..4d05678f0b7293 100644 --- a/eng/pipelines/coreclr/templates/helix-queues-setup.yml +++ b/eng/pipelines/coreclr/templates/helix-queues-setup.yml @@ -34,11 +34,11 @@ jobs: # iOS Simulator/Mac Catalyst arm64 - ${{ if in(parameters.platform, 'maccatalyst_arm64', 'iossimulator_arm64') }}: - - OSX.1200.Arm64.Open + - OSX.14.Arm64.Open # iOS/tvOS Simulator x64 & MacCatalyst x64 - ${{ if in(parameters.platform, 'iossimulator_x64', 'tvossimulator_x64', 'maccatalyst_x64') }}: - - OSX.1200.Amd64.Open + - OSX.15.Amd64.Open # Android arm64 - ${{ if in(parameters.platform, 'android_arm64') }}: @@ -70,37 +70,37 @@ jobs: # Linux arm64 - ${{ if eq(parameters.platform, 'linux_arm64') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - (Ubuntu.2004.Arm64.Open)Ubuntu.2204.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-arm64v8 + - (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.2004.Arm64)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.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.321.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-amd64 + - (Alpine.322.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-amd64 - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - (Alpine.321.Amd64)Ubuntu.2204.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-amd64 + - (Alpine.322.Amd64)AzureLinux.3.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-amd64 # Linux musl arm32 - ${{ if eq(parameters.platform, 'linux_musl_arm') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - (Alpine.321.Arm32.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-arm32v7 + - (Alpine.322.Arm32.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-arm32v7 - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - (Alpine.321.Arm32)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-arm32v7 + - (Alpine.322.Arm32)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-arm32v7 # Linux musl arm64 - ${{ if eq(parameters.platform, 'linux_musl_arm64') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - (Alpine.320.Arm64.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.20-helix-arm64v8 + - (Alpine.322.Arm64.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-arm64v8 - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - (Alpine.320.Arm64)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.20-helix-arm64v8 + - (Alpine.322.Arm64)Ubuntu.2204.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-arm64v8 # Linux x64 - ${{ if eq(parameters.platform, 'linux_x64') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - Ubuntu.2204.Amd64.Open + - AzureLinux.3.Amd64.Open - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - Ubuntu.2204.Amd64 + - AzureLinux.3.Amd64 # OSX arm64 - ${{ if eq(parameters.platform, 'osx_arm64') }}: diff --git a/eng/pipelines/coreclr/templates/sign-diagnostic-files.yml b/eng/pipelines/coreclr/templates/sign-diagnostic-files.yml index 2e6ec556150b8f..64c8ff12e4cb2d 100644 --- a/eng/pipelines/coreclr/templates/sign-diagnostic-files.yml +++ b/eng/pipelines/coreclr/templates/sign-diagnostic-files.yml @@ -15,12 +15,12 @@ steps: - task: EsrpCodeSigning@5 displayName: Sign Diagnostic Binaries inputs: - ConnectedServiceName: 'diagnostics-esrp-kvcertuser' - AppRegistrationClientId: '2234cdec-a13f-4bb2-aa63-04c57fd7a1f9' - AppRegistrationTenantId: '72f988bf-86f1-41af-91ab-2d7cd011db47' - AuthAKVName: 'clrdiag-esrp-id' - AuthCertName: 'dotnetesrp-diagnostics-aad-ssl-cert' - AuthSignCertName: 'dotnet-diagnostics-esrp-pki-onecert' + ConnectedServiceName: 'diagnostics-esrp-kvcertuser-pme' + AppRegistrationClientId: '22346933-af99-4e94-97d5-7fa1dcf4bba6' + AppRegistrationTenantId: '975f013f-7f24-47e8-a7d3-abc4752bf346' + AuthAKVName: 'clrdiag-esrp-pme' + AuthCertName: 'dac-dnceng-ssl-cert' + AuthSignCertName: 'dac-dnceng-esrpclient-cert' FolderPath: ${{ parameters.basePath }} Pattern: | **/mscordaccore*.dll @@ -69,7 +69,7 @@ steps: } if ($signingCert.Subject -ne "CN=.NET DAC, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" ` - -or $signingCert.Issuer -ne "CN=Microsoft Code Signing PCA 2010, O=Microsoft Corporation, L=Redmond, S=Washington, C=US") + -or $signingCert.Issuer -ne "CN=Microsoft Windows Code Signing PCA 2024, O=Microsoft Corporation, C=US") { throw "File $file not in expected trust chain." } diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml index 9794c736e2e823..0e83d79eb382d8 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml @@ -37,10 +37,9 @@ jobs: isExtraPlatforms: ${{ parameters.isExtraPlatformsBuild }} # Don't trim tests on rolling builds ${{ if eq(variables['isRollingBuild'], true) }}: - buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg) /p:BuildTestsOnHelix=true /p:EnableAdditionalTimezoneChecks=true /p:UsePortableRuntimePack=true /p:BuildDarwinFrameworks=true /p:IsManualOrRollingBuild=true /p:EnableAggressiveTrimming=false + buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg) /p:BuildTestsOnHelix=true /p:EnableAdditionalTimezoneChecks=true /p:UsePortableRuntimePack=false /p:BuildDarwinFrameworks=true /p:IsManualOrRollingBuild=true /p:EnableAggressiveTrimming=false ${{ else }}: - # Tracking issue: https://github.com/dotnet/runtime/issues/82637 - buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg) /p:BuildTestsOnHelix=true /p:EnableAdditionalTimezoneChecks=true /p:UsePortableRuntimePack=true /p:BuildDarwinFrameworks=true /p:IsManualOrRollingBuild=true /p:EnableAggressiveTrimming=false + buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg) /p:BuildTestsOnHelix=true /p:EnableAdditionalTimezoneChecks=true /p:UsePortableRuntimePack=false /p:BuildDarwinFrameworks=true /p:IsManualOrRollingBuild=true /p:EnableAggressiveTrimming=true timeoutInMinutes: 480 # extra steps, run tests postBuildSteps: diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml index 7ce0a0c3568aac..75ad650c119d74 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml @@ -25,9 +25,7 @@ jobs: platforms: - iossimulator_x64 - tvossimulator_x64 - # don't run tests on arm64 PRs until we can get significantly more devices - - ${{ if eq(variables['isRollingBuild'], true) }}: - - iossimulator_arm64 + - iossimulator_arm64 variables: # map dependencies variables to local variables - name: librariesContainsChange @@ -61,9 +59,7 @@ jobs: platforms: - iossimulator_x64 - tvossimulator_x64 - # don't run tests on arm64 PRs until we can get significantly more devices - - ${{ if eq(variables['isRollingBuild'], true) }}: - - iossimulator_arm64 + - iossimulator_arm64 variables: - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: - name: _HelixSource @@ -109,9 +105,7 @@ jobs: platforms: - iossimulator_x64 - tvossimulator_x64 - # don't run tests on arm64 PRs until we can get significantly more devices - - ${{ if eq(variables['isRollingBuild'], true) }}: - - iossimulator_arm64 + - iossimulator_arm64 variables: - ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}: - name: _HelixSource diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index d6c83bd12137da..cb8447877b09d4 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -27,61 +27,49 @@ jobs: - ${{ if eq(parameters.platform, 'linux_arm') }}: - ${{ if or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - (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') }}: - - (Raspbian.10.Armv6.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:raspbian-10-helix-arm32v6 - # Linux arm64 - ${{ if eq(parameters.platform, 'linux_arm64') }}: - - (Ubuntu.2204.Arm64.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8 + - ${{ if or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: + - (Ubuntu.2204.ArmArch.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-arm64v8 - ${{ if or(ne(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Debian.11.Arm64.Open)Ubuntu.2204.Armarch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-arm64v8 + - (AzureLinux.3.0.ArmArch.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-helix-arm64v8 # Linux musl x64 - ${{ if eq(parameters.platform, 'linux_musl_x64') }}: - - ${{ if or(ne(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Alpine.321.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-amd64 - - ${{ if or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Alpine.321.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.21-helix-amd64 + - (Alpine.322.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-amd64 # Linux musl arm64 - - ${{ if and(eq(parameters.platform, 'linux_musl_arm64'), or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true))) }}: - - (Alpine.320.Arm64.Open)ubuntu.2004.armarch.open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.20-helix-arm64v8 + - ${{ if eq(parameters.platform, 'linux_musl_arm64') }}: + - ${{ if or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: + - (Alpine.322.Arm64.Open)Ubuntu.2204.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.22-helix-arm64v8 + # Linux x64 - ${{ if eq(parameters.platform, 'linux_x64') }}: - - ${{ if and(eq(parameters.jobParameters.interpreter, ''), ne(parameters.jobParameters.isSingleFile, true)) }}: - - ${{ if and(eq(parameters.jobParameters.testScope, 'outerloop'), eq(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - - SLES.15.Amd64.Open - - (Centos.8.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8-helix - - (Fedora.41.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-41-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 - - ${{ if or(ne(parameters.jobParameters.testScope, 'outerloop'), ne(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - - ${{ if or(eq(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - SLES.15.Amd64.Open - - (Fedora.41.Amd64.Open)ubuntu.2204.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-41-helix - - Ubuntu.2204.Amd64.Open - - (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 - - (AzureLinux.3.0.Amd64.Open)Ubuntu.2204.Amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.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.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - - (Centos.8.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8-helix - - (Debian.12.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 - - Ubuntu.2204.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 - - # Linux s390x - - ${{ if eq(parameters.platform, 'linux_s390x') }}: - - Ubuntu.2004.S390X.Experimental.Open - - # Linux PPC64le - - ${{ if eq(parameters.platform, 'linux_ppc64le') }}: - - Ubuntu.2204.PPC64le.Experimental.Open + - (Debian.12.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 + + - ${{ else }}: + - ${{ if eq(parameters.jobParameters.runtimeFlavor, 'mono') }}: + # Mono path - test minimal scenario + - Ubuntu.2204.Amd64.Open + - ${{ else }}: + # CoreCLR path + - ${{ if and(eq(parameters.jobParameters.isExtraPlatformsBuild, true), ne(parameters.jobParameters.testScope, 'outerloop'))}}: + # extra-platforms CoreCLR (inner loop only) + - (Debian.12.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-12-helix-amd64 + - (Mariner.2.0.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-helix-amd64 + + - ${{ if eq(parameters.jobParameters.testScope, 'outerloop') }}: + # outerloop only CoreCLR + - AzureLinux.3.Amd64.Open + + - ${{ if or(ne(parameters.jobParameters.isExtraPlatformsBuild, true), eq(parameters.jobParameters.includeAllPlatforms, true))}}: + # inner and outer loop CoreCLR (general set) + - Ubuntu.2204.Amd64.Open + - (AzureLinux.3.0.Amd64.Open)AzureLinux.3.Amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-helix-amd64 + - (Centos.10.Amd64.Open)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-helix-amd64 # OSX arm64 - ${{ if eq(parameters.platform, 'osx_arm64') }}: @@ -99,11 +87,11 @@ jobs: # iOS Simulator/Mac Catalyst arm64 - ${{ if in(parameters.platform, 'maccatalyst_arm64', 'iossimulator_arm64') }}: - - OSX.1200.Arm64.Open + - OSX.14.Arm64.Open # iOS/tvOS Simulator x64 & MacCatalyst x64 - ${{ if in(parameters.platform, 'iossimulator_x64', 'tvossimulator_x64', 'maccatalyst_x64') }}: - - OSX.1200.Amd64.Open + - OSX.15.Amd64.Open # iOS devices - ${{ if in(parameters.platform, 'ios_arm64') }}: @@ -164,15 +152,15 @@ jobs: # WASI - ${{ if eq(parameters.platform, 'wasi_wasm') }}: - - (Ubuntu.2204.Amd64)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly + - (Ubuntu.2204.Amd64)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly # Browser WebAssembly - ${{ if eq(parameters.platform, 'browser_wasm') }}: - - (Ubuntu.2204.Amd64)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly + - (Ubuntu.2204.Amd64)AzureLinux.3.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly # Browser WebAssembly Firefox - ${{ if eq(parameters.platform, 'browser_wasm_firefox') }}: - - (Ubuntu.2204.Amd64)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-webassembly + - (Ubuntu.2204.Amd64)AzureLinux.3.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/outerloop-mono.yml b/eng/pipelines/libraries/outerloop-mono.yml index b9d4bcfecd7b27..ee4ad24571cfc7 100644 --- a/eng/pipelines/libraries/outerloop-mono.yml +++ b/eng/pipelines/libraries/outerloop-mono.yml @@ -6,6 +6,7 @@ schedules: branches: include: - main + always: false # run only if there were changes since the last successful scheduled run. variables: - template: variables.yml diff --git a/eng/pipelines/libraries/outerloop.yml b/eng/pipelines/libraries/outerloop.yml index 597f298c37a3e0..14d26e86dd0b2f 100644 --- a/eng/pipelines/libraries/outerloop.yml +++ b/eng/pipelines/libraries/outerloop.yml @@ -6,7 +6,8 @@ schedules: branches: include: - main - - release/*.* + - release/*.0 + always: false # run only if there were changes since the last successful scheduled run. variables: - template: variables.yml diff --git a/eng/pipelines/libraries/stress/http.yml b/eng/pipelines/libraries/stress/http.yml index 3290eda51ae02f..fdfd004b96eb3e 100644 --- a/eng/pipelines/libraries/stress/http.yml +++ b/eng/pipelines/libraries/stress/http.yml @@ -8,11 +8,11 @@ pr: schedules: - cron: "0 13 * * *" # 1PM UTC => 5 AM PST displayName: HttpStress nightly run + always: true branches: include: - main - - release/8.0 - - release/9.0 + - release/*-staging variables: - template: ../variables.yml @@ -37,7 +37,7 @@ extends: DUMPS_SHARE_MOUNT_ROOT: "/dumps-share" pool: name: $(DncEngPublicBuildPool) - demands: ImageOverride -equals 1es-ubuntu-1804-open + demands: ImageOverride -equals Build.Ubuntu.2204.Amd64.Open steps: - checkout: self diff --git a/eng/pipelines/libraries/stress/ssl.yml b/eng/pipelines/libraries/stress/ssl.yml index 230a2bef377304..ed1306990e294b 100644 --- a/eng/pipelines/libraries/stress/ssl.yml +++ b/eng/pipelines/libraries/stress/ssl.yml @@ -8,11 +8,11 @@ pr: schedules: - cron: "0 13 * * *" # 1PM UTC => 5 AM PST displayName: SslStress nightly run + always: true branches: include: - main - - release/8.0 - - release/9.0 + - release/*-staging variables: - template: ../variables.yml diff --git a/eng/pipelines/runtime-community.yml b/eng/pipelines/runtime-community.yml index b7a21f588973c1..446996e505b72b 100644 --- a/eng/pipelines/runtime-community.yml +++ b/eng/pipelines/runtime-community.yml @@ -71,17 +71,6 @@ extends: eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_mono_excluding_wasm.containsChange'], true), eq(variables['isRollingBuild'], true)) - # extra steps, run tests - postBuildSteps: - - template: /eng/pipelines/libraries/helix.yml - parameters: - creator: dotnet-bot - testRunNamePrefixSuffix: Mono_$(_BuildConfig) - condition: >- - or( - eq(variables['librariesContainsChange'], true), - eq(variables['monoContainsChange'], true), - eq(variables['isRollingBuild'], true)) # # Build the whole product using Mono diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml index e3c7dc5050005f..22375d5c37c81a 100644 --- a/eng/pipelines/runtime-official.yml +++ b/eng/pipelines/runtime-official.yml @@ -382,7 +382,6 @@ extends: parameters: name: MonoRuntimePacks - # Build Mono AOT offset headers once, for consumption elsewhere # - template: /eng/pipelines/common/platform-matrix.yml diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index f06667f3e8e6e2..8f6e4ab408dd08 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -836,21 +836,22 @@ extends: scenarios: - WasmTestOnChrome + # disabled: https://github.com/dotnet/runtime/issues/116492 # Library tests with full threading - - template: /eng/pipelines/common/templates/wasm-library-tests.yml - parameters: - platforms: - - browser_wasm - #- browser_wasm_win - nameSuffix: _Threading - extraBuildArgs: /p:WasmEnableThreads=true /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS) - extraHelixArguments: /p:WasmEnableThreads=true - alwaysRun: ${{ variables.isRollingBuild }} - shouldRunSmokeOnly: onLibrariesAndIllinkChanges - scenarios: - - WasmTestOnChrome - - WasmTestOnFirefox - #- WasmTestOnNodeJS - this is not supported yet, https://github.com/dotnet/runtime/issues/85592 + # - template: /eng/pipelines/common/templates/wasm-library-tests.yml + # parameters: + # platforms: + # - browser_wasm + # #- browser_wasm_win + # nameSuffix: _Threading + # extraBuildArgs: /p:WasmEnableThreads=true /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS) + # extraHelixArguments: /p:WasmEnableThreads=true + # alwaysRun: ${{ variables.isRollingBuild }} + # shouldRunSmokeOnly: onLibrariesAndIllinkChanges + # scenarios: + # - WasmTestOnChrome + # - WasmTestOnFirefox + # #- WasmTestOnNodeJS - this is not supported yet, https://github.com/dotnet/runtime/issues/85592 # EAT Library tests - only run on linux - template: /eng/pipelines/common/templates/wasm-library-aot-tests.yml @@ -1010,8 +1011,7 @@ extends: jobParameters: testGroup: innerloop nameSuffix: AllSubsets_Mono - # Tracking issue: https://github.com/dotnet/runtime/issues/82637 - buildArgs: -s mono+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true /p:RunSmokeTestsOnly=true /p:BuildTestsOnHelix=true /p:EnableAdditionalTimezoneChecks=true /p:UsePortableRuntimePack=true /p:BuildDarwinFrameworks=true /p:EnableAggressiveTrimming=false + buildArgs: -s mono+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true /p:RunSmokeTestsOnly=true /p:BuildTestsOnHelix=true /p:EnableAdditionalTimezoneChecks=true /p:UsePortableRuntimePack=false /p:BuildDarwinFrameworks=true /p:EnableAggressiveTrimming=true timeoutInMinutes: 480 condition: >- or( @@ -1087,8 +1087,7 @@ extends: runtimeFlavor: mono platforms: - maccatalyst_x64 - - ${{ if eq(variables['isRollingBuild'], true) }}: - - maccatalyst_arm64 + - maccatalyst_arm64 variables: # map dependencies variables to local variables - name: librariesContainsChange diff --git a/eng/testing/tests.ioslike.targets b/eng/testing/tests.ioslike.targets index a59cce6c49aeea..e2e36415a31834 100644 --- a/eng/testing/tests.ioslike.targets +++ b/eng/testing/tests.ioslike.targets @@ -16,7 +16,7 @@ <_AOTBuildCommand Condition="'$(ContinuousIntegrationBuild)' != 'true'">$(_AOTBuildCommand) /p:RuntimeSrcDir=$(RepoRoot) /p:RuntimeConfig=$(Configuration) - <_AOTBuildCommand>$(_AOTBuildCommand) /p:XHARNESS_EXECUTION_DIR="$XHARNESS_EXECUTION_DIR" /p:RunAOTCompilation=$(RunAOTCompilation) /p:UseNativeAOTRuntime=$(UseNativeAOTRuntime) /p:TargetOS=$(TargetOS) /p:TargetArchitecture=$(TargetArchitecture) /p:MonoForceInterpreter=$(MonoForceInterpreter) /p:MonoEnableLLVM=true /p:DevTeamProvisioning=$(DevTeamProvisioning) /p:UsePortableRuntimePack=true /p:Configuration=$(Configuration) /p:EnableAggressiveTrimming=$(EnableAggressiveTrimming) + <_AOTBuildCommand>$(_AOTBuildCommand) /p:XHARNESS_EXECUTION_DIR="$XHARNESS_EXECUTION_DIR" /p:RunAOTCompilation=$(RunAOTCompilation) /p:UseNativeAOTRuntime=$(UseNativeAOTRuntime) /p:TargetOS=$(TargetOS) /p:TargetArchitecture=$(TargetArchitecture) /p:MonoForceInterpreter=$(MonoForceInterpreter) /p:MonoEnableLLVM=true /p:DevTeamProvisioning=$(DevTeamProvisioning) /p:UsePortableRuntimePack=$(UsePortableRuntimePack) /p:Configuration=$(Configuration) <_AOTBuildCommand Condition="'$(NativeLib)' != ''">$(_AOTBuildCommand) /p:NativeLib=$(NativeLib) /p:BundlesResources=$(BundlesResources) /p:ForceLibraryModeGenerateAppBundle=$(ForceLibraryModeGenerateAppBundle) <_AOTBuildCommand>$(_AOTBuildCommand) @@ -77,8 +77,6 @@ - @@ -156,12 +154,6 @@ <_AppleItemsToPass Include="@(ReferenceExtraPathFiles->'%(FileName)%(Extension)')" OriginalItemName__="AppleReferenceExtraPathFiles" /> - <_AppleItemsToPass Include="@(RuntimeHostConfigurationOption)" - OriginalItemName__="_AppleUsedRuntimeHostConfigurationOption" /> - - <_AppleItemsToPass Include="@(TrimmerRootAssembly)" - OriginalItemName__="TrimmerRootAssembly" /> - - + + true true $(NoWarn);IL2103;IL2025;IL2111;IL2122 - false false - false - false false - false + + + + + false + <_DefaultValueAttributeSupport Condition="'$(OverrideDefaultValueAndDesignerHostSupport)' == 'true'">true + <_DesignerHostSupport Condition="'$(OverrideDefaultValueAndDesignerHostSupport)' == 'true'">true + + + + diff --git a/src/mono/browser/runtime/http.ts b/src/mono/browser/runtime/http.ts index 743972efd8df71..74f86f88791c4d 100644 --- a/src/mono/browser/runtime/http.ts +++ b/src/mono/browser/runtime/http.ts @@ -4,11 +4,12 @@ import BuildConfiguration from "consts:configuration"; import { wrap_as_cancelable_promise } from "./cancelable-promise"; -import { ENVIRONMENT_IS_NODE, Module, loaderHelpers, mono_assert } from "./globals"; +import { ENVIRONMENT_IS_NODE, loaderHelpers, mono_assert } from "./globals"; import { assert_js_interop } from "./invoke-js"; import { MemoryViewType, Span } from "./marshal"; import type { VoidPtr } from "./types/emscripten"; import { ControllablePromise } from "./types/internal"; +import { mono_log_debug } from "./logging"; function verifyEnvironment () { @@ -72,12 +73,11 @@ export function http_wasm_create_controller (): HttpController { return controller; } -function handle_abort_error (promise:Promise) { +function mute_unhandledrejection (promise:Promise) { promise.catch((err) => { if (err && err !== "AbortError" && err.name !== "AbortError" ) { - Module.err("Unexpected error: " + err); + mono_log_debug("http muted: " + err); } - // otherwise, it's expected }); } @@ -86,15 +86,15 @@ export function http_wasm_abort (controller: HttpController): void { try { if (!controller.isAborted) { if (controller.streamWriter) { - handle_abort_error(controller.streamWriter.abort()); + mute_unhandledrejection(controller.streamWriter.abort()); controller.isAborted = true; } if (controller.streamReader) { - handle_abort_error(controller.streamReader.cancel()); + mute_unhandledrejection(controller.streamReader.cancel()); controller.isAborted = true; } } - if (!controller.isAborted) { + if (!controller.isAborted && !controller.abortController.signal.aborted) { controller.abortController.abort("AbortError"); } } catch (err) { @@ -138,8 +138,8 @@ export function http_wasm_fetch_stream (controller: HttpController, url: string, if (BuildConfiguration === "Debug") commonAsserts(controller); const transformStream = new TransformStream(); controller.streamWriter = transformStream.writable.getWriter(); - handle_abort_error(controller.streamWriter.closed); - handle_abort_error(controller.streamWriter.ready); + mute_unhandledrejection(controller.streamWriter.closed); + mute_unhandledrejection(controller.streamWriter.ready); const fetch_promise = http_wasm_fetch(controller, url, header_names, header_values, option_names, option_values, transformStream.readable); return fetch_promise; } @@ -177,16 +177,18 @@ export function http_wasm_fetch (controller: HttpController, url: string, header } // make the fetch cancellable controller.responsePromise = wrap_as_cancelable_promise(() => { - return loaderHelpers.fetch_like(url, options); + return loaderHelpers.fetch_like(url, options).then((res: Response) => { + controller.response = res; + return null;// drop the response from the promise chain + }); }); // avoid processing headers if the fetch is canceled - controller.responsePromise.then((res: Response) => { - controller.response = res; + controller.responsePromise.then(() => { + mono_assert(controller.response, "expected response"); controller.responseHeaderNames = []; controller.responseHeaderValues = []; - if (res.headers && (res.headers).entries) { - const entries: Iterable = (res.headers).entries(); - + if (controller.response.headers && (controller.response.headers).entries) { + const entries: Iterable = (controller.response.headers).entries(); for (const pair of entries) { controller.responseHeaderNames.push(pair[0]); controller.responseHeaderValues.push(pair[1]); @@ -250,9 +252,15 @@ export function http_wasm_get_streamed_response_bytes (controller: HttpControlle // the bufferPtr is pinned by the caller const view = new Span(bufferPtr, bufferLength, MemoryViewType.Byte); return wrap_as_cancelable_promise(async () => { + await controller.responsePromise; mono_assert(controller.response, "expected response"); + if (!controller.response.body) { + // in FF when the verb is HEAD, the body is null + return 0; + } if (!controller.streamReader) { - controller.streamReader = controller.response.body!.getReader(); + controller.streamReader = controller.response.body.getReader(); + mute_unhandledrejection(controller.streamReader.closed); } if (!controller.currentStreamReaderChunk || controller.currentBufferOffset === undefined) { controller.currentStreamReaderChunk = await controller.streamReader.read(); diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index 300a46a245f92d..5ce5950556581c 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -924,9 +924,7 @@ delta_info_initialize_mutants (const MonoImage *base, const BaselineInfo *base_i g_assert (prev_table != NULL); MonoTableInfo *tbl = &delta->mutants [i]; - if (prev_table->rows_ == 0) { - /* table was empty in the baseline and it was empty in the prior generation, but now we have some rows. Use the format of the mutant table. */ - g_assert (prev_table->row_size == 0); + if (delta->delta_image->tables [i].row_size != 0 || prev_table->rows_ == 0) { tbl->row_size = delta->delta_image->tables [i].row_size; tbl->size_bitfield = delta->delta_image->tables [i].size_bitfield; } else { @@ -940,8 +938,60 @@ delta_info_initialize_mutants (const MonoImage *base, const BaselineInfo *base_i tbl->base = mono_mempool_alloc (delta->pool, tbl->row_size * rows); g_assert (table_info_get_rows (prev_table) == count->prev_gen_rows); - /* copy the old rows and zero out the new ones */ - memcpy ((char*)tbl->base, prev_table->base, count->prev_gen_rows * tbl->row_size); + /* copy the old rows and zero out the new ones */ + /* we need to copy following the new format (uncompressed one)*/ + for (guint32 j = 0 ; j < count->prev_gen_rows; j++) + { + guint32 src_offset = 0, dst_offset = 0; + guint32 dst_bitfield = tbl->size_bitfield; + guint32 src_bitfield = prev_table->size_bitfield; + const char *src_base = (char*)prev_table->base + j * prev_table->row_size; + char *dst_base = (char*)tbl->base + j * tbl->row_size; + for (guint col = 0; col < mono_metadata_table_count (dst_bitfield); ++col) { + guint32 dst_col_size = mono_metadata_table_size (dst_bitfield, col); + guint32 src_col_size = mono_metadata_table_size (src_bitfield, col); + { + const char *src = src_base + src_offset; + char *dst = dst_base + dst_offset; + + /* copy src to dst, via a temporary to adjust for size differences */ + /* FIXME: unaligned access, endianness */ + guint32 tmp; + + switch (src_col_size) { + case 1: + tmp = *(guint8*)src; + break; + case 2: + tmp = *(guint16*)src; + break; + case 4: + tmp = *(guint32*)src; + break; + default: + g_assert_not_reached (); + } + + /* FIXME: unaligned access, endianness */ + switch (dst_col_size) { + case 1: + *(guint8*)dst = (guint8)tmp; + break; + case 2: + *(guint16*)dst = (guint16)tmp; + break; + case 4: + *(guint32*)dst = tmp; + break; + default: + g_assert_not_reached (); + } + } + src_offset += src_col_size; + dst_offset += dst_col_size; + } + g_assert (dst_offset == tbl->row_size); + } memset (((char*)tbl->base) + count->prev_gen_rows * tbl->row_size, 0, count->inserted_rows * tbl->row_size); } } @@ -1386,8 +1436,8 @@ delta_info_mutate_row (MonoImage *image_dmeta, DeltaInfo *cur_delta, guint32 log /* The complication here is that we want the mutant table to look like the table in * the baseline image with respect to column widths, but the delta tables are generally coming in - * uncompressed (4-byte columns). So we have to copy one column at a time and adjust the - * widths as we go. + * uncompressed (4-byte columns). And we have already adjusted the baseline image column widths + * so we can use memcpy here. */ guint32 dst_bitfield = cur_delta->mutants [token_table].size_bitfield; @@ -1401,41 +1451,10 @@ delta_info_mutate_row (MonoImage *image_dmeta, DeltaInfo *cur_delta, guint32 log guint32 dst_col_size = mono_metadata_table_size (dst_bitfield, col); guint32 src_col_size = mono_metadata_table_size (src_bitfield, col); if ((m_SuppressedDeltaColumns [token_table] & (1 << col)) == 0) { + g_assert(src_col_size <= dst_col_size); const char *src = src_base + src_offset; char *dst = dst_base + dst_offset; - - /* copy src to dst, via a temporary to adjust for size differences */ - /* FIXME: unaligned access, endianness */ - guint32 tmp; - - switch (src_col_size) { - case 1: - tmp = *(guint8*)src; - break; - case 2: - tmp = *(guint16*)src; - break; - case 4: - tmp = *(guint32*)src; - break; - default: - g_assert_not_reached (); - } - - /* FIXME: unaligned access, endianness */ - switch (dst_col_size) { - case 1: - *(guint8*)dst = (guint8)tmp; - break; - case 2: - *(guint16*)dst = (guint16)tmp; - break; - case 4: - *(guint32*)dst = tmp; - break; - default: - g_assert_not_reached (); - } + memcpy(dst, src, src_col_size); } src_offset += src_col_size; dst_offset += dst_col_size; diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index 1c1a632a4003e7..8ff1295057db10 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -906,9 +906,13 @@ compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int guint32 field_iter = 1; guint32 field_instance_offset = field_offset; + int field_size = 0; // If struct has InlineArray attribute, iterate `length` times to set a bitmap - if (m_class_is_inlinearray (p)) + if (m_class_is_inlinearray (p)) { + int align; field_iter = m_class_inlinearray_value (p); + field_size = mono_type_size (field->type, &align); + } if (field_iter > 500) g_warning ("Large number of iterations detected when creating a GC bitmap, might affect performance."); @@ -973,7 +977,7 @@ compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int break; } - field_instance_offset += field_offset; + field_instance_offset += field_size; field_iter--; } } @@ -6806,6 +6810,7 @@ mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *er { error_init (error); + if (!m_class_is_inited (klass)) mono_class_init_internal (klass); diff --git a/src/mono/mono/metadata/sgen-bridge.c b/src/mono/mono/metadata/sgen-bridge.c index 579fc0d376cd6a..1f7dc31c9b4b11 100644 --- a/src/mono/mono/metadata/sgen-bridge.c +++ b/src/mono/mono/metadata/sgen-bridge.c @@ -316,24 +316,24 @@ dump_processor_state (SgenBridgeProcessor *p) { int i; - printf ("------\n"); - printf ("SCCS %d\n", p->num_sccs); + g_message ("------\n"); + g_message ("SCCS %d\n", p->num_sccs); for (i = 0; i < p->num_sccs; ++i) { int j; MonoGCBridgeSCC *scc = p->api_sccs [i]; - printf ("\tSCC %d:", i); + g_message ("\tSCC %d:", i); for (j = 0; j < scc->num_objs; ++j) { MonoObject *obj = scc->objs [j]; - printf (" %p(%s)", obj, SGEN_LOAD_VTABLE (obj)->klass->name); + g_message (" %p(%s)", obj, m_class_get_name (SGEN_LOAD_VTABLE (obj)->klass)); } - printf ("\n"); + g_message ("\n"); } - printf ("XREFS %d\n", p->num_xrefs); + g_message ("XREFS %d\n", p->num_xrefs); for (i = 0; i < p->num_xrefs; ++i) - printf ("\t%d -> %d\n", p->api_xrefs [i].src_scc_index, p->api_xrefs [i].dst_scc_index); + g_message ("\t%d -> %d\n", p->api_xrefs [i].src_scc_index, p->api_xrefs [i].dst_scc_index); - printf ("-------\n"); + g_message ("-------\n"); } */ @@ -352,7 +352,7 @@ sgen_compare_bridge_processor_results (SgenBridgeProcessor *a, SgenBridgeProcess if (a->num_sccs != b->num_sccs) g_error ("SCCS count expected %d but got %d", a->num_sccs, b->num_sccs); if (a->num_xrefs != b->num_xrefs) - g_error ("SCCS count expected %d but got %d", a->num_xrefs, b->num_xrefs); + g_error ("XREFS count expected %d but got %d", a->num_xrefs, b->num_xrefs); /* * First we build a hash of each object in `a` to its respective SCC index within diff --git a/src/mono/mono/metadata/sgen-tarjan-bridge.c b/src/mono/mono/metadata/sgen-tarjan-bridge.c index b0c9cf1f83baef..7a8ad5961d98e7 100644 --- a/src/mono/mono/metadata/sgen-tarjan-bridge.c +++ b/src/mono/mono/metadata/sgen-tarjan-bridge.c @@ -400,16 +400,7 @@ static const char* safe_name_bridge (GCObject *obj) { GCVTable vt = SGEN_LOAD_VTABLE (obj); - return vt->klass->name; -} - -static ScanData* -find_or_create_data (GCObject *obj) -{ - ScanData *entry = find_data (obj); - if (!entry) - entry = create_data (obj); - return entry; + return m_class_get_name (vt->klass); } #endif @@ -566,10 +557,15 @@ find_in_cache (int *insert_index) // Populate other_colors for a give color (other_colors represent the xrefs for this color) static void -add_other_colors (ColorData *color, DynPtrArray *other_colors) +add_other_colors (ColorData *color, DynPtrArray *other_colors, gboolean check_visited) { for (int i = 0; i < dyn_array_ptr_size (other_colors); ++i) { ColorData *points_to = (ColorData *)dyn_array_ptr_get (other_colors, i); + if (check_visited) { + if (points_to->visited) + continue; + points_to->visited = TRUE; + } dyn_array_ptr_add (&color->other_colors, points_to); // Inform targets points_to->incoming_colors = MIN (points_to->incoming_colors + 1, INCOMING_COLORS_MAX); @@ -593,7 +589,7 @@ new_color (gboolean has_bridges) cd = alloc_color_data (); cd->api_index = -1; - add_other_colors (cd, &color_merge_array); + add_other_colors (cd, &color_merge_array, FALSE); /* if cacheSlot >= 0, it means we prepared a given slot to receive the new color */ if (cacheSlot >= 0) @@ -700,11 +696,11 @@ compute_low_index (ScanData *data, GCObject *obj) obj = bridge_object_forward (obj); other = find_data (obj); -#if DUMP_GRAPH - printf ("\tcompute low %p ->%p (%s) %p (%d / %d, color %p)\n", data->obj, obj, safe_name_bridge (obj), other, other ? other->index : -2, other ? other->low_index : -2, other->color); -#endif if (!other) return; +#if DUMP_GRAPH + printf ("\tcompute low %p ->%p (%s) %p (%d / %d, color %p)\n", data->obj, obj, safe_name_bridge (obj), other, other ? other->index : -2, other->low_index, other->color); +#endif g_assert (other->state != INITIAL); @@ -777,10 +773,16 @@ create_scc (ScanData *data) gboolean found = FALSE; gboolean found_bridge = FALSE; ColorData *color_data = NULL; + gboolean can_reduce_color = TRUE; for (i = dyn_array_ptr_size (&loop_stack) - 1; i >= 0; --i) { ScanData *other = (ScanData *)dyn_array_ptr_get (&loop_stack, i); found_bridge |= other->is_bridge; + if (dyn_array_ptr_size (&other->xrefs) > 0 || found_bridge) { + // This scc will have more xrefs than the ones from the color_merge_array, + // we will need to create a new color to store this information. + can_reduce_color = FALSE; + } if (found_bridge || other == data) break; } @@ -788,13 +790,15 @@ create_scc (ScanData *data) if (found_bridge) { color_data = new_color (TRUE); ++num_colors_with_bridges; - } else { + } else if (can_reduce_color) { color_data = reduce_color (); + } else { + color_data = new_color (FALSE); } #if DUMP_GRAPH printf ("|SCC %p rooted in %s (%p) has bridge %d\n", color_data, safe_name_bridge (data->obj), data->obj, found_bridge); printf ("\tloop stack: "); - for (int i = 0; i < dyn_array_ptr_size (&loop_stack); ++i) { + for (i = 0; i < dyn_array_ptr_size (&loop_stack); ++i) { ScanData *other = dyn_array_ptr_get (&loop_stack, i); printf ("(%d/%d)", other->index, other->low_index); } @@ -824,10 +828,19 @@ create_scc (ScanData *data) dyn_array_ptr_add (&color_data->bridges, other->obj); } - // Maybe we should make sure we are not adding duplicates here. It is not really a problem - // since we will get rid of duplicates before submitting the SCCs to the client in gather_xrefs - if (color_data) - add_other_colors (color_data, &other->xrefs); + if (dyn_array_ptr_size (&other->xrefs) > 0) { + g_assert (color_data != NULL); + g_assert (can_reduce_color == FALSE); + // We need to eliminate duplicates early otherwise the heaviness property + // can change in gather_xrefs and it breaks down the loop that reports the + // xrefs to the client. + // + // We reuse the visited flag to mark the objects that are already part of + // the color_data array. The array was created above with the new_color call + // and xrefs were populated from color_merge_array, which is already + // deduplicated and every entry is marked as visited. + add_other_colors (color_data, &other->xrefs, TRUE); + } dyn_array_ptr_uninit (&other->xrefs); if (other == data) { @@ -837,11 +850,22 @@ create_scc (ScanData *data) } g_assert (found); + // Clear the visited flag on nodes that were added with add_other_colors in the loop above + if (!can_reduce_color) { + for (i = dyn_array_ptr_size (&color_merge_array); i < dyn_array_ptr_size (&color_data->other_colors); i++) { + ColorData *cd = (ColorData *)dyn_array_ptr_get (&color_data->other_colors, i); + g_assert (cd->visited); + cd->visited = FALSE; + } + } + #if DUMP_GRAPH - printf ("\tpoints-to-colors: "); - for (int i = 0; i < dyn_array_ptr_size (&color_data->other_colors); i++) - printf ("%p ", dyn_array_ptr_get (&color_data->other_colors, i)); - printf ("\n"); + if (color_data) { + printf ("\tpoints-to-colors: "); + for (i = 0; i < dyn_array_ptr_size (&color_data->other_colors); i++) + printf ("%p ", dyn_array_ptr_get (&color_data->other_colors, i)); + printf ("\n"); + } #endif } @@ -966,8 +990,11 @@ dump_color_table (const char *why, gboolean do_index) printf (" bridges: "); for (j = 0; j < dyn_array_ptr_size (&cd->bridges); ++j) { GCObject *obj = dyn_array_ptr_get (&cd->bridges, j); - ScanData *data = find_or_create_data (obj); - printf ("%d ", data->index); + ScanData *data = find_data (obj); + if (!data) + printf ("%p ", obj); + else + printf ("%p(%d) ", obj, data->index); } } printf ("\n"); @@ -1027,7 +1054,7 @@ processing_stw_step (void) #if defined (DUMP_GRAPH) printf ("----summary----\n"); printf ("bridges:\n"); - for (int i = 0; i < bridge_count; ++i) { + for (i = 0; i < bridge_count; ++i) { ScanData *sd = find_data (dyn_array_ptr_get (®istered_bridges, i)); printf ("\t%s (%p) index %d color %p\n", safe_name_bridge (sd->obj), sd->obj, sd->index, sd->color); } @@ -1141,6 +1168,7 @@ processing_build_callback_data (int generation) gather_xrefs (cd); reset_xrefs (cd); dyn_array_ptr_set_all (&cd->other_colors, &color_merge_array); + g_assert (color_visible_to_client (cd)); xref_count += dyn_array_ptr_size (&cd->other_colors); } } diff --git a/src/mono/mono/mini/interp/interp-simd-intrins.def b/src/mono/mono/mini/interp/interp-simd-intrins.def index d88e543af23471..197b3c269d6612 100644 --- a/src/mono/mono/mini/interp/interp-simd-intrins.def +++ b/src/mono/mono/mini/interp/interp-simd-intrins.def @@ -351,7 +351,7 @@ INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToSingle, U4, wasm_f32x4_convert_u32x4, INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToSingle, R8, wasm_f32x4_demote_f64x2_zero, 0x5e) INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToDoubleLower, I4, wasm_f64x2_convert_low_i32x4, 0xfe) INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToDoubleLower, U4, wasm_f64x2_convert_low_u32x4, 0xff) -INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToDoubleLower, R8, wasm_f64x2_promote_low_f32x4, 0x5f) +INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToDoubleLower, R4, wasm_f64x2_promote_low_f32x4, 0x5f) INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToInt32Saturate, R4, wasm_i32x4_trunc_sat_f32x4, 0xf8) INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToUInt32Saturate, R4, wasm_u32x4_trunc_sat_f32x4, 0xf9) INTERP_WASM_SIMD_INTRINSIC_V_V (ConvertToInt32Saturate, R8, wasm_i32x4_trunc_sat_f64x2_zero, 0xfc) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index c3016252942f4a..011d99a9625dda 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -8981,6 +8981,10 @@ mono_ee_interp_init (const char *opts) set_context (NULL); interp_parse_options (opts); + + const char *env_opts = g_getenv ("MONO_INTERPRETER_OPTIONS"); + if (env_opts) + interp_parse_options (env_opts); /* Don't do any optimizations if running under debugger */ if (mini_get_debug_options ()->mdb_optimizations) mono_interp_opt = 0; diff --git a/src/mono/mono/mini/interp/transform-opt.c b/src/mono/mono/mini/interp/transform-opt.c index b259e116c14404..f5ffbc89df7fdd 100644 --- a/src/mono/mono/mini/interp/transform-opt.c +++ b/src/mono/mono/mini/interp/transform-opt.c @@ -3124,6 +3124,7 @@ interp_cprop (TransformData *td) ins->data [2] = GINT_TO_UINT16 (ldsize); interp_clear_ins (ins->prev); + td->var_values [ins->dreg].def = ins; } if (td->verbose_level) { g_print ("Replace ldloca/ldobj_vt pair :\n\t"); @@ -3204,6 +3205,7 @@ interp_cprop (TransformData *td) ins->data [2] = vtsize; interp_clear_ins (ins->prev); + td->var_values [ins->dreg].def = ins; // MINT_MOV_DST_OFF doesn't work if dreg is allocated at the same location as the // field value to be stored, because its behavior is not atomic in nature. We first @@ -3400,9 +3402,11 @@ interp_super_instructions (TransformData *td) current_liveness.bb_dfs_index = bb->dfs_index; current_liveness.ins_index = 0; for (InterpInst *ins = bb->first_ins; ins != NULL; ins = ins->next) { - int opcode = ins->opcode; + int opcode; if (bb->dfs_index >= td->bblocks_count_no_eh || bb->dfs_index == -1 || (ins->flags & INTERP_INST_FLAG_LIVENESS_MARKER)) current_liveness.ins_index++; +retry_ins: + opcode = ins->opcode; if (MINT_IS_NOP (opcode)) continue; @@ -3801,9 +3805,7 @@ interp_super_instructions (TransformData *td) g_print ("superins: "); interp_dump_ins (ins, td->data_items); } - // The newly added opcode could be part of further superinstructions. Retry - ins = ins->prev; - continue; + goto retry_ins; } } } diff --git a/src/mono/mono/mini/interp/transform-simd.c b/src/mono/mono/mini/interp/transform-simd.c index c1d6b81019d02f..70b88cf0c148d0 100644 --- a/src/mono/mono/mini/interp/transform-simd.c +++ b/src/mono/mono/mini/interp/transform-simd.c @@ -779,6 +779,24 @@ emit_sn_vector4 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature *cs } #if HOST_BROWSER +static MonoTypeEnum +resolve_native_size (MonoTypeEnum type) +{ + if (type == MONO_TYPE_I) +#if TARGET_SIZEOF_VOID_P == 4 + return MONO_TYPE_I4; +#else + return MONO_TYPE_I8; +#endif + else if (type == MONO_TYPE_U) +#if TARGET_SIZEOF_VOID_P == 4 + return MONO_TYPE_U4; +#else + return MONO_TYPE_U8; +#endif + return type; + +} #define PSIMD_ARGTYPE_I1 MONO_TYPE_I1 #define PSIMD_ARGTYPE_I2 MONO_TYPE_I2 @@ -803,6 +821,7 @@ emit_sn_vector4 (TransformData *td, MonoMethod *cmethod, MonoMethodSignature *cs static gboolean packedsimd_type_matches (MonoTypeEnum type, int expected_type) { + type = resolve_native_size (type); if (expected_type == PSIMD_ARGTYPE_ANY) return TRUE; else if (type == expected_type) @@ -906,6 +925,8 @@ lookup_packedsimd_intrinsic (const char *name, MonoType *arg1) arg_type = mono_class_get_context (vector_klass)->class_inst->type_argv [0]; } else if (arg1->type == MONO_TYPE_PTR) { arg_type = arg1->data.type; + } else if (MONO_TYPE_IS_VECTOR_PRIMITIVE(arg1)) { + arg_type = arg1; } else { // g_printf ("%s arg1 type was not pointer or simd type: %s\n", name, m_class_get_name (vector_klass)); return FALSE; @@ -989,7 +1010,13 @@ emit_sri_packedsimd (TransformData *td, MonoMethod *cmethod, MonoMethodSignature int id = lookup_intrins (sri_packedsimd_methods, sizeof (sri_packedsimd_methods), cmethod->name); // We don't early-out for an unrecognized method, we will generate an NIY later - MonoClass *vector_klass = mono_class_from_mono_type_internal (csignature->ret); + MonoClass *vector_klass = NULL; + if (csignature->ret->type == MONO_TYPE_VOID && csignature->param_count > 1 && mono_type_is_pointer (csignature->params [0])) { + // The Store* methods have a more complicated signature + vector_klass = mono_class_from_mono_type_internal (csignature->params [1]); + } else { + vector_klass = mono_class_from_mono_type_internal (csignature->ret); + } MonoTypeEnum atype; int vector_size = -1, arg_size, scalar_arg; diff --git a/src/mono/mono/mini/jit-icalls.c b/src/mono/mono/mini/jit-icalls.c index df7c332f8fcd4c..a62f6959f2b2b7 100644 --- a/src/mono/mono/mini/jit-icalls.c +++ b/src/mono/mono/mini/jit-icalls.c @@ -1702,7 +1702,7 @@ mono_throw_type_load (MonoClass* klass) mono_error_set_type_load_class (error, klass, "Attempting to load invalid type '%s'.", klass_name); g_free (klass_name); } - + mono_error_set_pending_exception (error); } @@ -1743,6 +1743,11 @@ mini_init_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, MonoGSharedMeth mono_method_get_context (m), m->klass); g_assert (data); + // we need a barrier before publishing data via mrgctx->infos [i] because the contents of data may not + // have been published to all cores and another thread may read zeroes or partially initialized data + // out of it, even though we have a barrier before publication of entries in mrgctx->entries below + mono_memory_barrier(); + /* The first few entries are stored inline, the rest are stored in mrgctx->entries */ if (i < ninline) mrgctx->infos [i] = data; diff --git a/src/mono/mono/sgen/sgen-array-list.h b/src/mono/mono/sgen/sgen-array-list.h index d98e678cfc48c5..4de9433dbf891d 100644 --- a/src/mono/mono/sgen/sgen-array-list.h +++ b/src/mono/mono/sgen/sgen-array-list.h @@ -60,7 +60,10 @@ static inline guint32 sgen_clz (guint32 x) { gulong leading_zero_bits; - return _BitScanReverse (&leading_zero_bits, (gulong)x) ? 31 - leading_zero_bits : 32; + if (_BitScanReverse (&leading_zero_bits, (gulong)x)) + return 31 - leading_zero_bits; + else + return 32; } #elif defined(ENABLE_MSVC_LZCNT) && defined(_MSC_VER) static inline guint32 diff --git a/src/mono/mono/utils/atomic.h b/src/mono/mono/utils/atomic.h index 3f0a01e6beb428..9d4459d932fb1a 100644 --- a/src/mono/mono/utils/atomic.h +++ b/src/mono/mono/utils/atomic.h @@ -95,11 +95,25 @@ Apple targets have historically being problematic, xcode 4.6 would miscompile th #include +#if defined(HOST_ARM64) +// C11 atomics on ARM64 offers a weaker version of sequential consistent, not expected by mono atomics operations. +// C11 seq_cst on ARM64 corresponds to acquire/release semantics, but mono expects these functions to emit a full memory +// barrier preventing any kind of reordering around the atomic operation. GCC atomics on ARM64 had similar limitations, +// see comments on GCC atomics below and mono injected full memory barriers around GCC atomic functions to mitigate this. +// Since mono GCC atomics implementation ended up even stronger (full memory barrier before/after), the C11 atomics +// implementation is still a little weaker, but should correspond to the exact same semantics as implemented by JIT +// compiler for sequential consistent atomic load/store/add/exchange/cas op codes on ARM64. +#define C11_MEMORY_ORDER_SEQ_CST() atomic_thread_fence (memory_order_seq_cst) +#else +#define C11_MEMORY_ORDER_SEQ_CST() +#endif + static inline guint8 mono_atomic_cas_u8 (volatile guint8 *dest, guint8 exch, guint8 comp) { g_static_assert (sizeof (atomic_char) == sizeof (*dest) && ATOMIC_CHAR_LOCK_FREE == 2); (void)atomic_compare_exchange_strong ((volatile atomic_char *)dest, (char*)&comp, exch); + C11_MEMORY_ORDER_SEQ_CST (); return comp; } @@ -108,6 +122,7 @@ mono_atomic_cas_u16 (volatile guint16 *dest, guint16 exch, guint16 comp) { g_static_assert (sizeof (atomic_short) == sizeof (*dest) && ATOMIC_SHORT_LOCK_FREE == 2); (void)atomic_compare_exchange_strong ((volatile atomic_short *)dest, (short*)&comp, exch); + C11_MEMORY_ORDER_SEQ_CST (); return comp; } @@ -116,6 +131,7 @@ mono_atomic_cas_i32 (volatile gint32 *dest, gint32 exch, gint32 comp) { g_static_assert (sizeof (atomic_int) == sizeof (*dest) && ATOMIC_INT_LOCK_FREE == 2); (void)atomic_compare_exchange_strong ((volatile atomic_int *)dest, &comp, exch); + C11_MEMORY_ORDER_SEQ_CST (); return comp; } @@ -125,14 +141,14 @@ mono_atomic_cas_i64 (volatile gint64 *dest, gint64 exch, gint64 comp) #if SIZEOF_LONG == 8 g_static_assert (sizeof (atomic_long) == sizeof (*dest) && ATOMIC_LONG_LOCK_FREE == 2); (void)atomic_compare_exchange_strong ((volatile atomic_long *)dest, (long*)&comp, exch); - return comp; #elif SIZEOF_LONG_LONG == 8 g_static_assert (sizeof (atomic_llong) == sizeof (*dest) && ATOMIC_LLONG_LOCK_FREE == 2); (void)atomic_compare_exchange_strong ((volatile atomic_llong *)dest, (long long*)&comp, exch); - return comp; #else #error "gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC" #endif + C11_MEMORY_ORDER_SEQ_CST (); + return comp; } static inline gpointer @@ -140,6 +156,7 @@ mono_atomic_cas_ptr (volatile gpointer *dest, gpointer exch, gpointer comp) { g_static_assert(ATOMIC_POINTER_LOCK_FREE == 2); (void)atomic_compare_exchange_strong ((volatile _Atomic(gpointer) *)dest, &comp, exch); + C11_MEMORY_ORDER_SEQ_CST (); return comp; } @@ -191,21 +208,27 @@ static inline guint8 mono_atomic_xchg_u8 (volatile guint8 *dest, guint8 exch) { g_static_assert (sizeof (atomic_char) == sizeof (*dest) && ATOMIC_CHAR_LOCK_FREE == 2); - return atomic_exchange ((volatile atomic_char *)dest, exch); + guint8 old = atomic_exchange ((volatile atomic_char *)dest, exch); + C11_MEMORY_ORDER_SEQ_CST (); + return old; } static inline guint16 mono_atomic_xchg_u16 (volatile guint16 *dest, guint16 exch) { g_static_assert (sizeof (atomic_short) == sizeof (*dest) && ATOMIC_SHORT_LOCK_FREE == 2); - return atomic_exchange ((volatile atomic_short *)dest, exch); + guint16 old = atomic_exchange ((volatile atomic_short *)dest, exch); + C11_MEMORY_ORDER_SEQ_CST (); + return old; } static inline gint32 mono_atomic_xchg_i32 (volatile gint32 *dest, gint32 exch) { g_static_assert (sizeof (atomic_int) == sizeof (*dest) && ATOMIC_INT_LOCK_FREE == 2); - return atomic_exchange ((volatile atomic_int *)dest, exch); + gint32 old = atomic_exchange ((volatile atomic_int *)dest, exch); + C11_MEMORY_ORDER_SEQ_CST (); + return old; } static inline gint64 @@ -213,27 +236,33 @@ mono_atomic_xchg_i64 (volatile gint64 *dest, gint64 exch) { #if SIZEOF_LONG == 8 g_static_assert (sizeof (atomic_long) == sizeof (*dest) && ATOMIC_LONG_LOCK_FREE == 2); - return atomic_exchange ((volatile atomic_long *)dest, exch); + gint64 old = atomic_exchange ((volatile atomic_long *)dest, exch); #elif SIZEOF_LONG_LONG == 8 g_static_assert (sizeof (atomic_llong) == sizeof (*dest) && ATOMIC_LLONG_LOCK_FREE == 2); - return atomic_exchange ((volatile atomic_llong *)dest, exch); + gint64 old = atomic_exchange ((volatile atomic_llong *)dest, exch); #else #error "gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC" #endif + C11_MEMORY_ORDER_SEQ_CST (); + return old; } static inline gpointer mono_atomic_xchg_ptr (volatile gpointer *dest, gpointer exch) { g_static_assert (ATOMIC_POINTER_LOCK_FREE == 2); - return atomic_exchange ((volatile _Atomic(gpointer) *)dest, exch); + gpointer old = atomic_exchange ((volatile _Atomic(gpointer) *)dest, exch); + C11_MEMORY_ORDER_SEQ_CST (); + return old; } static inline gint32 mono_atomic_fetch_add_i32 (volatile gint32 *dest, gint32 add) { g_static_assert (sizeof (atomic_int) == sizeof (*dest) && ATOMIC_INT_LOCK_FREE == 2); - return atomic_fetch_add ((volatile atomic_int *)dest, add); + gint32 old = atomic_fetch_add ((volatile atomic_int *)dest, add); + C11_MEMORY_ORDER_SEQ_CST (); + return old; } static inline gint64 @@ -241,33 +270,41 @@ mono_atomic_fetch_add_i64 (volatile gint64 *dest, gint64 add) { #if SIZEOF_LONG == 8 g_static_assert (sizeof (atomic_long) == sizeof (*dest) && ATOMIC_LONG_LOCK_FREE == 2); - return atomic_fetch_add ((volatile atomic_long *)dest, add); + gint64 old = atomic_fetch_add ((volatile atomic_long *)dest, add); #elif SIZEOF_LONG_LONG == 8 g_static_assert (sizeof (atomic_llong) == sizeof (*dest) && ATOMIC_LLONG_LOCK_FREE == 2); - return atomic_fetch_add ((volatile atomic_llong *)dest, add); + gint64 old = atomic_fetch_add ((volatile atomic_llong *)dest, add); #else #error "gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC" #endif + C11_MEMORY_ORDER_SEQ_CST (); + return old; } static inline gint8 mono_atomic_load_i8 (volatile gint8 *src) { g_static_assert (sizeof (atomic_char) == sizeof (*src) && ATOMIC_CHAR_LOCK_FREE == 2); - return atomic_load ((volatile atomic_char *)src); + C11_MEMORY_ORDER_SEQ_CST (); + gint8 val = atomic_load ((volatile atomic_char *)src); + return val; } static inline gint16 mono_atomic_load_i16 (volatile gint16 *src) { g_static_assert (sizeof (atomic_short) == sizeof (*src) && ATOMIC_SHORT_LOCK_FREE == 2); - return atomic_load ((volatile atomic_short *)src); + C11_MEMORY_ORDER_SEQ_CST (); + gint16 val = atomic_load ((volatile atomic_short *)src); + return val; } static inline gint32 mono_atomic_load_i32 (volatile gint32 *src) { g_static_assert (sizeof (atomic_int) == sizeof (*src) && ATOMIC_INT_LOCK_FREE == 2); - return atomic_load ((volatile atomic_int *)src); + C11_MEMORY_ORDER_SEQ_CST (); + gint32 val = atomic_load ((volatile atomic_int *)src); + return val; } static inline gint64 @@ -275,20 +312,25 @@ mono_atomic_load_i64 (volatile gint64 *src) { #if SIZEOF_LONG == 8 g_static_assert (sizeof (atomic_long) == sizeof (*src) && ATOMIC_LONG_LOCK_FREE == 2); - return atomic_load ((volatile atomic_long *)src); + C11_MEMORY_ORDER_SEQ_CST (); + gint64 val = atomic_load ((volatile atomic_long *)src); #elif SIZEOF_LONG_LONG == 8 g_static_assert (sizeof (atomic_llong) == sizeof (*src) && ATOMIC_LLONG_LOCK_FREE == 2); - return atomic_load ((volatile atomic_llong *)src); + C11_MEMORY_ORDER_SEQ_CST (); + gint64 val = atomic_load ((volatile atomic_llong *)src); #else #error "gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC" #endif + return val; } static inline gpointer mono_atomic_load_ptr (volatile gpointer *src) { g_static_assert (ATOMIC_POINTER_LOCK_FREE == 2); - return atomic_load ((volatile _Atomic(gpointer) *)src); + C11_MEMORY_ORDER_SEQ_CST (); + gpointer val = atomic_load ((volatile _Atomic(gpointer) *)src); + return val; } static inline void @@ -296,6 +338,7 @@ mono_atomic_store_i8 (volatile gint8 *dst, gint8 val) { g_static_assert (sizeof (atomic_char) == sizeof (*dst) && ATOMIC_CHAR_LOCK_FREE == 2); atomic_store ((volatile atomic_char *)dst, val); + C11_MEMORY_ORDER_SEQ_CST (); } static inline void @@ -303,6 +346,7 @@ mono_atomic_store_i16 (volatile gint16 *dst, gint16 val) { g_static_assert (sizeof (atomic_short) == sizeof (*dst) && ATOMIC_SHORT_LOCK_FREE == 2); atomic_store ((volatile atomic_short *)dst, val); + C11_MEMORY_ORDER_SEQ_CST (); } static inline void @@ -310,6 +354,7 @@ mono_atomic_store_i32 (volatile gint32 *dst, gint32 val) { g_static_assert (sizeof (atomic_int) == sizeof (*dst) && ATOMIC_INT_LOCK_FREE == 2); atomic_store ((atomic_int *)dst, val); + C11_MEMORY_ORDER_SEQ_CST (); } static inline void @@ -324,6 +369,7 @@ mono_atomic_store_i64 (volatile gint64 *dst, gint64 val) #else #error "gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC" #endif + C11_MEMORY_ORDER_SEQ_CST (); } static inline void @@ -331,6 +377,7 @@ mono_atomic_store_ptr (volatile gpointer *dst, gpointer val) { g_static_assert (ATOMIC_POINTER_LOCK_FREE == 2); atomic_store ((volatile _Atomic(gpointer) *)dst, val); + C11_MEMORY_ORDER_SEQ_CST (); } #elif defined(MONO_USE_WIN32_ATOMIC) diff --git a/src/mono/msbuild/apple/data/ProxyProjectForAOTOnHelix.proj b/src/mono/msbuild/apple/data/ProxyProjectForAOTOnHelix.proj index 2847f567f469a1..2035333122a2f0 100644 --- a/src/mono/msbuild/apple/data/ProxyProjectForAOTOnHelix.proj +++ b/src/mono/msbuild/apple/data/ProxyProjectForAOTOnHelix.proj @@ -7,7 +7,6 @@ $([MSBuild]::NormalizeDirectory($(TestRootDir), '..', 'extraFiles')) $([MSBuild]::NormalizeDirectory($(TestRootDir), '..', 'obj')) - ConfigureTrimming;_AdjustTrimmedAssembliesToBundle;$(AppleBuildDependsOn) _PublishRuntimePack;_PrepareForAppleBuildAppOnHelix;$(AppleBuildDependsOn);_AfterAppleBuildOnHelix true @@ -71,7 +70,7 @@ - + <_ExtraFiles Include="$(ExtraFilesPath)**\*" /> @@ -95,14 +94,6 @@ - - - - - - - - - - - - - - - - diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs index 46c8f2ce132870..e2406c873b986c 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/BlazorWasmTestBase.cs @@ -46,11 +46,11 @@ public void InitBlazorWasmProjectDir(string id, string targetFramework = Default public string CreateBlazorWasmTemplateProject(string id) { InitBlazorWasmProjectDir(id); - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("new blazorwasm") - .EnsureSuccessful(); + using DotNetCommand dotnetCommand = new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false); + CommandResult result = dotnetCommand.WithWorkingDirectory(_projectDir!) + .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .ExecuteWithCapturedOutput("new blazorwasm") + .EnsureSuccessful(); return Path.Combine(_projectDir!, $"{id}.csproj"); } @@ -195,12 +195,12 @@ public async Task BlazorRunTest(string runArgs, runOptions.ServerEnvironment?.ToList().ForEach( kv => s_buildEnv.EnvVars[kv.Key] = kv.Value); - using var runCommand = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(workingDirectory); + using RunCommand runCommand = new RunCommand(s_buildEnv, _testOutput); + ToolCommand cmd = runCommand.WithWorkingDirectory(workingDirectory); await using var runner = new BrowserRunner(_testOutput); var page = await runner.RunAsync( - runCommand, + cmd, runArgs, onConsoleMessage: OnConsoleMessage, onServerMessage: runOptions.OnServerMessage, diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/CleanTests.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/CleanTests.cs index db3c7da2243ac0..122aa274962373 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/CleanTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/CleanTests.cs @@ -40,11 +40,11 @@ public void Blazor_BuildThenClean_NativeRelinking(string config) Assert.True(Directory.Exists(relinkDir), $"Could not find expected relink dir: {relinkDir}"); string logPath = Path.Combine(s_buildEnv.LogRootPath, id, $"{id}-clean.binlog"); - new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("build", "-t:Clean", $"-p:Configuration={config}", $"-bl:{logPath}") - .EnsureSuccessful(); + using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput) + .WithWorkingDirectory(_projectDir!); + cmd.WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .ExecuteWithCapturedOutput("build", "-t:Clean", $"-p:Configuration={config}", $"-bl:{logPath}") + .EnsureSuccessful(); AssertEmptyOrNonExistentDirectory(relinkDir); } @@ -88,9 +88,9 @@ private void Blazor_BuildNativeNonNative_ThenCleanTest(string config, bool first Assert.True(Directory.Exists(relinkDir), $"Could not find expected relink dir: {relinkDir}"); string logPath = Path.Combine(s_buildEnv.LogRootPath, id, $"{id}-clean.binlog"); - new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _projectDir!) + using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput) + .WithWorkingDirectory(_projectDir!); + cmd.WithEnvironmentVariable("NUGET_PACKAGES", _projectDir!) .ExecuteWithCapturedOutput("build", "-t:Clean", $"-p:Configuration={config}", $"-bl:{logPath}") .EnsureSuccessful(); diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests2.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests2.cs index 23c002b454d91c..00a47837523ce4 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests2.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests2.cs @@ -59,11 +59,11 @@ private CommandResult PublishForRequiresWorkloadTest(string config, string extra extraItems: extraItems); string publishLogPath = Path.Combine(s_buildEnv.LogRootPath, id, $"{id}.binlog"); - return new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("publish", - $"-bl:{publishLogPath}", - $"-p:Configuration={config}"); + using DotNetCommand cmd = new DotNetCommand(s_buildEnv, _testOutput); + return cmd.WithWorkingDirectory(_projectDir!) + .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .ExecuteWithCapturedOutput("publish", + $"-bl:{publishLogPath}", + $"-p:Configuration={config}"); } } diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs index 4d82356b103790..a7f39ce9d3341a 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs @@ -99,17 +99,16 @@ public void BugRegression_60479_WithRazorClassLib() string wasmProjectDir = Path.Combine(_projectDir!, "wasm"); string wasmProjectFile = Path.Combine(wasmProjectDir, "wasm.csproj"); Directory.CreateDirectory(wasmProjectDir); - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(wasmProjectDir) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("new blazorwasm") - .EnsureSuccessful(); + using DotNetCommand cmd = new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false); + cmd.WithWorkingDirectory(wasmProjectDir) + .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .ExecuteWithCapturedOutput("new blazorwasm") + .EnsureSuccessful(); string razorProjectDir = Path.Combine(_projectDir!, "RazorClassLibrary"); Directory.CreateDirectory(razorProjectDir); - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(razorProjectDir) + cmd.WithWorkingDirectory(razorProjectDir) .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) .ExecuteWithCapturedOutput("new razorclasslib") .EnsureSuccessful(); diff --git a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs index cccc44efb621ee..53f25caa3a525f 100644 --- a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs @@ -16,6 +16,7 @@ using Xunit; using Xunit.Abstractions; using Xunit.Sdk; +using Microsoft.Build.Logging.StructuredLogger; #nullable enable @@ -163,10 +164,10 @@ public BuildTestBase(ProjectProviderBase providerBase, ITestOutputHelper output, if (buildProjectOptions.Publish && buildProjectOptions.BuildOnlyAfterPublish) commandLineArgs.Append("-p:WasmBuildOnlyAfterPublish=true"); - var cmd = new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .WithEnvironmentVariables(buildProjectOptions.ExtraBuildEnvironmentVariables); + using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput) + .WithWorkingDirectory(_projectDir!); + cmd.WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .WithEnvironmentVariables(buildProjectOptions.ExtraBuildEnvironmentVariables); if (UseWBTOverridePackTargets && s_buildEnv.IsWorkload) cmd.WithEnvironmentVariable("WBTOverrideRuntimePack", "true"); @@ -176,9 +177,48 @@ public BuildTestBase(ProjectProviderBase providerBase, ITestOutputHelper output, else if (res.ExitCode == 0) throw new XunitException($"Build should have failed, but it didn't. Process exited with exitCode : {res.ExitCode}"); + // Ensure we got all output. + string[] successMessages = ["Build succeeded"]; + string[] errorMessages = ["Build failed", "Build FAILED", "Restore failed", "Stopping the build"]; + if ((res.ExitCode == 0 && successMessages.All(m => !res.Output.Contains(m))) || (res.ExitCode != 0 && errorMessages.All(m => !res.Output.Contains(m)))) + { + _testOutput.WriteLine("Replacing dotnet process output with messages from binlog"); + + var outputBuilder = new StringBuilder(); + var buildRoot = BinaryLog.ReadBuild(logFilePath); + buildRoot.VisitAllChildren(m => + { + if (m is Message || m is Error || m is Warning) + { + var context = GetBinlogMessageContext(m); + outputBuilder.AppendLine($"{context}{m.Title}"); + } + }); + + res = new CommandResult(res.StartInfo, res.ExitCode, outputBuilder.ToString()); + } + return (res, logFilePath); } + private string GetBinlogMessageContext(TextNode node) + { + var currentNode = node; + while (currentNode != null) + { + if (currentNode is Error error) + { + return $"{error.File}({error.LineNumber},{error.ColumnNumber}): error {error.Code}: "; + } + else if (currentNode is Warning warning) + { + return $"{warning.File}({warning.LineNumber},{warning.ColumnNumber}): warning {warning.Code}: "; + } + currentNode = currentNode.Parent as TextNode; + } + return string.Empty; + } + protected string RunAndTestWasmApp(BuildArgs buildArgs, RunHost host, string id, @@ -447,6 +487,7 @@ public static (int exitCode, string buildOutput) RunProcess(string path, _testOutput.WriteLine($"WorkingDirectory: {workingDir}"); StringBuilder outputBuilder = new(); object syncObj = new(); + bool isDisposed = false; var processStartInfo = new ProcessStartInfo { @@ -502,11 +543,13 @@ public static (int exitCode, string buildOutput) RunProcess(string path, using CancellationTokenSource cts = new(); cts.CancelAfter(timeoutMs ?? s_defaultPerTestTimeoutMs); - await process.WaitForExitAsync(cts.Token); - - if (cts.IsCancellationRequested) + try { - // process didn't exit + await process.WaitForExitAsync(cts.Token); + } + catch (OperationCanceledException) + { + // process didn't exit within timeout process.Kill(entireProcessTree: true); lock (syncObj) { @@ -520,6 +563,12 @@ public static (int exitCode, string buildOutput) RunProcess(string path, // https://learn.microsoft.com/dotnet/api/system.diagnostics.process.waitforexit?view=net-5.0#System_Diagnostics_Process_WaitForExit_System_Int32_ process.WaitForExit(); + // Mark as disposed before detaching handlers to prevent further TestOutput access + lock (syncObj) + { + isDisposed = true; + } + process.ErrorDataReceived -= logStdErr; process.OutputDataReceived -= logStdOut; process.CancelErrorRead(); @@ -533,7 +582,12 @@ public static (int exitCode, string buildOutput) RunProcess(string path, } catch (Exception ex) { - _testOutput.WriteLine($"-- exception -- {ex}"); + // Mark as disposed before writing to avoid potential race condition + lock (syncObj) + { + isDisposed = true; + } + TryWriteToTestOutput(_testOutput, $"-- exception -- {ex}", outputBuilder); throw; } @@ -541,9 +595,11 @@ void LogData(string label, string? message) { lock (syncObj) { + if (isDisposed) + return; if (message != null) { - _testOutput.WriteLine($"{label} {message}"); + TryWriteToTestOutput(_testOutput, $"{label} {message}", outputBuilder, label); } outputBuilder.AppendLine($"{label} {message}"); } @@ -587,6 +643,24 @@ public static string AddItemsPropertiesToProject(string projectFile, string? ext return projectFile; } + private static void TryWriteToTestOutput(ITestOutputHelper testOutput, string message, StringBuilder? outputBuffer = null, string? warningPrefix = null) + { + try + { + testOutput.WriteLine(message); + } + catch (InvalidOperationException) + { + // Test context has expired, but we still want to capture output in buffer + // for potential debugging purposes + if (outputBuffer != null) + { + string prefix = warningPrefix ?? ""; + outputBuffer.AppendLine($"{prefix}[WARNING: Test context expired, subsequent output may be incomplete]"); + } + } + } + public void Dispose() { if (_projectDir != null && _enablePerTestCleanup) diff --git a/src/mono/wasm/Wasm.Build.Tests/Common/RunHost.cs b/src/mono/wasm/Wasm.Build.Tests/Common/RunHost.cs index 137316ebb546c5..1208060464a9e7 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Common/RunHost.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Common/RunHost.cs @@ -15,6 +15,6 @@ public enum RunHost Firefox = 8, NodeJS = 16, - All = V8 | NodeJS | Chrome//| Firefox//Safari + All = V8 | Chrome//| NodeJS//Firefox//Safari } } diff --git a/src/mono/wasm/Wasm.Build.Tests/Common/ToolCommand.cs b/src/mono/wasm/Wasm.Build.Tests/Common/ToolCommand.cs index c8289da17350d6..4c7531a889007d 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Common/ToolCommand.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Common/ToolCommand.cs @@ -13,6 +13,8 @@ namespace Wasm.Build.Tests { public class ToolCommand : IDisposable { + private bool isDisposed = false; + private readonly object _lock = new object(); private string _label; protected ITestOutputHelper _testOutput; @@ -93,41 +95,45 @@ public virtual CommandResult ExecuteWithCapturedOutput(params string[] args) public virtual void Dispose() { - if (CurrentProcess is not null && !CurrentProcess.HasExited) + lock (_lock) { - CurrentProcess.Kill(entireProcessTree: true); - CurrentProcess.Dispose(); - CurrentProcess = null; + if (isDisposed) + return; + if (CurrentProcess is not null && !CurrentProcess.HasExited) + { + CurrentProcess.Kill(entireProcessTree: true); + CurrentProcess.Dispose(); + CurrentProcess = null; + } + isDisposed = true; } } protected virtual string GetFullArgs(params string[] args) => string.Join(" ", args); - private async Task ExecuteAsyncInternal(string executable, string args) { var output = new List(); CurrentProcess = CreateProcess(executable, args); - DataReceivedEventHandler errorHandler = (s, e) => + + void HandleDataReceived(DataReceivedEventArgs e, DataReceivedEventHandler? additionalHandler) { - if (e.Data == null) + if (e.Data == null || isDisposed) return; - string msg = $"[{_label}] {e.Data}"; - output.Add(msg); - _testOutput.WriteLine(msg); - ErrorDataReceived?.Invoke(s, e); - }; + lock (_lock) + { + if (e.Data == null || isDisposed) + return; - DataReceivedEventHandler outputHandler = (s, e) => - { - if (e.Data == null) - return; + string msg = $"[{_label}] {e.Data}"; + output.Add(msg); + TryWriteToTestOutput(msg, output); + additionalHandler?.Invoke(this, e); + } + } - string msg = $"[{_label}] {e.Data}"; - output.Add(msg); - _testOutput.WriteLine(msg); - OutputDataReceived?.Invoke(s, e); - }; + DataReceivedEventHandler errorHandler = (s, e) => HandleDataReceived(e, ErrorDataReceived); + DataReceivedEventHandler outputHandler = (s, e) => HandleDataReceived(e, OutputDataReceived); CurrentProcess.ErrorDataReceived += errorHandler; CurrentProcess.OutputDataReceived += outputHandler; @@ -148,6 +154,20 @@ private async Task ExecuteAsyncInternal(string executable, string string.Join(System.Environment.NewLine, output)); } + private void TryWriteToTestOutput(string message, List output) + { + try + { + _testOutput.WriteLine(message); + } + catch (InvalidOperationException) + { + // Test context may have expired, continue without logging to test output + // Add a marker to the output buffer so we know this happened + output.Add($"[{_label}] [WARNING: Test context expired, subsequent output may be incomplete]"); + } + } + private Process CreateProcess(string executable, string args) { var psi = new ProcessStartInfo diff --git a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs index dbaeba4bb1165b..6381b1ac41b944 100644 --- a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs @@ -35,8 +35,8 @@ public IcuShardingTests(ITestOutputHelper output, SharedBuildPerTestClassFixture .UnwrapItemsAsArrays(); [Theory] - [MemberData(nameof(IcuExpectedAndMissingCustomShardTestData), parameters: new object[] { false, RunHost.NodeJS | RunHost.Chrome })] - [MemberData(nameof(IcuExpectedAndMissingCustomShardTestData), parameters: new object[] { true, RunHost.NodeJS | RunHost.Chrome })] + [MemberData(nameof(IcuExpectedAndMissingCustomShardTestData), parameters: new object[] { false, RunHost.Chrome })] + [MemberData(nameof(IcuExpectedAndMissingCustomShardTestData), parameters: new object[] { true, RunHost.Chrome })] public void CustomIcuShard(BuildArgs buildArgs, string shardName, string testedLocales, bool onlyPredefinedCultures, RunHost host, string id) => TestIcuShards(buildArgs, shardName, testedLocales, host, id, onlyPredefinedCultures); diff --git a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs index c04d5c1114dc00..221850f27a188d 100644 --- a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs +++ b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs @@ -32,8 +32,8 @@ public IcuShardingTests2(ITestOutputHelper output, SharedBuildPerTestClassFixtur [Theory] - [MemberData(nameof(IcuExpectedAndMissingShardFromRuntimePackTestData), parameters: new object[] { false, RunHost.NodeJS | RunHost.Chrome })] - [MemberData(nameof(IcuExpectedAndMissingShardFromRuntimePackTestData), parameters: new object[] { true, RunHost.NodeJS | RunHost.Chrome })] + [MemberData(nameof(IcuExpectedAndMissingShardFromRuntimePackTestData), parameters: new object[] { false, RunHost.Chrome })] + [MemberData(nameof(IcuExpectedAndMissingShardFromRuntimePackTestData), parameters: new object[] { true, RunHost.Chrome })] public void DefaultAvailableIcuShardsFromRuntimePack(BuildArgs buildArgs, string shardName, string testedLocales, RunHost host, string id) => TestIcuShards(buildArgs, shardName, testedLocales, host, id); } \ No newline at end of file diff --git a/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs b/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs index 0f58d24ac9f3d0..5137de3c096a2b 100644 --- a/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs @@ -37,8 +37,8 @@ public IcuTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildCo .UnwrapItemsAsArrays(); [Theory] - [MemberData(nameof(FullIcuWithInvariantTestData), parameters: new object[] { false, RunHost.NodeJS | RunHost.Chrome })] - [MemberData(nameof(FullIcuWithInvariantTestData), parameters: new object[] { true, RunHost.NodeJS | RunHost.Chrome })] + [MemberData(nameof(FullIcuWithInvariantTestData), parameters: new object[] { false, RunHost.Chrome })] + [MemberData(nameof(FullIcuWithInvariantTestData), parameters: new object[] { true, RunHost.Chrome })] public void FullIcuFromRuntimePackWithInvariant(BuildArgs buildArgs, bool invariant, bool fullIcu, string testedLocales, RunHost host, string id) { string projectName = $"fullIcuInvariant_{fullIcu}_{invariant}_{buildArgs.Config}_{buildArgs.AOT}"; @@ -60,8 +60,8 @@ public void FullIcuFromRuntimePackWithInvariant(BuildArgs buildArgs, bool invari } [Theory] - [MemberData(nameof(FullIcuWithICustomIcuTestData), parameters: new object[] { false, RunHost.NodeJS | RunHost.Chrome })] - [MemberData(nameof(FullIcuWithICustomIcuTestData), parameters: new object[] { true, RunHost.NodeJS | RunHost.Chrome })] + [MemberData(nameof(FullIcuWithICustomIcuTestData), parameters: new object[] { false, RunHost.Chrome })] + [MemberData(nameof(FullIcuWithICustomIcuTestData), parameters: new object[] { true, RunHost.Chrome })] public void FullIcuFromRuntimePackWithCustomIcu(BuildArgs buildArgs, bool fullIcu, RunHost host, string id) { string projectName = $"fullIcuCustom_{fullIcu}_{buildArgs.Config}_{buildArgs.AOT}"; diff --git a/src/mono/wasm/Wasm.Build.Tests/MainWithArgsTests.cs b/src/mono/wasm/Wasm.Build.Tests/MainWithArgsTests.cs index fc6099fb727987..c931fe0beeb6de 100644 --- a/src/mono/wasm/Wasm.Build.Tests/MainWithArgsTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/MainWithArgsTests.cs @@ -38,13 +38,13 @@ public static async System.Threading.Tasks.Task Main(string[] args) }", buildArgs, args, host, id); - [Theory] - [MemberData(nameof(MainWithArgsTestData), parameters: new object[] { /*aot*/ false, RunHost.NodeJS })] - //[MemberData(nameof(MainWithArgsTestData), parameters: new object[] { /*aot*/ true, RunHost.All })] - public void TopLevelWithArgs(BuildArgs buildArgs, string[] args, RunHost host, string id) - => TestMainWithArgs("top_level_args", - @"##CODE## return await System.Threading.Tasks.Task.FromResult(42 + count);", - buildArgs, args, host, id); + // [Theory] + // [MemberData(nameof(MainWithArgsTestData), parameters: new object[] { /*aot*/ false, RunHost.NodeJS })] + // //[MemberData(nameof(MainWithArgsTestData), parameters: new object[] { /*aot*/ true, RunHost.All })] + // public void TopLevelWithArgs(BuildArgs buildArgs, string[] args, RunHost host, string id) + // => TestMainWithArgs("top_level_args", + // @"##CODE## return await System.Threading.Tasks.Task.FromResult(42 + count);", + // buildArgs, args, host, id); [Theory] [MemberData(nameof(MainWithArgsTestData), parameters: new object[] { /*aot*/ false, RunHost.All })] diff --git a/src/mono/wasm/Wasm.Build.Tests/NonWasmTemplateBuildTests.cs b/src/mono/wasm/Wasm.Build.Tests/NonWasmTemplateBuildTests.cs index 90ce88af865f72..e85a212f83d49f 100644 --- a/src/mono/wasm/Wasm.Build.Tests/NonWasmTemplateBuildTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/NonWasmTemplateBuildTests.cs @@ -112,22 +112,18 @@ private void NonWasmConsoleBuild(string config, File.WriteAllText(Path.Combine(_projectDir, "Directory.Build.props"), ""); File.WriteAllText(Path.Combine(_projectDir, "Directory.Build.targets"), directoryBuildTargets); - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput("new console --no-restore") - .EnsureSuccessful(); + using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) + .WithWorkingDirectory(_projectDir!); + cmd.ExecuteWithCapturedOutput("new console --no-restore") + .EnsureSuccessful(); - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"build -restore -c {config} -bl:{Path.Combine(s_buildEnv.LogRootPath, $"{id}.binlog")} {extraBuildArgs} -f {targetFramework}") - .EnsureSuccessful(); + cmd.ExecuteWithCapturedOutput($"build -restore -c {config} -bl:{Path.Combine(s_buildEnv.LogRootPath, $"{id}.binlog")} {extraBuildArgs} -f {targetFramework}") + .EnsureSuccessful(); if (shouldRun) { - var result = new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"run -c {config} -f {targetFramework} --no-build") - .EnsureSuccessful(); + CommandResult result = cmd.ExecuteWithCapturedOutput($"run -c {config} -f {targetFramework} --no-build") + .EnsureSuccessful(); Assert.Contains("Hello, World!", result.Output); } diff --git a/src/mono/wasm/Wasm.Build.Tests/Templates/NativeBuildTests.cs b/src/mono/wasm/Wasm.Build.Tests/Templates/NativeBuildTests.cs index 37f9b6aa46ca25..5a72a3da5a7713 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Templates/NativeBuildTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Templates/NativeBuildTests.cs @@ -45,10 +45,10 @@ public void BuildWithUndefinedNativeSymbol(bool allowUndefined) File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), code); File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "native-libs", "undefined-symbol.c"), Path.Combine(_projectDir!, "undefined_xyz.c")); - CommandResult result = new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("build", "-c Release"); + using DotNetCommand cmd = new DotNetCommand(s_buildEnv, _testOutput); + CommandResult result = cmd.WithWorkingDirectory(_projectDir!) + .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) + .ExecuteWithCapturedOutput("build", "-c Release"); if (allowUndefined) { @@ -61,41 +61,5 @@ public void BuildWithUndefinedNativeSymbol(bool allowUndefined) Assert.Contains("Use '-p:WasmAllowUndefinedSymbols=true' to allow undefined symbols", result.Output); } } - - [Theory] - [InlineData("Debug")] - [InlineData("Release")] - public void ProjectWithDllImportsRequiringMarshalIlGen_ArrayTypeParameter(string config) - { - string id = $"dllimport_incompatible_{GetRandomId()}"; - string projectPath = CreateWasmTemplateProject(id, template: "wasmconsole"); - - string nativeSourceFilename = "incompatible_type.c"; - string nativeCode = "void call_needing_marhsal_ilgen(void *x) {}"; - File.WriteAllText(path: Path.Combine(_projectDir!, nativeSourceFilename), nativeCode); - - AddItemsPropertiesToProject( - projectPath, - extraItems: "" - ); - - File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "marshal_ilgen_test.cs"), - Path.Combine(_projectDir!, "Program.cs"), - overwrite: true); - - CommandResult result = new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .ExecuteWithCapturedOutput("build", $"-c {config} -bl"); - - Assert.True(result.ExitCode == 0, "Expected build to succeed"); - - CommandResult res = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {config}") - .EnsureSuccessful(); - Assert.Contains("Hello, Console!", res.Output); - Assert.Contains("Hello, World! Greetings from node version", res.Output); - } } } diff --git a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs index b32b95debd879f..64c7a954325ea3 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs @@ -167,117 +167,9 @@ public void BrowserBuildThenPublish(string config) UseCache: false)); } - [Theory] - [InlineData("Debug")] - [InlineData("Release")] - public void ConsoleBuildThenPublish(string config) - { - string id = $"{config}_{GetRandomId()}"; - string projectFile = CreateWasmTemplateProject(id, "wasmconsole"); - string projectName = Path.GetFileNameWithoutExtension(projectFile); - - UpdateConsoleMainJs(); - - var buildArgs = new BuildArgs(projectName, config, false, id, null); - buildArgs = ExpandBuildArgs(buildArgs); - - BuildTemplateProject(buildArgs, - id: id, - new BuildProjectOptions( - DotnetWasmFromRuntimePack: true, - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: false, - TargetFramework: BuildTestBase.DefaultTargetFramework, - IsBrowserProject: false - )); - - CommandResult res = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {config}") - .EnsureSuccessful(); - Assert.Contains("Hello, Console!", res.Output); - - if (!_buildContext.TryGetBuildFor(buildArgs, out BuildProduct? product)) - throw new XunitException($"Test bug: could not get the build product in the cache"); - - File.Move(product!.LogFile, Path.ChangeExtension(product.LogFile!, ".first.binlog")); - - _testOutput.WriteLine($"{Environment.NewLine}Publishing with no changes ..{Environment.NewLine}"); - - bool expectRelinking = config == "Release"; - BuildTemplateProject(buildArgs, - id: id, - new BuildProjectOptions( - DotnetWasmFromRuntimePack: !expectRelinking, - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: true, - TargetFramework: BuildTestBase.DefaultTargetFramework, - UseCache: false, - IsBrowserProject: false)); - } - - [Theory] - [InlineData("Debug", false)] - [InlineData("Debug", true)] - [InlineData("Release", false)] - [InlineData("Release", true)] - public void ConsoleBuildAndRunDefault(string config, bool relinking) - => ConsoleBuildAndRun(config, relinking, string.Empty, DefaultTargetFramework, addFrameworkArg: true); - - [Theory] - // [ActiveIssue("https://github.com/dotnet/runtime/issues/79313")] - // [InlineData("Debug", "-f net7.0", "net7.0")] - //[InlineData("Debug", "-f net8.0", "net8.0")] - [InlineData("Debug", "-f net9.0", "net9.0")] - public void ConsoleBuildAndRunForSpecificTFM(string config, string extraNewArgs, string expectedTFM) - => ConsoleBuildAndRun(config, false, extraNewArgs, expectedTFM, addFrameworkArg: extraNewArgs?.Length == 0); - - private void ConsoleBuildAndRun(string config, bool relinking, string extraNewArgs, string expectedTFM, bool addFrameworkArg) - { - string id = $"{config}_{GetRandomId()}"; - string projectFile = CreateWasmTemplateProject(id, "wasmconsole", extraNewArgs, addFrameworkArg: addFrameworkArg); - string projectName = Path.GetFileNameWithoutExtension(projectFile); - - UpdateConsoleProgramCs(); - UpdateConsoleMainJs(); - if (relinking) - AddItemsPropertiesToProject(projectFile, "true"); - - var buildArgs = new BuildArgs(projectName, config, false, id, null); - buildArgs = ExpandBuildArgs(buildArgs); - - BuildTemplateProject(buildArgs, - id: id, - new BuildProjectOptions( - DotnetWasmFromRuntimePack: !relinking, - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: false, - TargetFramework: expectedTFM, - IsBrowserProject: false - )); - - CommandResult res = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {config} x y z") - .EnsureExitCode(42); - - Assert.Contains("args[0] = x", res.Output); - Assert.Contains("args[1] = y", res.Output); - Assert.Contains("args[2] = z", res.Output); - } - public static TheoryData TestDataForAppBundleDir() { var data = new TheoryData(); - AddTestData(forConsole: true, runOutsideProjectDirectory: false); - AddTestData(forConsole: true, runOutsideProjectDirectory: true); - AddTestData(forConsole: false, runOutsideProjectDirectory: false); AddTestData(forConsole: false, runOutsideProjectDirectory: true); @@ -355,7 +247,7 @@ private Task ConsoleRunWithAndThenWithoutBuildAsync(string config, string extraP using var cmd = new RunCommand(s_buildEnv, _testOutput, label: id) .WithWorkingDirectory(workingDir) .WithEnvironmentVariables(s_buildEnv.EnvVars); - var res = cmd.ExecuteWithCapturedOutput(runArgs).EnsureExitCode(42); + CommandResult res = cmd.ExecuteWithCapturedOutput(runArgs).EnsureExitCode(42); Assert.Contains("args[0] = x", res.Output); Assert.Contains("args[1] = y", res.Output); @@ -370,7 +262,7 @@ private Task ConsoleRunWithAndThenWithoutBuildAsync(string config, string extraP runArgs += " x y z"; using var cmd = new RunCommand(s_buildEnv, _testOutput, label: id) .WithWorkingDirectory(workingDir); - var res = cmd.ExecuteWithCapturedOutput(runArgs).EnsureExitCode(42); + CommandResult res = cmd.ExecuteWithCapturedOutput(runArgs).EnsureExitCode(42); Assert.Contains("args[0] = x", res.Output); Assert.Contains("args[1] = y", res.Output); @@ -380,74 +272,6 @@ private Task ConsoleRunWithAndThenWithoutBuildAsync(string config, string extraP return Task.CompletedTask; } - public static TheoryData TestDataForConsolePublishAndRun() - { - var data = new TheoryData(); - data.Add("Debug", false, false); - data.Add("Debug", false, true); - data.Add("Release", false, false); // Release relinks by default - data.Add("Release", true, false); - - return data; - } - - [Theory] - [MemberData(nameof(TestDataForConsolePublishAndRun))] - public void ConsolePublishAndRun(string config, bool aot, bool relinking) - { - string id = $"{config}_{GetRandomId()}"; - string projectFile = CreateWasmTemplateProject(id, "wasmconsole"); - string projectName = Path.GetFileNameWithoutExtension(projectFile); - - UpdateConsoleProgramCs(); - UpdateConsoleMainJs(); - - if (aot) - { - // FIXME: pass envvars via the environment, once that is supported - UpdateMainJsEnvironmentVariables(("MONO_LOG_MASK", "aot"), ("MONO_LOG_LEVEL", "debug")); - AddItemsPropertiesToProject(projectFile, "true"); - } - else if (relinking) - { - AddItemsPropertiesToProject(projectFile, "true"); - } - - var buildArgs = new BuildArgs(projectName, config, aot, id, null); - buildArgs = ExpandBuildArgs(buildArgs); - - bool expectRelinking = config == "Release" || aot || relinking; - BuildTemplateProject(buildArgs, - id: id, - new BuildProjectOptions( - DotnetWasmFromRuntimePack: !expectRelinking, - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: true, - TargetFramework: BuildTestBase.DefaultTargetFramework, - UseCache: false, - IsBrowserProject: false)); - - new RunCommand(s_buildEnv, _testOutput, label: id) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput("--info") - .EnsureExitCode(0); - - string runArgs = $"run --no-silent --no-build -c {config} -v diag"; - runArgs += " x y z"; - var res = new RunCommand(s_buildEnv, _testOutput, label: id) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput(runArgs) - .EnsureExitCode(42); - - if (aot) - Assert.Contains($"AOT: image '{Path.GetFileNameWithoutExtension(projectFile)}' found", res.Output); - Assert.Contains("args[0] = x", res.Output); - Assert.Contains("args[1] = y", res.Output); - Assert.Contains("args[2] = z", res.Output); - } - public static IEnumerable BrowserBuildAndRunTestData() { yield return new object?[] { "", BuildTestBase.DefaultTargetFramework, DefaultRuntimeAssetsRelativePath }; @@ -474,10 +298,10 @@ public async Task BrowserBuildAndRun(string extraNewArgs, string targetFramework UpdateBrowserMainJs(targetFramework, runtimeAssetsRelativePath); - new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .Execute($"build -c {config} -bl:{Path.Combine(s_buildEnv.LogRootPath, $"{id}.binlog")} {(runtimeAssetsRelativePath != DefaultRuntimeAssetsRelativePath ? "-p:WasmRuntimeAssetsLocation=" + runtimeAssetsRelativePath : "")}") - .EnsureSuccessful(); + using ToolCommand cmd = new DotNetCommand(s_buildEnv, _testOutput) + .WithWorkingDirectory(_projectDir!); + cmd.Execute($"build -c {config} -bl:{Path.Combine(s_buildEnv.LogRootPath, $"{id}.binlog")} {(runtimeAssetsRelativePath != DefaultRuntimeAssetsRelativePath ? "-p:WasmRuntimeAssetsLocation=" + runtimeAssetsRelativePath : "")}") + .EnsureSuccessful(); using var runCommand = new RunCommand(s_buildEnv, _testOutput) .WithWorkingDirectory(_projectDir!); @@ -488,106 +312,6 @@ public async Task BrowserBuildAndRun(string extraNewArgs, string targetFramework Assert.Contains("Hello, Browser!", string.Join(Environment.NewLine, runner.OutputLines)); } - [Theory] - [InlineData("Debug", /*appendRID*/ true, /*useArtifacts*/ false)] - [InlineData("Debug", /*appendRID*/ true, /*useArtifacts*/ true)] - [InlineData("Debug", /*appendRID*/ false, /*useArtifacts*/ true)] - [InlineData("Debug", /*appendRID*/ false, /*useArtifacts*/ false)] - public void BuildAndRunForDifferentOutputPaths(string config, bool appendRID, bool useArtifacts) - { - string id = $"{config}_{GetRandomId()}"; - string projectFile = CreateWasmTemplateProject(id, "wasmconsole"); - string projectName = Path.GetFileNameWithoutExtension(projectFile); - - string extraPropertiesForDBP = ""; - if (appendRID) - extraPropertiesForDBP += "true"; - if (useArtifacts) - extraPropertiesForDBP += "true."; - - string projectDirectory = Path.GetDirectoryName(projectFile)!; - if (!string.IsNullOrEmpty(extraPropertiesForDBP)) - AddItemsPropertiesToProject(Path.Combine(projectDirectory, "Directory.Build.props"), - extraPropertiesForDBP); - - var buildOptions = new BuildProjectOptions( - DotnetWasmFromRuntimePack: true, - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: false, - TargetFramework: DefaultTargetFramework, - IsBrowserProject: false); - if (useArtifacts) - { - buildOptions = buildOptions with - { - BinFrameworkDir = Path.Combine( - projectDirectory, - "bin", - id, - $"{config.ToLower()}_{BuildEnvironment.DefaultRuntimeIdentifier}", - "AppBundle", - "_framework") - }; - } - - var buildArgs = new BuildArgs(projectName, config, false, id, null); - buildArgs = ExpandBuildArgs(buildArgs); - BuildTemplateProject(buildArgs, id: id, buildOptions); - - CommandResult res = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {config} x y z") - .EnsureSuccessful(); - } - - [Theory] - [InlineData("", true)] // Default case - [InlineData("false", false)] // the other case - public void Test_WasmStripILAfterAOT(string stripILAfterAOT, bool expectILStripping) - { - string config = "Release"; - string id = $"strip_{config}_{GetRandomId()}"; - string projectFile = CreateWasmTemplateProject(id, "wasmconsole"); - string projectName = Path.GetFileNameWithoutExtension(projectFile); - string projectDirectory = Path.GetDirectoryName(projectFile)!; - bool aot = true; - - UpdateConsoleProgramCs(); - UpdateConsoleMainJs(); - - string extraProperties = "true"; - if (!string.IsNullOrEmpty(stripILAfterAOT)) - extraProperties += $"{stripILAfterAOT}"; - AddItemsPropertiesToProject(projectFile, extraProperties); - - var buildArgs = new BuildArgs(projectName, config, aot, id, null); - buildArgs = ExpandBuildArgs(buildArgs); - - BuildTemplateProject(buildArgs, - id: id, - new BuildProjectOptions( - CreateProject: false, - HasV8Script: false, - MainJS: "main.mjs", - Publish: true, - TargetFramework: BuildTestBase.DefaultTargetFramework, - UseCache: false, - IsBrowserProject: false, - AssertAppBundle: false)); - - string runArgs = $"run --no-silent --no-build -c {config}"; - var res = new RunCommand(s_buildEnv, _testOutput, label: id) - .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput(runArgs) - .EnsureExitCode(42); - - string frameworkDir = Path.Combine(projectDirectory, "bin", config, BuildTestBase.DefaultTargetFramework, "browser-wasm", "AppBundle", "_framework"); - string objBuildDir = Path.Combine(projectDirectory, "obj", config, BuildTestBase.DefaultTargetFramework, "browser-wasm", "wasm", "for-publish"); - TestWasmStripILAfterAOTOutput(objBuildDir, frameworkDir, expectILStripping, _testOutput); - } - internal static void TestWasmStripILAfterAOTOutput(string objBuildDir, string frameworkDir, bool expectILStripping, ITestOutputHelper testOutput) { string origAssemblyDir = Path.Combine(objBuildDir, "aot-in"); diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs index 4ef606b784e45b..ea1037e27872ac 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/SatelliteLoadingTests.cs @@ -77,8 +77,8 @@ public async Task LoadSatelliteAssemblyFromReference() // Build the library var libraryCsprojPath = Path.GetFullPath(Path.Combine(_projectDir!, "..", "ResourceLibrary")); - new DotNetCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(libraryCsprojPath) + using DotNetCommand cmd = new DotNetCommand(s_buildEnv, _testOutput); + CommandResult res = cmd.WithWorkingDirectory(libraryCsprojPath) .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) .ExecuteWithCapturedOutput("build -c Release") .EnsureSuccessful(); diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmAppBuilderDebugLevelTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmAppBuilderDebugLevelTests.cs index 83809b3c2a9a3a..bf8c3272960b36 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmAppBuilderDebugLevelTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/WasmAppBuilderDebugLevelTests.cs @@ -35,8 +35,8 @@ protected override void SetupProject(string projectId) protected override Task RunForBuild(string configuration) { - CommandResult res = new RunCommand(s_buildEnv, _testOutput) - .WithWorkingDirectory(_projectDir!) + using RunCommand cmd = new RunCommand(s_buildEnv, _testOutput); + CommandResult res = cmd.WithWorkingDirectory(_projectDir!) .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {configuration}"); return Task.FromResult(ProcessRunOutput(res)); @@ -61,8 +61,8 @@ 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!) + using RunCommand cmd = new RunCommand(s_buildEnv, _testOutput); + CommandResult res = cmd.WithWorkingDirectory(_projectDir!) .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {configuration}"); return Task.FromResult(ProcessRunOutput(res)); diff --git a/src/mono/wasm/Wasm.Build.Tests/Wasm.Build.Tests.csproj b/src/mono/wasm/Wasm.Build.Tests/Wasm.Build.Tests.csproj index 1c5ff4506db0ee..0b796d87bc0471 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Wasm.Build.Tests.csproj +++ b/src/mono/wasm/Wasm.Build.Tests/Wasm.Build.Tests.csproj @@ -47,6 +47,7 @@ + diff --git a/src/mono/wasm/Wasm.Build.Tests/WasmSIMDTests.cs b/src/mono/wasm/Wasm.Build.Tests/WasmSIMDTests.cs index e87ed3450fcd96..08ac8512665b75 100644 --- a/src/mono/wasm/Wasm.Build.Tests/WasmSIMDTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/WasmSIMDTests.cs @@ -41,7 +41,6 @@ public void Build_NoAOT_ShouldNotRelink(BuildArgs buildArgs, RunHost host, strin Assert.DoesNotContain("Compiling native assets with emcc", output); RunAndTestWasmApp(buildArgs, - extraXHarnessArgs: host == RunHost.NodeJS ? "--engine-arg=--experimental-wasm-simd --engine-arg=--experimental-wasm-eh" : "", expectedExitCode: 42, test: output => { diff --git a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs index 894097fed554b6..3ea5078b4da3e2 100644 --- a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs @@ -43,8 +43,8 @@ public string CreateWasmTemplateProject(string id, string template = "wasmbrowse if (addFrameworkArg) extraArgs += $" -f {DefaultTargetFramework}"; - new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false) - .WithWorkingDirectory(_projectDir!) + using DotNetCommand cmd = new DotNetCommand(s_buildEnv, _testOutput, useDefaultArgs: false); + CommandResult result = cmd.WithWorkingDirectory(_projectDir!) .ExecuteWithCapturedOutput($"new {template} {extraArgs}") .EnsureSuccessful(); diff --git a/src/native/corehost/apphost/standalone/hostfxr_resolver.cpp b/src/native/corehost/apphost/standalone/hostfxr_resolver.cpp index 073445177993cc..84c726ddbf75c0 100644 --- a/src/native/corehost/apphost/standalone/hostfxr_resolver.cpp +++ b/src/native/corehost/apphost/standalone/hostfxr_resolver.cpp @@ -118,6 +118,11 @@ hostfxr_resolver_t::hostfxr_resolver_t(const pal::string_t& app_root) { m_status_code = StatusCode::CoreHostLibMissingFailure; } + else if (!pal::is_path_fully_qualified(m_fxr_path)) + { + // We should always be loading hostfxr from an absolute path + m_status_code = StatusCode::CoreHostLibMissingFailure; + } else if (pal::load_library(&m_fxr_path, &m_hostfxr_dll)) { m_status_code = StatusCode::Success; diff --git a/src/native/corehost/apphost/static/CMakeLists.txt b/src/native/corehost/apphost/static/CMakeLists.txt index 3ea4d5d043ca3a..880510d06976b1 100644 --- a/src/native/corehost/apphost/static/CMakeLists.txt +++ b/src/native/corehost/apphost/static/CMakeLists.txt @@ -25,7 +25,7 @@ include_directories(${CLR_ARTIFACTS_OBJ_DIR}) # Generated version files add_subdirectory(../../hostmisc hostmisc) configure_file(${CLR_SRC_NATIVE_DIR}/corehost/configure.h.in ${GENERATED_INCLUDE_DIR}/corehost/configure.h) -target_include_directories(hostmisc PUBLIC ${GENERATED_INCLUDE_DIR}/corehost) +target_include_directories(hostmisc_interface INTERFACE ${GENERATED_INCLUDE_DIR}/corehost) if ((NOT DEFINED CLR_CMAKE_USE_SYSTEM_RAPIDJSON) OR (NOT CLR_CMAKE_USE_SYSTEM_RAPIDJSON)) include_directories(${CLR_SRC_NATIVE_DIR}/external/) diff --git a/src/native/corehost/build.cmd b/src/native/corehost/build.cmd index e5f535467ad38b..ff40b5048a66be 100644 --- a/src/native/corehost/build.cmd +++ b/src/native/corehost/build.cmd @@ -5,7 +5,7 @@ setlocal :: Initialize the args that will be passed to cmake set "__sourceDir=%~dp0" :: remove trailing slash -if %__sourceDir:~-1%==\ set "__ProjectDir=%__sourceDir:~0,-1%" +if "%__sourceDir:~-1%"=="\" set "__sourceDir=%__sourceDir:~0,-1%" set "__RepoRootDir=%__sourceDir%\..\..\.." :: normalize diff --git a/src/native/corehost/corehost.cpp b/src/native/corehost/corehost.cpp index c8a94312c5d6d4..c359c30fd7dd89 100644 --- a/src/native/corehost/corehost.cpp +++ b/src/native/corehost/corehost.cpp @@ -115,7 +115,7 @@ int exe_start(const int argc, const pal::char_t* argv[]) // Use realpath to find the path of the host, resolving any symlinks. // hostfxr (for dotnet) and the app dll (for apphost) are found relative to the host. pal::string_t host_path; - if (!pal::get_own_executable_path(&host_path) || !pal::realpath(&host_path)) + if (!pal::get_own_executable_path(&host_path) || !pal::fullpath(&host_path)) { trace::error(_X("Failed to resolve full path of the current executable [%s]"), host_path.c_str()); return StatusCode::CoreHostCurHostFindFailure; @@ -200,6 +200,7 @@ int exe_start(const int argc, const pal::char_t* argv[]) int rc = fxr.status_code(); if (rc != StatusCode::Success) { + trace::error(_X("Failed to resolve %s [%s]. Error code: 0x%x"), LIBFXR_NAME, fxr.fxr_path().empty() ? _X("not found") : fxr.fxr_path().c_str(), rc); return rc; } diff --git a/src/native/corehost/fxr/standalone/hostpolicy_resolver.cpp b/src/native/corehost/fxr/standalone/hostpolicy_resolver.cpp index 4e75400a04a81b..ff68220193d47b 100644 --- a/src/native/corehost/fxr/standalone/hostpolicy_resolver.cpp +++ b/src/native/corehost/fxr/standalone/hostpolicy_resolver.cpp @@ -180,6 +180,10 @@ int hostpolicy_resolver::load( return StatusCode::CoreHostLibMissingFailure; } + // We should always be loading hostpolicy from an absolute path + if (!pal::is_path_fully_qualified(host_path)) + return StatusCode::CoreHostLibMissingFailure; + // Load library // We expect to leak hostpolicy - just as we do not unload coreclr, we do not unload hostpolicy if (!pal::load_library(&host_path, &g_hostpolicy)) diff --git a/src/native/corehost/fxr_resolver.cpp b/src/native/corehost/fxr_resolver.cpp index a69bf7ced896a5..0d1cbddf9deb5c 100644 --- a/src/native/corehost/fxr_resolver.cpp +++ b/src/native/corehost/fxr_resolver.cpp @@ -95,7 +95,7 @@ bool fxr_resolver::try_get_path( bool search_global = (search & search_location_global) != 0; pal::string_t default_install_location; pal::string_t dotnet_root_env_var_name; - if (search_app_relative && pal::realpath(app_relative_dotnet_root)) + if (search_app_relative && pal::fullpath(app_relative_dotnet_root)) { trace::info(_X("Using app-relative location [%s] as runtime location."), app_relative_dotnet_root->c_str()); out_dotnet_root->assign(*app_relative_dotnet_root); diff --git a/src/native/corehost/fxr_resolver.h b/src/native/corehost/fxr_resolver.h index b61f3b8fb4e6dc..4764783b2afc7f 100644 --- a/src/native/corehost/fxr_resolver.h +++ b/src/native/corehost/fxr_resolver.h @@ -55,6 +55,10 @@ int load_fxr_and_get_delegate(hostfxr_delegate_type type, THostPathToConfigCallb return StatusCode::CoreHostLibMissingFailure; } + // We should always be loading hostfxr from an absolute path + if (!pal::is_path_fully_qualified(fxr_path)) + return StatusCode::CoreHostLibMissingFailure; + // Load library if (!pal::load_library(&fxr_path, &fxr)) { diff --git a/src/native/corehost/hostmisc/CMakeLists.txt b/src/native/corehost/hostmisc/CMakeLists.txt index f39b586590c62a..76669e902fa6ad 100644 --- a/src/native/corehost/hostmisc/CMakeLists.txt +++ b/src/native/corehost/hostmisc/CMakeLists.txt @@ -31,23 +31,34 @@ endif() # hostmisc must be an "object library" as we want to build it once # and embed the objects into static libraries we ship (like libnethost). -add_library(hostmisc OBJECT ${SOURCES}) - -target_include_directories(hostmisc PUBLIC +add_library(hostmisc_interface INTERFACE) +target_include_directories(hostmisc_interface INTERFACE ${CMAKE_CURRENT_BINARY_DIR} ${CLR_SRC_NATIVE_DIR} ${CMAKE_CURRENT_LIST_DIR}) if (MSVC) - target_sources(hostmisc PRIVATE ${HEADERS}) - target_link_libraries(hostmisc PUBLIC advapi32) + target_link_libraries(hostmisc_interface INTERFACE advapi32) endif() -target_link_libraries(hostmisc PUBLIC +target_link_libraries(hostmisc_interface INTERFACE ${CMAKE_DL_LIBS} $<$:${PTHREAD_LIB}>) if(CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARMV6) - target_link_libraries(hostmisc PUBLIC + target_link_libraries(hostmisc_interface INTERFACE $<$:${ATOMIC_SUPPORT_LIB}>) endif() + + +add_library(hostmisc STATIC ${SOURCES}) +target_link_libraries(hostmisc PUBLIC hostmisc_interface) +if (MSVC) + target_sources(hostmisc PRIVATE ${HEADERS}) +endif() + +add_library(hostmisc_public OBJECT ${SOURCES}) +target_link_libraries(hostmisc_public PUBLIC hostmisc_interface) +set_target_properties(hostmisc_public PROPERTIES INTERPROCEDURAL_OPTIMIZATION OFF) + +add_library(hostmisc::public ALIAS hostmisc_public) \ No newline at end of file diff --git a/src/native/corehost/hostmisc/pal.h b/src/native/corehost/hostmisc/pal.h index bde8446cc22cdf..94166e65d6f63a 100644 --- a/src/native/corehost/hostmisc/pal.h +++ b/src/native/corehost/hostmisc/pal.h @@ -335,6 +335,7 @@ namespace pal bool get_default_breadcrumb_store(string_t* recv); bool is_path_rooted(const string_t& path); + bool is_path_fully_qualified(const string_t& path); // Returns a platform-specific, user-private directory // that can be used for extracting out components of a single-file app. diff --git a/src/native/corehost/hostmisc/pal.unix.cpp b/src/native/corehost/hostmisc/pal.unix.cpp index 613902b5eaf3ac..265ad809d9af19 100644 --- a/src/native/corehost/hostmisc/pal.unix.cpp +++ b/src/native/corehost/hostmisc/pal.unix.cpp @@ -192,7 +192,7 @@ bool pal::get_loaded_library( { pal::string_t library_name_local; #if defined(TARGET_OSX) - if (!pal::is_path_rooted(library_name)) + if (!pal::is_path_fully_qualified(library_name)) library_name_local.append("@rpath/"); #endif library_name_local.append(library_name); @@ -200,7 +200,7 @@ bool pal::get_loaded_library( dll_t dll_maybe = dlopen(library_name_local.c_str(), RTLD_LAZY | RTLD_NOLOAD); if (dll_maybe == nullptr) { - if (pal::is_path_rooted(library_name)) + if (pal::is_path_fully_qualified(library_name)) return false; // dlopen on some systems only finds loaded libraries when given the full path @@ -265,6 +265,11 @@ bool pal::is_path_rooted(const pal::string_t& path) return path.front() == '/'; } +bool pal::is_path_fully_qualified(const pal::string_t& path) +{ + return is_path_rooted(path); +} + bool pal::get_default_breadcrumb_store(string_t* recv) { recv->clear(); diff --git a/src/native/corehost/hostmisc/pal.windows.cpp b/src/native/corehost/hostmisc/pal.windows.cpp index 3479c72aced1de..dacafb182899ec 100644 --- a/src/native/corehost/hostmisc/pal.windows.cpp +++ b/src/native/corehost/hostmisc/pal.windows.cpp @@ -641,9 +641,31 @@ pal::string_t pal::get_current_os_rid_platform() return ridOS; } +namespace +{ + bool is_directory_separator(pal::char_t c) + { + return c == DIR_SEPARATOR || c == L'/'; + } +} + bool pal::is_path_rooted(const string_t& path) { - return path.length() >= 2 && path[1] == L':'; + return (path.length() >= 1 && is_directory_separator(path[0])) // UNC or device paths + || (path.length() >= 2 && path[1] == L':'); // Drive letter paths +} + +bool pal::is_path_fully_qualified(const string_t& path) +{ + if (path.length() < 2) + return false; + + // Check for UNC and DOS device paths + if (is_directory_separator(path[0])) + return path[1] == L'?' || is_directory_separator(path[1]); + + // Check for drive absolute path - for example C:\. + return path.length() >= 3 && path[1] == L':' && is_directory_separator(path[2]); } // Returns true only if an env variable can be read successfully to be non-empty. diff --git a/src/native/corehost/hostpolicy/deps_resolver.cpp b/src/native/corehost/hostpolicy/deps_resolver.cpp index 55d9bd8f948868..88cb29ce6bffdb 100644 --- a/src/native/corehost/hostpolicy/deps_resolver.cpp +++ b/src/native/corehost/hostpolicy/deps_resolver.cpp @@ -601,7 +601,7 @@ void deps_resolver_t::init_known_entry_path(const deps_entry_t& entry, const pal return; } - assert(pal::is_path_rooted(path)); + assert(pal::is_path_fully_qualified(path)); if (m_coreclr_path.empty() && utils::ends_with(path, DIR_SEPARATOR_STR LIBCORECLR_NAME, false)) { m_coreclr_path = path; @@ -830,15 +830,21 @@ bool deps_resolver_t::resolve_probe_dirs( } } - // If the deps file is missing add known locations. - if (!get_app_deps().exists()) + // If the deps file is missing for the app, add known locations. + // For libhost scenarios, there is no app or app path + if (m_host_mode != host_mode_t::libhost && !get_app_deps().exists()) { + assert(!m_app_dir.empty()); + // App local path add_unique_path(asset_type, m_app_dir, &items, output, &non_serviced, core_servicing); - // deps_resolver treats being able to get the coreclr path as optional, so we ignore the return value here. - // The caller is responsible for checking whether coreclr path is set and handling as appropriate. - (void) file_exists_in_dir(m_app_dir, LIBCORECLR_NAME, &m_coreclr_path); + if (m_coreclr_path.empty()) + { + // deps_resolver treats being able to get the coreclr path as optional, so we ignore the return value here. + // The caller is responsible for checking whether coreclr path is set and handling as appropriate. + (void) file_exists_in_dir(m_app_dir, LIBCORECLR_NAME, &m_coreclr_path); + } } // Handle any additional deps.json that were specified. diff --git a/src/native/corehost/hostpolicy/standalone/coreclr_resolver.cpp b/src/native/corehost/hostpolicy/standalone/coreclr_resolver.cpp index b040c3e8546278..adcebeb9a029c5 100644 --- a/src/native/corehost/hostpolicy/standalone/coreclr_resolver.cpp +++ b/src/native/corehost/hostpolicy/standalone/coreclr_resolver.cpp @@ -13,6 +13,10 @@ bool coreclr_resolver_t::resolve_coreclr(const pal::string_t& libcoreclr_path, c pal::string_t coreclr_dll_path(libcoreclr_path); append_path(&coreclr_dll_path, LIBCORECLR_NAME); + // We should always be loading coreclr from an absolute path + if (!pal::is_path_fully_qualified(coreclr_dll_path)) + return false; + if (!pal::load_library(&coreclr_dll_path, &coreclr_resolver_contract.coreclr)) { return false; diff --git a/src/native/corehost/nethost/CMakeLists.txt b/src/native/corehost/nethost/CMakeLists.txt index 38b103b7178bee..f9a3a5086ec77f 100644 --- a/src/native/corehost/nethost/CMakeLists.txt +++ b/src/native/corehost/nethost/CMakeLists.txt @@ -34,7 +34,7 @@ if (WIN32) endif(WIN32) target_link_libraries(nethost PRIVATE hostmisc fxr_resolver) -target_link_libraries(libnethost PRIVATE hostmisc fxr_resolver) +target_link_libraries(libnethost PRIVATE hostmisc::public fxr_resolver) target_compile_definitions(nethost PRIVATE FEATURE_LIBHOST NETHOST_EXPORT) target_compile_definitions(libnethost PRIVATE FEATURE_LIBHOST NETHOST_EXPORT) diff --git a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt index c8239e4ee04b4a..8cd64461b55694 100644 --- a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt +++ b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt @@ -14,6 +14,10 @@ set(NATIVECOMPRESSION_SOURCES pal_zlib.c ) +if (CLR_CMAKE_TARGET_WIN32 AND NOT CLR_CMAKE_TARGET_ARCH_I386) + list(APPEND NATIVECOMPRESSION_SOURCES "zlib_allocator_win.c") +endif() + if (NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI) if (CLR_CMAKE_USE_SYSTEM_BROTLI) diff --git a/src/native/libs/System.IO.Compression.Native/pal_zlib.c b/src/native/libs/System.IO.Compression.Native/pal_zlib.c index a04f60aa876a88..8910bab7b6d7cb 100644 --- a/src/native/libs/System.IO.Compression.Native/pal_zlib.c +++ b/src/native/libs/System.IO.Compression.Native/pal_zlib.c @@ -8,6 +8,9 @@ #ifdef _WIN32 #define c_static_assert(e) static_assert((e),"") #include "../Common/pal_utilities.h" + #if _WIN64 + #include + #endif #else #include "pal_utilities.h" #endif @@ -39,6 +42,11 @@ static int32_t Init(PAL_ZStream* stream) { z_stream* zStream = (z_stream*)calloc(1, sizeof(z_stream)); +#ifdef _WIN64 + zStream->zalloc = z_custom_calloc; + zStream->zfree = z_custom_cfree; +#endif + stream->internalState = zStream; if (zStream != NULL) diff --git a/src/native/libs/System.IO.Compression.Native/zlib_allocator.h b/src/native/libs/System.IO.Compression.Native/zlib_allocator.h new file mode 100644 index 00000000000000..cadd00bb5879c5 --- /dev/null +++ b/src/native/libs/System.IO.Compression.Native/zlib_allocator.h @@ -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 // voidpf + +voidpf z_custom_calloc(voidpf opaque, unsigned items, unsigned size); + +void z_custom_cfree(voidpf opaque, voidpf ptr); diff --git a/src/native/libs/System.IO.Compression.Native/zlib_allocator_win.c b/src/native/libs/System.IO.Compression.Native/zlib_allocator_win.c new file mode 100644 index 00000000000000..239a46e0bfb64b --- /dev/null +++ b/src/native/libs/System.IO.Compression.Native/zlib_allocator_win.c @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include +#include +#include +#include /* _ASSERTE */ + +#include + +/* A custom allocator for zlib that uses a dedicated heap. + This provides better performance and avoids fragmentation + that can occur on Windows when using the default process heap. + */ + +// Gets the special heap we'll allocate from. +HANDLE GetZlibHeap() +{ + static HANDLE s_hPublishedHeap = NULL; + + // If already initialized, return immediately. + // We don't need a volatile read here since the publish is performed with release semantics. + if (s_hPublishedHeap != NULL) { return s_hPublishedHeap; } + + // Attempt to create a new heap. The heap will be dynamically sized. + HANDLE hNewHeap = HeapCreate(0, 0, 0); + + if (hNewHeap != NULL) + { + // We created a new heap. Attempt to publish it. + if (InterlockedCompareExchangePointer(&s_hPublishedHeap, hNewHeap, NULL) != NULL) + { + HeapDestroy(hNewHeap); // Somebody published before us. Destroy our heap. + hNewHeap = NULL; // Guard against accidental use later in the method. + } + } + else + { + // If we can't create a new heap, fall back to the process default heap. + InterlockedCompareExchangePointer(&s_hPublishedHeap, GetProcessHeap(), NULL); + } + + // Some thread - perhaps us, perhaps somebody else - published the heap. Return it. + // We don't need a volatile read here since the publish is performed with release semantics. + _ASSERTE(s_hPublishedHeap != NULL); + return s_hPublishedHeap; +} + +voidpf z_custom_calloc(opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + + SIZE_T cbRequested; + if (sizeof(items) + sizeof(size) <= sizeof(cbRequested)) + { + // multiplication can't overflow; no need for safeint + cbRequested = (SIZE_T)items * (SIZE_T)size; + } + else + { + // multiplication can overflow; go through safeint + if (FAILED(SIZETMult(items, size, &cbRequested))) { return NULL; } + } + + return HeapAlloc(GetZlibHeap(), 0, cbRequested); +} + +void z_custom_cfree(opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + if (ptr == NULL) { return; } // ok to free nullptr + + if (!HeapFree(GetZlibHeap(), 0, ptr)) { goto Fail; } + return; + +Fail: + __fastfail(FAST_FAIL_HEAP_METADATA_CORRUPTION); +} diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c index 0b6eab7e8c22bd..9bdd28616ad475 100644 --- a/src/native/libs/System.Native/pal_io.c +++ b/src/native/libs/System.Native/pal_io.c @@ -1883,6 +1883,53 @@ int32_t SystemNative_PWrite(intptr_t fd, void* buffer, int32_t bufferSize, int64 return (int32_t)count; } +#if (HAVE_PREADV || HAVE_PWRITEV) && !defined(TARGET_WASM) +static int GetAllowedVectorCount(IOVector* vectors, int32_t vectorCount) +{ +#if defined(IOV_MAX) + const int IovMax = IOV_MAX; +#else + // In theory all the platforms that we support define IOV_MAX, + // but we want to be extra safe and provde a fallback + // in case it turns out to not be true. + // 16 is low, but supported on every platform. + const int IovMax = 16; +#endif + + int allowedCount = (int)vectorCount; + + // We need to respect the limit of items that can be passed in iov. + // In case of writes, the managed code is responsible for handling incomplete writes. + // In case of reads, we simply returns the number of bytes read and it's up to the users. + if (IovMax < allowedCount) + { + allowedCount = IovMax; + } + +#if defined(TARGET_APPLE) + // For macOS preadv and pwritev can fail with EINVAL when the total length + // of all vectors overflows a 32-bit integer. + size_t totalLength = 0; + for (int i = 0; i < allowedCount; i++) + { + assert(INT_MAX >= vectors[i].Count); + + totalLength += vectors[i].Count; + + if (totalLength > INT_MAX) + { + allowedCount = i; + break; + } + } +#else + (void)vectors; +#endif + + return allowedCount; +} +#endif // (HAVE_PREADV || HAVE_PWRITEV) && !defined(TARGET_WASM) + int64_t SystemNative_PReadV(intptr_t fd, IOVector* vectors, int32_t vectorCount, int64_t fileOffset) { assert(vectors != NULL); @@ -1891,7 +1938,8 @@ int64_t SystemNative_PReadV(intptr_t fd, IOVector* vectors, int32_t vectorCount, int64_t count = 0; int fileDescriptor = ToFileDescriptor(fd); #if HAVE_PREADV && !defined(TARGET_WASM) // preadv is buggy on WASM - while ((count = preadv(fileDescriptor, (struct iovec*)vectors, (int)vectorCount, (off_t)fileOffset)) < 0 && errno == EINTR); + int allowedVectorCount = GetAllowedVectorCount(vectors, vectorCount); + while ((count = preadv(fileDescriptor, (struct iovec*)vectors, allowedVectorCount, (off_t)fileOffset)) < 0 && errno == EINTR); #else int64_t current; for (int i = 0; i < vectorCount; i++) @@ -1931,7 +1979,8 @@ int64_t SystemNative_PWriteV(intptr_t fd, IOVector* vectors, int32_t vectorCount int64_t count = 0; int fileDescriptor = ToFileDescriptor(fd); #if HAVE_PWRITEV && !defined(TARGET_WASM) // pwritev is buggy on WASM - while ((count = pwritev(fileDescriptor, (struct iovec*)vectors, (int)vectorCount, (off_t)fileOffset)) < 0 && errno == EINTR); + int allowedVectorCount = GetAllowedVectorCount(vectors, vectorCount); + while ((count = pwritev(fileDescriptor, (struct iovec*)vectors, allowedVectorCount, (off_t)fileOffset)) < 0 && errno == EINTR); #else int64_t current; for (int i = 0; i < vectorCount; i++) diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt index 84615493f4495c..bc333326b9837e 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt @@ -77,9 +77,14 @@ if (NOT SWIFT_COMPILER_TARGET) endif() endif() +set(SWIFT_SDK_FLAG "") +if (CMAKE_OSX_SYSROOT) + set(SWIFT_SDK_FLAG -sdk ${CMAKE_OSX_SYSROOT}) +endif() + add_custom_command( OUTPUT pal_swiftbindings.o - COMMAND xcrun swiftc -emit-object -static -parse-as-library -enable-library-evolution -g ${SWIFT_OPTIMIZATION_FLAG} -runtime-compatibility-version none -sdk ${CMAKE_OSX_SYSROOT} -target ${SWIFT_COMPILER_TARGET} ${CMAKE_CURRENT_SOURCE_DIR}/pal_swiftbindings.swift -o pal_swiftbindings.o + COMMAND xcrun swiftc -emit-object -static -parse-as-library -enable-library-evolution -g ${SWIFT_OPTIMIZATION_FLAG} -runtime-compatibility-version none ${SWIFT_SDK_FLAG} -target ${SWIFT_COMPILER_TARGET} ${CMAKE_CURRENT_SOURCE_DIR}/pal_swiftbindings.swift -o pal_swiftbindings.o MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/pal_swiftbindings.swift COMMENT "Compiling Swift file pal_swiftbindings.swift" ) diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_evp_kdf.c b/src/native/libs/System.Security.Cryptography.Native/pal_evp_kdf.c index a7af40330316a5..31d5c0eaadec81 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_evp_kdf.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_evp_kdf.c @@ -201,18 +201,27 @@ static int32_t HkdfCore( size_t keyLengthT = Int32ToSizeT(keyLength); size_t destinationLengthT = Int32ToSizeT(destinationLength); - size_t saltLengthT = Int32ToSizeT(saltLength); - size_t infoLengthT = Int32ToSizeT(infoLength); - OSSL_PARAM params[] = + OSSL_PARAM params[6] = {{0}}; + int i = 0; + params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, (void*)key, keyLengthT); + params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, algorithm, 0); + + if (salt != NULL && saltLength > 0) { - OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, (void*)key, keyLengthT), - OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, algorithm, 0), - OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, (void*)salt, saltLengthT), - OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, (void*)info, infoLengthT), - OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &operation), - OSSL_PARAM_construct_end(), - }; + size_t saltLengthT = Int32ToSizeT(saltLength); + params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, (void*)salt, saltLengthT); + } + + if (info != NULL && infoLength > 0) + { + size_t infoLengthT = Int32ToSizeT(infoLength); + params[i++] = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, (void*)info, infoLengthT); + } + + params[i++] = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &operation); + params[i] = OSSL_PARAM_construct_end(); + assert(i < 6); if (EVP_KDF_derive(ctx, destination, destinationLengthT, params) <= 0) { diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c index e444d8c0c57b12..f4a79df5fa1498 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c @@ -215,6 +215,15 @@ int32_t CryptoNative_RsaEncrypt(EVP_PKEY* pkey, static bool ConfigureSignature(EVP_PKEY_CTX* ctx, RsaPaddingMode padding, const EVP_MD* digest) { + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-qual" + if (EVP_PKEY_CTX_set_signature_md(ctx, digest) <= 0) +#pragma clang diagnostic pop + { + return false; + } + if (padding == RsaPaddingPkcs1) { if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) @@ -233,14 +242,6 @@ static bool ConfigureSignature(EVP_PKEY_CTX* ctx, RsaPaddingMode padding, const } } -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wcast-qual" - if (EVP_PKEY_CTX_set_signature_md(ctx, digest) <= 0) -#pragma clang diagnostic pop - { - return false; - } - return true; } diff --git a/src/native/libs/build-native.proj b/src/native/libs/build-native.proj index 36bfccbfe07ad8..a60ddf43f4000a 100644 --- a/src/native/libs/build-native.proj +++ b/src/native/libs/build-native.proj @@ -70,7 +70,7 @@ - + - + + { + for (int i = 0; i < 5; i++) + { + await Task.Yield(); + var buffer = new byte[10_000]; + await Task.Run(() => {var _ = buffer[0];} ); + await Task.Yield(); + } + }); + } + } + + public static async Task Main(string[] args) + { + mono_ios_set_summary($"Starting functional test"); + + await GitHubIssue_114262_Async(); + + Console.WriteLine("Done!"); + + return 42; + } +} diff --git a/src/tests/FunctionalTests/iOS/Device/ParallelForEachAsync/iOS.Device.ParallelForEachAsync.Test.csproj b/src/tests/FunctionalTests/iOS/Device/ParallelForEachAsync/iOS.Device.ParallelForEachAsync.Test.csproj new file mode 100644 index 00000000000000..ae748949616933 --- /dev/null +++ b/src/tests/FunctionalTests/iOS/Device/ParallelForEachAsync/iOS.Device.ParallelForEachAsync.Test.csproj @@ -0,0 +1,22 @@ + + + Exe + true + $(NetCoreAppCurrent) + ios + arm64 + false + 42 + true + + + + true + false + iOS.Device.ParallelForEachAsync.Test.dll + + + + + + diff --git a/src/tests/FunctionalTests/tvOS/Device/AOT/tvOS.Device.Aot.Test.csproj b/src/tests/FunctionalTests/tvOS/Device/AOT/tvOS.Device.Aot.Test.csproj index 0e2f71fe06b3d0..92271eb0c889ce 100644 --- a/src/tests/FunctionalTests/tvOS/Device/AOT/tvOS.Device.Aot.Test.csproj +++ b/src/tests/FunctionalTests/tvOS/Device/AOT/tvOS.Device.Aot.Test.csproj @@ -19,11 +19,6 @@ false - - - - - diff --git a/src/tests/GC/Features/Bridge/Bridge.cs b/src/tests/GC/Features/Bridge/Bridge.cs new file mode 100644 index 00000000000000..c481087943efcd --- /dev/null +++ b/src/tests/GC/Features/Bridge/Bridge.cs @@ -0,0 +1,422 @@ +// 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; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; + +// False pinning cases are still possible. For example the thread can die +// and its stack reused by another thread. It also seems that a thread that +// does a GC can keep on the stack references to objects it encountered +// during the collection which are never released afterwards. This would +// be more likely to happen with the interpreter which reuses more stack. +public static class FinalizerHelpers +{ + private static IntPtr aptr; + + private static unsafe void NoPinActionHelper(int depth, Action act) + { + // Avoid tail calls + int* values = stackalloc int[20]; + aptr = new IntPtr(values); + + if (depth <= 0) + { + // + // When the action is called, this new thread might have not allocated + // anything yet in the nursery. This means that the address of the first + // object that would be allocated would be at the start of the tlab and + // implicitly the end of the previous tlab (address which can be in use + // when allocating on another thread, at checking if an object fits in + // this other tlab). We allocate a new dummy object to avoid this type + // of false pinning for most common cases. + // + new object(); + act(); + ClearStack(); + } + else + { + NoPinActionHelper(depth - 1, act); + } + } + + private static unsafe void ClearStack() + { + int* values = stackalloc int[25000]; + for (int i = 0; i < 25000; i++) + values[i] = 0; + } + + public static void PerformNoPinAction(Action act) + { + Thread thr = new Thread(() => NoPinActionHelper (128, act)); + thr.Start(); + thr.Join(); + } +} + +public class BridgeBase +{ + public static int fin_count; + + ~BridgeBase() + { + fin_count++; + } +} + +public class Bridge : BridgeBase +{ + public List Links = new List(); + public int __test; + + ~Bridge() + { + Links = null; + } +} + +public class Bridge1 : BridgeBase +{ + public object Link; + ~Bridge1() + { + Link = null; + } +} + +// 128 size +public class Bridge14 : BridgeBase +{ + public object a,b,c,d,e,f,g,h,i,j,k,l,m,n; +} + +public class NonBridge +{ + public object Link; +} + +public class NonBridge2 : NonBridge +{ + public object Link2; +} + +public class NonBridge14 +{ + public object a,b,c,d,e,f,g,h,i,j,k,l,m,n; +} + + +public class BridgeTest +{ + const int OBJ_COUNT = 100 * 1000; + const int LINK_COUNT = 2; + const int EXTRAS_COUNT = 0; + const double survival_rate = 0.1; + + // Pathological case for the original old algorithm. Goes + // away when merging is replaced by appending with flag + // checking. + static void SetupLinks() + { + var list = new List(); + for (int i = 0; i < OBJ_COUNT; ++i) + { + var bridge = new Bridge(); + list.Add(bridge); + } + + var r = new Random(100); + for (int i = 0; i < OBJ_COUNT; ++i) + { + var n = list[i]; + for (int j = 0; j < LINK_COUNT; ++j) + n.Links.Add(list[r.Next (OBJ_COUNT)]); + for (int j = 0; j < EXTRAS_COUNT; ++j) + n.Links.Add(j); + if (r.NextDouble() <= survival_rate) + n.__test = 1; + } + } + + const int LIST_LENGTH = 10000; + const int FAN_OUT = 10000; + + // Pathological case for the new algorithm. Goes away with + // the single-node elimination optimization, but will still + // persist if modified by using a ladder instead of the single + // list. + static void SetupLinkedFan() + { + var head = new Bridge(); + var tail = new NonBridge(); + head.Links.Add(tail); + for (int i = 0; i < LIST_LENGTH; ++i) + { + var obj = new NonBridge (); + tail.Link = obj; + tail = obj; + } + var list = new List(); + tail.Link = list; + for (int i = 0; i < FAN_OUT; ++i) + list.Add (new Bridge()); + } + + // Pathological case for the improved old algorithm. Goes + // away with copy-on-write DynArrays, but will still persist + // if modified by using a ladder instead of the single list. + static void SetupInverseFan() + { + var tail = new Bridge(); + object list = tail; + for (int i = 0; i < LIST_LENGTH; ++i) + { + var obj = new NonBridge(); + obj.Link = list; + list = obj; + } + var heads = new Bridge[FAN_OUT]; + for (int i = 0; i < FAN_OUT; ++i) + { + var obj = new Bridge(); + obj.Links.Add(list); + heads[i] = obj; + } + } + + // Not necessarily a pathology, but a special case of where we + // generate lots of "dead" SCCs. A non-bridge object that + // can't reach a bridge object can safely be removed from the + // graph. In this special case it's a linked list hanging off + // a bridge object. We can handle this by "forwarding" edges + // going to non-bridge nodes that have only a single outgoing + // edge. That collapses the whole list into a single node. + // We could remove that node, too, by removing non-bridge + // nodes with no outgoing edges. + static void SetupDeadList() + { + var head = new Bridge(); + var tail = new NonBridge(); + head.Links.Add(tail); + for (int i = 0; i < LIST_LENGTH; ++i) + { + var obj = new NonBridge(); + tail.Link = obj; + tail = obj; + } + } + + // Triggered a bug in the forwarding mechanic. + static void SetupSelfLinks() + { + var head = new Bridge(); + var tail = new NonBridge(); + head.Links.Add(tail); + tail.Link = tail; + } + + const int L0_COUNT = 50000; + const int L1_COUNT = 50000; + const int EXTRA_LEVELS = 4; + + // Set a complex graph from one bridge to a couple. + // The graph is designed to expose naive coloring on + // tarjan and SCC explosion on classic. + static void Spider() + { + Bridge a = new Bridge(); + Bridge b = new Bridge(); + + var l1 = new List(); + for (int i = 0; i < L0_COUNT; ++i) { + var l0 = new List(); + l0.Add(a); + l0.Add(b); + l1.Add(l0); + } + var last_level = l1; + for (int l = 0; l < EXTRA_LEVELS; ++l) { + int j = 0; + var l2 = new List(); + for (int i = 0; i < L1_COUNT; ++i) { + var tmp = new List(); + tmp.Add(last_level [j++ % last_level.Count]); + tmp.Add(last_level [j++ % last_level.Count]); + l2.Add(tmp); + } + last_level = l2; + } + Bridge c = new Bridge(); + c.Links.Add(last_level); + } + + // Simulates a graph with two nested cycles that is produces by + // the async state machine when `async Task M()` method gets its + // continuation rooted by an Action held by RunnableImplementor + // (ie. the task continuation is hooked through the SynchronizationContext + // implentation and rooted only by Android bridge objects). + static void NestedCycles() + { + Bridge runnableImplementor = new Bridge (); + Bridge byteArrayOutputStream = new Bridge (); + NonBridge2 action = new NonBridge2 (); + NonBridge displayClass = new NonBridge (); + NonBridge2 asyncStateMachineBox = new NonBridge2 (); + NonBridge2 asyncStreamWriter = new NonBridge2 (); + + runnableImplementor.Links.Add(action); + action.Link = displayClass; + action.Link2 = asyncStateMachineBox; + displayClass.Link = action; + asyncStateMachineBox.Link = asyncStreamWriter; + asyncStateMachineBox.Link2 = action; + asyncStreamWriter.Link = byteArrayOutputStream; + asyncStreamWriter.Link2 = asyncStateMachineBox; + } + + // Simulates a graph where a heavy node has its fanout components + // represented by cycles with back-references to the heavy node and + // references to the same bridge objects. + // This enters a pathological path in the SCC contraction where the + // links to the bridge objects need to be correctly deduplicated. The + // deduplication causes the heavy node to no longer be heavy. + static void FauxHeavyNodeWithCycles() + { + Bridge fanout = new Bridge(); + + // Need enough edges for the node to be considered heavy by bridgeless_color_is_heavy + NonBridge[] fauxHeavyNode = new NonBridge[100]; + for (int i = 0; i < fauxHeavyNode.Length; i++) + { + NonBridge2 cycle = new NonBridge2(); + cycle.Link = fanout; + cycle.Link2 = fauxHeavyNode; + fauxHeavyNode[i] = cycle; + } + + // Need at least HEAVY_REFS_MIN + 1 fan-in nodes + Bridge[] faninNodes = new Bridge[3]; + for (int i = 0; i < faninNodes.Length; i++) + { + faninNodes[i] = new Bridge(); + faninNodes[i].Links.Add(fauxHeavyNode); + } + } + + static void RunGraphTest(Action test) + { + Console.WriteLine("Start test {0}", test.Method.Name); + FinalizerHelpers.PerformNoPinAction(test); + Console.WriteLine("-graph built-"); + for (int i = 0; i < 5; i++) + { + Console.WriteLine("-GC {0}/5-", i); + GC.Collect (); + GC.WaitForPendingFinalizers(); + } + + Console.WriteLine("Finished test {0}, finalized {1}", test.Method.Name, Bridge.fin_count); + } + + static void TestLinkedList() + { + int count = Environment.ProcessorCount + 2; + var th = new Thread [count]; + for (int i = 0; i < count; ++i) + { + th [i] = new Thread( _ => + { + var lst = new ArrayList(); + for (var j = 0; j < 500 * 1000; j++) + { + lst.Add (new object()); + if ((j % 999) == 0) + lst.Add (new BridgeBase()); + if ((j % 1000) == 0) + new BridgeBase(); + if ((j % 50000) == 0) + lst = new ArrayList(); + } + }); + + th [i].Start(); + } + + for (int i = 0; i < count; ++i) + th [i].Join(); + + GC.Collect(2); + Console.WriteLine("Finished test LinkedTest, finalized {0}", BridgeBase.fin_count); + } + + //we fill 16Mb worth of stuff, eg, 256k objects + const int major_fill = 1024 * 256; + + //4mb nursery with 64 bytes objects -> alloc half + const int nursery_obj_count = 16 * 1024; + + static void SetupFragmentation() + where TBridge : new() + where TNonBridge : new() + { + const int loops = 4; + for (int k = 0; k < loops; k++) + { + Console.WriteLine("[{0}] CrashLoop {1}/{2}", DateTime.Now, k + 1, loops); + var arr = new object[major_fill]; + for (int i = 0; i < major_fill; i++) + arr[i] = new TNonBridge(); + GC.Collect(1); + Console.WriteLine("[{0}] major fill done", DateTime.Now); + + //induce massive fragmentation + for (int i = 0; i < major_fill; i += 4) + { + arr[i + 1] = null; + arr[i + 2] = null; + arr[i + 3] = null; + } + GC.Collect (1); + Console.WriteLine("[{0}] fragmentation done", DateTime.Now); + + //since 50% is garbage, do 2 fill passes + for (int j = 0; j < 2; ++j) + { + for (int i = 0; i < major_fill; i++) + { + if ((i % 1000) == 0) + new TBridge(); + else + arr[i] = new TBridge(); + } + } + Console.WriteLine("[{0}] done spewing bridges", DateTime.Now); + + for (int i = 0; i < major_fill; i++) + arr[i] = null; + GC.Collect (); + } + } + + public static int Main(string[] args) + { +// TestLinkedList(); // Crashes, but only in this multithreaded variant + RunGraphTest(SetupFragmentation); // This passes but the following crashes ?? +// RunGraphTest(SetupFragmentation); + RunGraphTest(SetupLinks); + RunGraphTest(SetupLinkedFan); + RunGraphTest(SetupInverseFan); + + RunGraphTest(SetupDeadList); + RunGraphTest(SetupSelfLinks); + RunGraphTest(NestedCycles); + RunGraphTest(FauxHeavyNodeWithCycles); +// RunGraphTest(Spider); // Crashes + return 100; + } +} diff --git a/src/tests/GC/Features/Bridge/Bridge.csproj b/src/tests/GC/Features/Bridge/Bridge.csproj new file mode 100644 index 00000000000000..29b8c0f5fd3a2d --- /dev/null +++ b/src/tests/GC/Features/Bridge/Bridge.csproj @@ -0,0 +1,11 @@ + + + + true + false + BuildOnly + + + + + diff --git a/src/tests/GC/Features/Bridge/BridgeTester.cs b/src/tests/GC/Features/Bridge/BridgeTester.cs new file mode 100644 index 00000000000000..960e39a5e6eb0d --- /dev/null +++ b/src/tests/GC/Features/Bridge/BridgeTester.cs @@ -0,0 +1,35 @@ +// 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.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime; +using System.Text; + +using Xunit; + +public class BridgeTester +{ + [Fact] + public static void RunTests() + { + string corerun = TestLibrary.Utilities.IsWindows ? "corerun.exe" : "corerun"; + string coreRoot = Environment.GetEnvironmentVariable("CORE_ROOT"); + string bridgeTestApp = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Bridge.dll"); + + var startInfo = new ProcessStartInfo(Path.Combine(coreRoot, corerun), bridgeTestApp); + startInfo.EnvironmentVariables["MONO_GC_DEBUG"] = "bridge=BridgeBase,bridge-compare-to=new"; + startInfo.EnvironmentVariables["MONO_GC_PARAMS"] = "bridge-implementation=tarjan,bridge-require-precise-merge"; + + using (Process p = Process.Start(startInfo)) + { + p.WaitForExit(); + Console.WriteLine ("Bridge Test App returned {0}", p.ExitCode); + if (p.ExitCode != 100) + throw new Exception("Bridge Test App failed execution"); + } + } +} diff --git a/src/tests/GC/Features/Bridge/BridgeTester.csproj b/src/tests/GC/Features/Bridge/BridgeTester.csproj new file mode 100644 index 00000000000000..5045d91e4c89a8 --- /dev/null +++ b/src/tests/GC/Features/Bridge/BridgeTester.csproj @@ -0,0 +1,17 @@ + + + true + true + + + + + + + + false + Content + Always + + + diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_113658/Runtime_113658.cs b/src/tests/JIT/Regression/JitBlue/Runtime_113658/Runtime_113658.cs new file mode 100644 index 00000000000000..089f666d280002 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_113658/Runtime_113658.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.CompilerServices; +using Xunit; + +public static class Runtime_113658 +{ + [Fact] + public static int TestEntryPoint() + { + FillStackWithGarbage(); + long? nullable = FaultyDefaultNullable(); + return (int)(100 + nullable.GetValueOrDefault()); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void FillStackWithGarbage() + { + stackalloc byte[256].Fill(0xcc); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [SkipLocalsInit] + private static T FaultyDefaultNullable() + { + // When T is a Nullable (and only in that case), we support returning null + if (default(T) is null && typeof(T).IsValueType) + return default!; + + throw new InvalidOperationException("Not nullable"); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_113658/Runtime_113658.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_113658/Runtime_113658.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_113658/Runtime_113658.csproj @@ -0,0 +1,8 @@ + + + True + + + + + diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.cs b/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.cs new file mode 100644 index 00000000000000..77f42fe7d49453 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_115815 +{ + [Fact] + public static void TestEntryPoint() + { + var destination = new KeyValuePair[1_000]; + + // loop to make this method fully interruptible + to get into OSR version + for (int i = 0; i < destination.Length * 1000; i++) + { + destination[i / 1000] = default; + } + + for (int i = 0; i < 5; i++) + { + for (int j = 0; j < destination.Length; j++) + { + destination[j] = GetValue(j); + } + + Thread.Sleep(10); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static KeyValuePair GetValue(int i) + => KeyValuePair.Create(new Container(i.ToString()), (double)i); + + private struct Container + { + public string Name; + public Container(string name) { this.Name = name; } + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.csproj @@ -0,0 +1,8 @@ + + + True + + + + + diff --git a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/DeadCodeElimination.cs b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/DeadCodeElimination.cs index 0a6090f8092432..032c3a07d7dea6 100644 --- a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/DeadCodeElimination.cs +++ b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/DeadCodeElimination.cs @@ -12,6 +12,7 @@ class DeadCodeElimination public static int Run() { SanityTest.Run(); + Test110932Regression.Run(); TestInstanceMethodOptimization.Run(); TestReflectionInvokeSignatures.Run(); TestAbstractTypeNeverDerivedVirtualsOptimization.Run(); @@ -52,6 +53,34 @@ public static void Run() } } + class Test110932Regression + { + static bool s_trueConst = true; + static bool s_falseConst = false; + + interface I + { + static virtual bool GetValue() => false; + } + + class C : I + { + static bool I.GetValue() => true; + } + + public static void Run() + { + if (!Call()) + throw new Exception(); + } + static bool Call() where T : I + { + if (T.GetValue()) + return s_trueConst; + return s_falseConst; + } + } + class TestInstanceMethodOptimization { class UnreferencedType { } diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 2e41771ee39634..ef88f6d4d007c4 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -417,8 +417,8 @@ bool ProcessPrimaryQueue () while (!QueueIsEmpty ()) { ProcessQueue (); - ProcessInterfaceMethods (); ProcessMarkedTypesWithInterfaces (); + ProcessInterfaceMethods (); ProcessDynamicCastableImplementationInterfaces (); ProcessPendingBodies (); DoAdditionalProcessing (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs index 6b58c1dbf0de9c..1a97ef3fa1e972 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs @@ -6,6 +6,11 @@ namespace Mono.Linker.Tests.Cases.Attributes.OnlyKeepUsed { [SetupCSharpCompilerToUse ("csc")] [SetupLinkerArgument ("--used-attrs-only", "true")] + + // Necessary to allow trimming the attribute instance from types in CoreLib. + [SetupLinkerTrimMode ("link")] + // When we allow trimming CoreLib, some well-known types expected by ILVerify are removed. + [SkipILVerify] public class MethodWithUnmanagedConstraint { public static void Main ()