diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 7fcec77f199e6e..449ecc145c2618 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "9.0.0-prerelease.25426.1", + "version": "9.0.0-prerelease.25504.2", "commands": [ "xharness" ] diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 8f390ade2f34cf..f221471a9156e2 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,8 +1,8 @@ - + https://github.com/dotnet/icu - 4ca307e1d07b3b76d1aa66c15d67de89bcca0cd8 + 82b2c68d359fe1f84f592e877aa9e021591b39b8 https://github.com/dotnet/msquic @@ -54,14 +54,14 @@ 803d8598f98fb4efd94604b32627ee9407f246db - + https://github.com/dotnet/cecil - e5381291dd01d040b5b111f3a2ee8508ec990d78 + 1b55accc7029bd4038d35b2072ec58841431122f - + https://github.com/dotnet/cecil - e5381291dd01d040b5b111f3a2ee8508ec990d78 + 1b55accc7029bd4038d35b2072ec58841431122f @@ -79,9 +79,9 @@ - + https://github.com/dotnet/source-build-reference-packages - 745de7d839fdd3b5884d72e953badcfb15493d13 + bd4018e4d8a9006e7f62378db31522354ab15aae @@ -174,57 +174,57 @@ https://github.com/dotnet/arcade f8c9a6d12e5a3b281661924da22d7de1cc6ab27d - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 https://github.com/dotnet/llvm-project @@ -320,17 +320,17 @@ https://github.com/dotnet/runtime b030c4dfdfa1bf287f10f96006619a06bc2000ae - + https://github.com/dotnet/xharness - 7b6f58237ff2355392960408f4d9fd98dfe58f9b + 47324ca7227e3b6e9f51b85b3e1a4a425e89a0ae - + https://github.com/dotnet/xharness - 7b6f58237ff2355392960408f4d9fd98dfe58f9b + 47324ca7227e3b6e9f51b85b3e1a4a425e89a0ae - + https://github.com/dotnet/xharness - 7b6f58237ff2355392960408f4d9fd98dfe58f9b + 47324ca7227e3b6e9f51b85b3e1a4a425e89a0ae https://github.com/dotnet/arcade @@ -352,13 +352,13 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 9d7532585ce71e30ab55f0364d3cecccaf0775d1 - + https://github.com/dotnet/hotreload-utils - 0334eb13c37ab4d8d1b405952e838fc8cad195be + d29a5b47fc17d7c0cfeedaf44ac7f18388195375 - + https://github.com/dotnet/runtime-assets - 36490ea19fe9622e76fb3534069a6459ff56353b + a01a686de0c5d8407874b1c79d67efaf03d4c8b6 https://github.com/dotnet/roslyn diff --git a/eng/Versions.props b/eng/Versions.props index 7bbf0b6646cc5a..2080f8290e16f8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -136,25 +136,31 @@ 4.5.0 9.0.0-rtm.24511.16 + 8.0.0 + 4.5.1 8.0.0 - 8.0.4 + 4.5.5 + 8.0.5 8.0.0 8.0.0 + 8.0.0 + 8.0.0 + 4.5.4 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 - 9.0.0-beta.25462.1 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 + 9.0.0-beta.25504.2 1.0.0-prerelease.24462.2 1.0.0-prerelease.24462.2 @@ -185,11 +191,11 @@ 1.4.0 17.4.0-preview-20220707-01 - 9.0.0-prerelease.25426.1 - 9.0.0-prerelease.25426.1 - 9.0.0-prerelease.25426.1 + 9.0.0-prerelease.25504.2 + 9.0.0-prerelease.25504.2 + 9.0.0-prerelease.25504.2 - 9.0.0-alpha.0.25462.1 + 9.0.0-alpha.0.25504.3 3.12.0 4.5.0 6.0.0 @@ -217,15 +223,14 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25464.3 + 0.11.5-alpha.25504.2 9.0.0-rtm.24511.16 - 9.0.0-rtm.25469.1 + 9.0.0-rtm.25509.1 9.0.0-rtm.24466.4 2.4.8 - 9.0.0-alpha.1.24167.3 19.1.0-alpha.1.25504.3 19.1.0-alpha.1.25504.3 diff --git a/eng/pipelines/coreclr/templates/helix-queues-setup.yml b/eng/pipelines/coreclr/templates/helix-queues-setup.yml index 4d05678f0b7293..15a67fd0098508 100644 --- a/eng/pipelines/coreclr/templates/helix-queues-setup.yml +++ b/eng/pipelines/coreclr/templates/helix-queues-setup.yml @@ -105,16 +105,16 @@ jobs: # OSX arm64 - ${{ if eq(parameters.platform, 'osx_arm64') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - OSX.1200.ARM64.Open + - OSX.13.ARM64.Open - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - OSX.1200.ARM64 + - OSX.13.ARM64 # OSX x64 - ${{ if eq(parameters.platform, 'osx_x64') }}: - ${{ if eq(variables['System.TeamProject'], 'public') }}: - - OSX.1200.Amd64.Open + - OSX.13.Amd64.Open - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - - OSX.1200.Amd64 + - OSX.13.Amd64 # windows x64 - ${{ if eq(parameters.platform, 'windows_x64') }}: diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index cb8447877b09d4..c35ec8c5444c53 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -73,11 +73,11 @@ jobs: # OSX arm64 - ${{ if eq(parameters.platform, 'osx_arm64') }}: - - OSX.1200.ARM64.Open + - OSX.13.ARM64.Open # OSX x64 - ${{ if eq(parameters.platform, 'osx_x64') }}: - - OSX.1200.Amd64.Open + - OSX.13.Amd64.Open # Android - ${{ if in(parameters.platform, 'android_x86', 'android_x64', 'linux_bionic_x64') }}: diff --git a/src/coreclr/scripts/superpmi_collect_setup.py b/src/coreclr/scripts/superpmi_collect_setup.py index 40c3a768e68283..d1eb398ecace9f 100644 --- a/src/coreclr/scripts/superpmi_collect_setup.py +++ b/src/coreclr/scripts/superpmi_collect_setup.py @@ -465,7 +465,7 @@ def main(main_args): else: helix_queue = "Ubuntu.2204.Amd64" elif platform_name == "osx": - helix_queue = "OSX.1200.ARM64" if arch == "arm64" else "OSX.1200.Amd64" + helix_queue = "OSX.13.ARM64" if arch == "arm64" else "OSX.13.Amd64" # Copy the superpmi scripts diff --git a/src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs b/src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs index e8e97f2eb31973..b6bb5af4bc2fd0 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs @@ -318,6 +318,12 @@ private static bool DoesMethodMatchUnsafeAccessorDeclaration(ref GenerationConte return false; } + // Validate generic parameter. + if (declSig.GenericParameterCount != maybeSig.GenericParameterCount) + { + return false; + } + // Validate argument count and return type if (context.Kind == UnsafeAccessorKind.Constructor) { diff --git a/src/coreclr/vm/gcheaputilities.cpp b/src/coreclr/vm/gcheaputilities.cpp index cd0259eef45d83..94564204f769b0 100644 --- a/src/coreclr/vm/gcheaputilities.cpp +++ b/src/coreclr/vm/gcheaputilities.cpp @@ -186,8 +186,12 @@ HMODULE LoadStandaloneGc(LPCWSTR libFileName, LPCWSTR libFilePath) return nullptr; } + // The APP_CONTEXT_BASE_DIRECTORY is always set by the host. In cases + // where the runtime is activated as a component, the base directory + // will be an empty string. If the base directory is an empty string, skip it. SString appBase; - if (HostInformation::GetProperty("APP_CONTEXT_BASE_DIRECTORY", appBase)) + if (HostInformation::GetProperty("APP_CONTEXT_BASE_DIRECTORY", appBase) + && u16_strlen(appBase.GetUnicode()) != 0) { PathString libPath = appBase.GetUnicode(); libPath.Append(libFileName); diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 35882fdde5ddfc..480c29ebc4dcde 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -2959,7 +2959,7 @@ class NDirectMethodDesc : public MethodDesc BOOL IsPopulated() { LIMITED_METHOD_CONTRACT; - return (ndirect.m_wFlags & kNDirectPopulated) != 0; + return (VolatileLoad(&ndirect.m_wFlags) & kNDirectPopulated) != 0; } ULONG DefaultDllImportSearchPathsAttributeCachedValue() diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 99086a462a26fb..0d7fb7f875453a 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -1190,14 +1190,26 @@ namespace return false; } - // Handle generic param count - DWORD declGenericCount = 0; - DWORD methodGenericCount = 0; + // Handle generic signature if (callConvDecl & IMAGE_CEE_CS_CALLCONV_GENERIC) + { + if (!(callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC)) + return false; + + DWORD declGenericCount = 0; + DWORD methodGenericCount = 0; IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &declGenericCount)); - if (callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC) IfFailThrow(CorSigUncompressData_EndPtr(pSig2, pEndSig2, &methodGenericCount)); + if (declGenericCount != methodGenericCount) + return false; + } + else if (callConvMethod & IMAGE_CEE_CS_CALLCONV_GENERIC) + { + // Method is generic but declaration is not + return false; + } + DWORD declArgCount; DWORD methodArgCount; IfFailThrow(CorSigUncompressData_EndPtr(pSig1, pEndSig1, &declArgCount)); @@ -3541,7 +3553,7 @@ static PCODE getHelperForStaticBase(Module * pModule, CORCOMPILE_FIXUP_BLOB_KIND bool threadStatic = (kind == ENCODE_THREAD_STATIC_BASE_NONGC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER); CorInfoHelpFunc helper; - + if (threadStatic) { if (GCStatic) diff --git a/src/libraries/Common/tests/System/Security/Cryptography/PlatformSupport.cs b/src/libraries/Common/tests/System/Security/Cryptography/PlatformSupport.cs index 6be4ed60277044..0544d858fab0ae 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/PlatformSupport.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/PlatformSupport.cs @@ -11,8 +11,89 @@ namespace Test.Cryptography { internal static class PlatformSupport { + private static readonly RSAParameters s_rsa384Parameters = new RSAParameters + { + Modulus = new byte[] + { + 0xDA, 0xCC, 0x22, 0xD8, 0x6E, 0x67, 0x15, 0x75, + 0x03, 0x2E, 0x31, 0xF2, 0x06, 0xDC, 0xFC, 0x19, + 0x2C, 0x65, 0xE2, 0xD5, 0x10, 0x89, 0xE5, 0x11, + 0x2D, 0x09, 0x6F, 0x28, 0x82, 0xAF, 0xDB, 0x5B, + 0x78, 0xCD, 0xB6, 0x57, 0x2F, 0xD2, 0xF6, 0x1D, + 0xB3, 0x90, 0x47, 0x22, 0x32, 0xE3, 0xD9, 0xF5, + }, + Exponent = new byte[] + { + 0x01, 0x00, 0x01, + }, + D = new byte[] + { + 0x7A, 0x59, 0xBD, 0x02, 0x9A, 0x7A, 0x3A, 0x9D, + 0x7C, 0x71, 0xD0, 0xAC, 0x2E, 0xFA, 0x54, 0x5F, + 0x1F, 0x5C, 0xBA, 0x43, 0xBB, 0x43, 0xE1, 0x3B, + 0x78, 0x77, 0xAF, 0x82, 0xEF, 0xEB, 0x40, 0xC3, + 0x8D, 0x1E, 0xCD, 0x73, 0x7F, 0x5B, 0xF9, 0xC8, + 0x96, 0x92, 0xB2, 0x9C, 0x87, 0x5E, 0xD6, 0xE1, + }, + P = new byte[] + { + 0xFA, 0xDB, 0xD7, 0xF8, 0xA1, 0x8B, 0x3A, 0x75, + 0xA4, 0xF6, 0xDF, 0xAE, 0xE3, 0x42, 0x6F, 0xD0, + 0xFF, 0x8B, 0xAC, 0x74, 0xB6, 0x72, 0x2D, 0xEF, + }, + DP = new byte[] + { + 0x24, 0xFF, 0xBB, 0xD0, 0xDD, 0xF2, 0xAD, 0x02, + 0xA0, 0xFC, 0x10, 0x6D, 0xB8, 0xF3, 0x19, 0x8E, + 0xD7, 0xC2, 0x00, 0x03, 0x8E, 0xCD, 0x34, 0x5D, + }, + Q = new byte[] + { + 0xDF, 0x48, 0x14, 0x4A, 0x6D, 0x88, 0xA7, 0x80, + 0x14, 0x4F, 0xCE, 0xA6, 0x6B, 0xDC, 0xDA, 0x50, + 0xD6, 0x07, 0x1C, 0x54, 0xE5, 0xD0, 0xDA, 0x5B, + }, + DQ = new byte[] + { + 0x85, 0xDF, 0x73, 0xBB, 0x04, 0x5D, 0x91, 0x00, + 0x6C, 0x2D, 0x45, 0x9B, 0xE6, 0xC4, 0x2E, 0x69, + 0x95, 0x4A, 0x02, 0x24, 0xAC, 0xFE, 0x42, 0x4D, + }, + InverseQ = new byte[] + { + 0x1A, 0x3A, 0x76, 0x9C, 0x21, 0x26, 0x2B, 0x84, + 0xCA, 0x9C, 0xA9, 0x62, 0x0F, 0x98, 0xD2, 0xF4, + 0x3E, 0xAC, 0xCC, 0xD4, 0x87, 0x9A, 0x6F, 0xFD, + }, + }; + private static readonly Dictionary s_platformCryptoSupportedAlgorithms = new(); + private static readonly Lazy s_lazyIsRSA384Supported = new Lazy(() => + { + // Linux and Apple are known to support RSA-384, so return true without checking. + if (PlatformDetection.IsLinux || PlatformDetection.IsApplePlatform) + { + return true; + } + + RSA rsa = RSA.Create(); + + try + { + rsa.ImportParameters(s_rsa384Parameters); + return true; + } + catch (CryptographicException) + { + return false; + } + finally + { + rsa.Dispose(); + } + }); + private static bool PlatformCryptoProviderFunctional(CngAlgorithm algorithm) { // Use a full lock around a non-concurrent dictionary. We do not want the value factory for @@ -91,6 +172,8 @@ private static bool CheckIfVbsAvailable() // Whether or not the current platform supports RC2 internal static readonly bool IsRC2Supported = !PlatformDetection.IsAndroid; + internal static bool IsRSA384Supported => s_lazyIsRSA384Supported.Value; + #if NET internal static readonly bool IsAndroidVersionAtLeast31 = OperatingSystem.IsAndroidVersionAtLeast(31); #else diff --git a/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs index c89d6797581e9b..d5d098e03f6b13 100644 --- a/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs @@ -1,6 +1,7 @@ // 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; @@ -77,9 +78,10 @@ public override int GetCount(bool onlyIfCheap) if (index == 0) { found = true; + return _default; } - return _default; + return default; } } } diff --git a/src/libraries/System.Linq/tests/DefaultIfEmptyTests.cs b/src/libraries/System.Linq/tests/DefaultIfEmptyTests.cs index 3dadd6d679378e..f128afc41d8183 100644 --- a/src/libraries/System.Linq/tests/DefaultIfEmptyTests.cs +++ b/src/libraries/System.Linq/tests/DefaultIfEmptyTests.cs @@ -124,5 +124,36 @@ public void First_Last_ElementAt() Assert.Equal(42, empty.DefaultIfEmpty(42).ElementAt(0)); Assert.Throws(() => empty.DefaultIfEmpty(42).ElementAt(1)); } + + [Fact] + public void ElementAtOrDefault_OutOfBounds_ReturnsTypeDefault() + { + // Regression test for https://github.com/dotnet/runtime/issues/119834 + // ElementAtOrDefault should return default(T) for out-of-bounds indices, + // not the DefaultIfEmpty default value + + // Test with empty source + int[] empty = []; + var defaultIfEmpty = empty.DefaultIfEmpty(999); + + // Index 0 should return the DefaultIfEmpty value (999) + Assert.Equal(999, defaultIfEmpty.ElementAtOrDefault(0)); + + // Out-of-bounds indices should return default(int) which is 0, not 999 + Assert.Equal(0, defaultIfEmpty.ElementAtOrDefault(1)); + Assert.Equal(0, defaultIfEmpty.ElementAtOrDefault(2)); + Assert.Equal(0, defaultIfEmpty.ElementAtOrDefault(-1)); + + // Test with different type (string) + string[] emptyStrings = []; + var defaultIfEmptyString = emptyStrings.DefaultIfEmpty("default"); + + // Index 0 should return the DefaultIfEmpty value + Assert.Equal("default", defaultIfEmptyString.ElementAtOrDefault(0)); + + // Out-of-bounds indices should return default(string) which is null + Assert.Null(defaultIfEmptyString.ElementAtOrDefault(1)); + Assert.Null(defaultIfEmptyString.ElementAtOrDefault(2)); + } } } diff --git a/src/libraries/System.Net.Quic/readme.md b/src/libraries/System.Net.Quic/readme.md index e8ba3e7f32c6a4..b8b8589c8ac29e 100644 --- a/src/libraries/System.Net.Quic/readme.md +++ b/src/libraries/System.Net.Quic/readme.md @@ -77,15 +77,19 @@ Testing on Linux is done with the help of docker images whose definition can be To consume a release version of the package, the docker image definition will contain: ```docker -RUN curl -LO https://packages.microsoft.com/keys/microsoft.asc && \ - echo 2cfd20a306b2fa5e25522d78f2ef50a1f429d35fd30bd983e2ebffc2b80944fa microsoft.asc | sha256sum --check - && \ - apt-key add microsoft.asc && \ - rm microsoft.asc && \ - apt-add-repository https://packages.microsoft.com/debian/11/prod && \ - apt-get update && \ - apt-get install -y libmsquic +RUN apt-get update \ + && apt-get upgrade -y \ + && apt-get install -y \ + apt-transport-https \ + curl \ + software-properties-common \ + && curl -sL https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -o packages-microsoft-prod.deb \ + && dpkg -i packages-microsoft-prod.deb \ + && rm packages-microsoft-prod.deb \ + && apt-get update \ + && apt-get install -y libmsquic ``` -Source: https://github.com/dotnet/dotnet-buildtools-prereqs-docker/blob/efbcd1079edef4698ada1676a5e33c4c9672f85a/src/debian/11/helix/amd64/Dockerfile#L44-L52 +Source: https://github.com/dotnet/dotnet-buildtools-prereqs-docker/blob/7f86167248bcbda898a6b7f17ed01dce3adff2dd/src/debian/12/helix/amd64/Dockerfile#L22-L31 To consume the current main branch of msquic, we pull code from [dotnet/msquic](https://github.com/dotnet/msquic) and build it locally in our docker image: ```docker @@ -94,13 +98,13 @@ RUN apt-get update -y && \ apt-get upgrade -y && \ apt-get install -y cmake clang ruby-dev gem lttng-tools libssl-dev && \ gem install fpm -RUN git clone --recursive https://github.com/dotnet/msquic -RUN cd msquic/src/msquic && \ +RUN git clone --depth 1 --single-branch --branch main --recursive https://github.com/microsoft/msquic +RUN cd msquic/ && \ mkdir build && \ - cmake -B build -DCMAKE_BUILD_TYPE=Release -DQUIC_ENABLE_LOGGING=false -DQUIC_USE_SYSTEM_LIBCRYPTO=true -DQUIC_BUILD_TOOLS=off -DQUIC_BUILD_TEST=off -DQUIC_BUILD_PERF=off && \ + cmake -B build -DCMAKE_BUILD_TYPE=Debug -DQUIC_ENABLE_LOGGING=false -DQUIC_USE_SYSTEM_LIBCRYPTO=true -DQUIC_BUILD_TOOLS=off -DQUIC_BUILD_TEST=off -DQUIC_BUILD_PERF=off -DQUIC_TLS_LIB=quictls -DQUIC_ENABLE_SANITIZERS=on && \ cd build && \ - cmake --build . --config Release -RUN cd msquic/src/msquic/build/bin/Release && \ + cmake --build . --config Debug +RUN cd msquic/build/bin/Debug && \ rm libmsquic.so && \ fpm -f -s dir -t deb -n libmsquic -v $( find -type f | cut -d "." -f 4- ) \ --license MIT --url https://github.com/microsoft/msquic --log error \ @@ -109,15 +113,10 @@ RUN cd msquic/src/msquic/build/bin/Release && \ ``` Source: -https://github.com/dotnet/runtime/blob/bd540938a4830ee91dec5ee2d39545b2f69a19d5/src/libraries/System.Net.Http/tests/StressTests/HttpStress/Dockerfile#L4-L21 +https://github.com/dotnet/runtime/blob/c6566fb0bcc539c523be9796ba5af681bf65a904/src/libraries/System.Net.Http/tests/StressTests/HttpStress/Dockerfile#L4-L21 Note that to propagate newest sources / package to the docker image used for the test runs, it must be rebuilt by [dotnet-buildtools-prereqs-docker-all](https://dev.azure.com/dnceng/internal/_build?definitionId=1183&_a=summary) pipeline with `noCache = true` variable. And since [#76630](https://github.com/dotnet/runtime/pull/76630), the newest image will get automatically picked up by the dotnet/runtime infra. ### Windows -Officially released `msquic.dll` is published to NuGet.org, see [Microsoft.Native.Quic.MsQuic.Schannel](https://www.nuget.org/packages/Microsoft.Native.Quic.MsQuic.Schannel). - -To consume MsQuic from the current main branch, we use [dotnet/msquic](https://github.com/dotnet/msquic) repository which will build and publish `msquic.dll` to the transport feed, e.g. [dotnet8-transport](https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet8-transport). And from there, it'll get flown into this repository via [Darc subscription](https://github.com/dotnet/arcade/blob/main/Documentation/Darc.md). See https://github.com/dotnet/runtime/blob/bd540938a4830ee91dec5ee2d39545b2f69a19d5/eng/Version.Details.xml#L7-L10 and maestro-bot PR: https://github.com/dotnet/runtime/pull/71900. - - -System.Net.Quic [project file](https://github.com/dotnet/runtime/blob/0304f1f5157a8280fa093bdfc7cfb8d9f62e016f/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj) allows switching between those two options with [`UseQuicTransportPackage` property](https://github.com/dotnet/runtime/blob/0304f1f5157a8280fa093bdfc7cfb8d9f62e016f/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj#L15). +Officially released `msquic.dll` is published to NuGet.org, see [Microsoft.Native.Quic.MsQuic.Schannel](https://www.nuget.org/packages/Microsoft.Native.Quic.MsQuic.Schannel). \ No newline at end of file diff --git a/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj b/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj index f09a5d14dd08b0..f11b6fc7b06de1 100644 --- a/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj +++ b/src/libraries/System.Net.Quic/src/System.Net.Quic.csproj @@ -15,9 +15,6 @@ $(DefineConstants);TARGET_WINDOWS SR.SystemNetQuic_PlatformNotSupported ExcludeApiList.PNSE.txt - - false @@ -159,41 +156,15 @@ '$(DotNetBuildSourceOnly)' != 'true'"> - - - - - - + - - - - - - diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngProvider.cs b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngProvider.cs index 025bbc426a4cdf..8b831ea9b041f1 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/RSACngProvider.cs +++ b/src/libraries/System.Security.Cryptography.Cng/tests/RSACngProvider.cs @@ -2,32 +2,17 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; +using Test.Cryptography; namespace System.Security.Cryptography.Rsa.Tests { public class RSACngProvider : IRSAProvider { - private bool? _supports384PrivateKey; - public RSA Create() => new RSACng(); public RSA Create(int keySize) => new RSACng(keySize); - public bool Supports384PrivateKey - { - get - { - if (!_supports384PrivateKey.HasValue) - { - // For Windows 7 (Microsoft Windows 6.1) and Windows 8 (Microsoft Windows 6.2) this is false for RSACng. - _supports384PrivateKey = - !RuntimeInformation.OSDescription.Contains("Windows 6.1") && - !RuntimeInformation.OSDescription.Contains("Windows 6.2"); - } - - return _supports384PrivateKey.Value; - } - } + public bool Supports384PrivateKey => PlatformSupport.IsRSA384Supported; public bool SupportsLargeExponent => true; diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs index fb40b5ece1d0fc..84825bcbb5c3b5 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs +++ b/src/libraries/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using System.Security.Cryptography.Tests; +using Test.Cryptography; namespace System.Security.Cryptography.Rsa.Tests { @@ -15,7 +16,7 @@ public class RSACryptoServiceProviderProvider : IRSAProvider public RSA Create(int keySize) => new RSACryptoServiceProvider(keySize); - public bool Supports384PrivateKey => true; + public bool Supports384PrivateKey => PlatformSupport.IsRSA384Supported; public bool SupportsLargeExponent => false; diff --git a/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs b/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs index 1aa87fdab4a9db..affcb571f1307f 100644 --- a/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs +++ b/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs @@ -3,12 +3,12 @@ using System.Runtime.InteropServices; using System.Security.Cryptography.Tests; +using Test.Cryptography; namespace System.Security.Cryptography.Rsa.Tests { public class DefaultRSAProvider : IRSAProvider { - private bool? _supports384PrivateKey; private bool? _supportsSha1Signatures; private bool? _supportsMd5Signatures; @@ -26,21 +26,7 @@ public RSA Create(int keySize) #endif } - public bool Supports384PrivateKey - { - get - { - if (!_supports384PrivateKey.HasValue) - { - // For Windows 7 (Microsoft Windows 6.1) and Windows 8 (Microsoft Windows 6.2) this is false for RSACng. - _supports384PrivateKey = !RuntimeInformation.OSDescription.Contains("Windows 6.1") && - !RuntimeInformation.OSDescription.Contains("Windows 6.2"); - } - - return _supports384PrivateKey.Value; - } - } - + public bool Supports384PrivateKey => PlatformSupport.IsRSA384Supported; public bool SupportsSha1Signatures => _supportsSha1Signatures ??= SignatureSupport.CanProduceSha1Signature(Create()); public bool SupportsMd5Signatures => _supportsMd5Signatures ??= SignatureSupport.CanProduceMd5Signature(Create()); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.WriteTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.WriteTests.cs index 22572f9a8fd98a..50dcf59ed17db5 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.WriteTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.WriteTests.cs @@ -338,8 +338,7 @@ public async Task VeryLargeJsonFileTest(int payloadSize, bool ignoreNull, bool w [InlineData(2, true, false)] [InlineData(2, false, false)] [InlineData(4, false, false)] - [InlineData(8, false, false)] - [InlineData(16, false, false)] // This results a reader\writer depth of 324 which currently works on all test platforms. + [InlineData(8, false, false)] // Greater depths have caused failures on some test machine configurations due to memory constraints public async Task DeepNestedJsonFileTest(int depthFactor, bool ignoreNull, bool writeIndented) { const int ListLength = 10; diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index eae58ac93c86b0..c52212e3a18e48 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -40,6 +40,11 @@ + + + + + diff --git a/src/mono/mono/component/hot_reload.c b/src/mono/mono/component/hot_reload.c index 5ce5950556581c..e5614bb0788aec 100644 --- a/src/mono/mono/component/hot_reload.c +++ b/src/mono/mono/component/hot_reload.c @@ -2381,9 +2381,11 @@ hot_reload_apply_changes (int origin, MonoImage *image_base, gconstpointer dmeta if (!assembly_update_supported (image_base, error)) { return; } - + if (dmeta_bytes == 0 && dil_bytes_orig == 0) // we may receive empty updates + { + return; + } static int first_origin = -1; - if (first_origin < 0) { first_origin = origin; } diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index 76459536c24971..e431249b184780 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -1689,8 +1689,6 @@ mono_class_setup_count_virtual_methods (MonoClass *klass) return vcount; } -#ifdef COMPRESSED_INTERFACE_BITMAP - /* * Compressed interface bitmap design. * @@ -1745,7 +1743,7 @@ mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size) while (bitmap < end) { if (*bitmap || numz == 255) { if (dest) { - *dest++ = numz; + *dest++ = (uint8_t)numz; *dest++ = *bitmap; } res += 2; @@ -1759,7 +1757,7 @@ mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size) if (numz) { res += 2; if (dest) { - *dest++ = numz; + *dest++ = (uint8_t)numz; *dest++ = 0; } } @@ -1780,7 +1778,7 @@ mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size) * FALSE otherwise. */ int -mono_class_interface_match (const uint8_t *bitmap, int id) +mono_class_interface_match_compressed (const uint8_t *bitmap, int id) { while (TRUE) { id -= bitmap [0] * 8; @@ -1793,7 +1791,6 @@ mono_class_interface_match (const uint8_t *bitmap, int id) id -= 8; } } -#endif static char* concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2) diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index 55067f680d1b31..22b35e1e674c6f 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -17,6 +17,7 @@ #include "mono/utils/mono-error-internals.h" #include "mono/utils/mono-memory-model.h" #include "mono/utils/mono-compiler.h" +#include "mono/utils/options.h" #define MONO_CLASS_IS_ARRAY(c) (m_class_get_rank (c)) @@ -287,12 +288,6 @@ union _MonoClassSizes { int generic_param_token; /* for generic param types, both var and mvar */ }; -/* enabled only with small config for now: we might want to do it unconditionally */ -#ifdef MONO_SMALL_CONFIG -#define COMPRESSED_INTERFACE_BITMAP 1 -#endif - - #ifdef ENABLE_CHECKED_BUILD_PRIVATE_TYPES #define MONO_CLASS_DEF_PRIVATE 1 #endif @@ -321,14 +316,12 @@ union _MonoClassSizes { #undef MONO_CLASS_GETTER #undef MONO_CLASS_OFFSET -#ifdef COMPRESSED_INTERFACE_BITMAP int mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size); -int mono_class_interface_match (const uint8_t *bitmap, int id); -#else +int mono_class_interface_match_compressed (const uint8_t *bitmap, int id); + #define mono_class_interface_match(bmap,uiid) ((bmap) [(uiid) >> 3] & (1 << ((uiid)&7))) -#endif -#define MONO_CLASS_IMPLEMENTS_INTERFACE(k,uiid) (((uiid) <= m_class_get_max_interface_id (k)) && mono_class_interface_match (m_class_get_interface_bitmap (k), (uiid))) +#define MONO_CLASS_IMPLEMENTS_INTERFACE(k,uiid) (((uiid) <= m_class_get_max_interface_id (k)) && (mono_opt_compressed_interface_bitmap ? mono_class_interface_match_compressed (m_class_get_interface_bitmap (k), (uiid)) : mono_class_interface_match (m_class_get_interface_bitmap (k), (uiid)))) #define MONO_VTABLE_AVAILABLE_GC_BITS 4 @@ -378,7 +371,7 @@ struct MonoVTable { #define MONO_SIZEOF_VTABLE (sizeof (MonoVTable) - MONO_ZERO_LEN_ARRAY * SIZEOF_VOID_P) -#define MONO_VTABLE_IMPLEMENTS_INTERFACE(vt,uiid) (((uiid) <= (vt)->max_interface_id) && mono_class_interface_match ((vt)->interface_bitmap, (uiid))) +#define MONO_VTABLE_IMPLEMENTS_INTERFACE(vt,uiid) (((uiid) <= (vt)->max_interface_id) && (mono_opt_compressed_interface_bitmap ? mono_class_interface_match_compressed ((vt)->interface_bitmap, (uiid)) : mono_class_interface_match ((vt)->interface_bitmap, (uiid)))) /* * Generic instantiation data type encoding. diff --git a/src/mono/mono/metadata/class-setup-vtable.c b/src/mono/mono/metadata/class-setup-vtable.c index b2f13d72dfc47c..b4a86602079c13 100644 --- a/src/mono/mono/metadata/class-setup-vtable.c +++ b/src/mono/mono/metadata/class-setup-vtable.c @@ -56,8 +56,7 @@ print_implemented_interfaces (MonoClass *klass) printf ("(%d,F)", i); printf ("\n"); printf ("Dump interface flags:"); -#ifdef COMPRESSED_INTERFACE_BITMAP - { + if (mono_opt_compressed_interface_bitmap) { const uint8_t* p = klass->interface_bitmap; guint32 i = klass->max_interface_id; while (i > 0) { @@ -65,11 +64,10 @@ print_implemented_interfaces (MonoClass *klass) i -= p [0] * 8; i -= 8; } + } else { + for (guint32 i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7) ? 1 : 0)); i++) + printf (" %02X", klass->interface_bitmap [i]); } -#else - for (guint32 i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++) - printf (" %02X", klass->interface_bitmap [i]); -#endif printf ("\n"); while (klass != NULL) { printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name); @@ -329,11 +327,12 @@ mono_class_setup_interface_offsets_internal (MonoClass *klass, int cur_slot, int klass->interface_offsets_packed = (guint16 *)mono_class_alloc (klass, sizeof (guint16) * interface_offsets_count); } bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0); -#ifdef COMPRESSED_INTERFACE_BITMAP - bitmap = g_malloc0 (bsize); -#else - bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize); -#endif + + if (mono_opt_compressed_interface_bitmap) + bitmap = g_malloc0 (bsize); + else + bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize); + for (int i = 0; i < interface_offsets_count; i++) { guint32 id = interfaces_full [i]->interface_id; bitmap [id >> 3] |= (1 << (id & 7)); @@ -343,14 +342,16 @@ mono_class_setup_interface_offsets_internal (MonoClass *klass, int cur_slot, int } } if (!klass->interface_bitmap) { -#ifdef COMPRESSED_INTERFACE_BITMAP - int i = mono_compress_bitmap (NULL, bitmap, bsize); - klass->interface_bitmap = mono_class_alloc0 (klass, i); - mono_compress_bitmap (klass->interface_bitmap, bitmap, bsize); - g_free (bitmap); -#else - klass->interface_bitmap = bitmap; -#endif + if (mono_opt_compressed_interface_bitmap) { + int len = mono_compress_bitmap (NULL, bitmap, bsize); + uint8_t *compressed_bitmap = mono_class_alloc0 (klass, len); + mono_compress_bitmap (compressed_bitmap, bitmap, bsize); + g_free (bitmap); + + klass->interface_bitmap = compressed_bitmap; + } else { + klass->interface_bitmap = bitmap; + } } } end: diff --git a/src/mono/mono/metadata/jit-icall-reg.h b/src/mono/mono/metadata/jit-icall-reg.h index e412fdd5448dca..4353840f66b939 100644 --- a/src/mono/mono/metadata/jit-icall-reg.h +++ b/src/mono/mono/metadata/jit-icall-reg.h @@ -162,7 +162,7 @@ MONO_JIT_ICALL (mono_break) \ MONO_JIT_ICALL (mono_byvalarray_to_byte_array) \ MONO_JIT_ICALL (mono_chkstk_win64) \ MONO_JIT_ICALL (mono_ckfinite) \ -MONO_JIT_ICALL (mono_class_interface_match) \ +MONO_JIT_ICALL (mono_class_interface_match_compressed) \ MONO_JIT_ICALL (mono_class_static_field_address) \ MONO_JIT_ICALL (mono_compile_method_icall) \ MONO_JIT_ICALL (mono_context_get_icall) \ diff --git a/src/mono/mono/metadata/loader.c b/src/mono/mono/metadata/loader.c index 921fe29e2743e1..ea4195287e79b9 100644 --- a/src/mono/mono/metadata/loader.c +++ b/src/mono/mono/metadata/loader.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,8 @@ static gint32 memberref_sig_cache_size; static gint32 methods_size; static gint32 signatures_size; +static gboolean mono_enable_dynfree = FALSE; + void mono_loader_init (void) { @@ -103,6 +106,11 @@ mono_loader_init (void) mono_counters_register ("MonoMethodSignature size", MONO_COUNTER_METADATA | MONO_COUNTER_INT, &signatures_size); + char *env_opt = g_getenv ("MONO_ENABLE_DYNMETHOD_FREE"); + if (env_opt && env_opt [0] == '1') + mono_enable_dynfree = TRUE; + g_free (env_opt); + inited = TRUE; } } @@ -1371,8 +1379,14 @@ mono_free_method (MonoMethod *method) MONO_PROFILER_RAISE (method_free, (method)); - /* FIXME: This hack will go away when the profiler will support freeing methods */ - if (G_UNLIKELY (mono_profiler_installed ())) + if (G_UNLIKELY (mono_profiler_installed () && !mono_enable_dynfree)) + return; + + // EventPipe might require information about methods to be stored throughout + // entire app execution, so stack traces can be resolved at a later time. + // Same for debugger, we are being overly conservative + if (mono_component_event_pipe ()->component.available () || + mono_component_debugger ()->component.available ()) return; if (method->signature) { diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index f9aa95467519f9..258ebfd09d54f6 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -4860,11 +4860,8 @@ get_virtual_stelemref_kind (MonoClass *element_class) /* Compressed interface bitmaps require code that is quite complex, so don't optimize for it. */ if (MONO_CLASS_IS_INTERFACE_INTERNAL (element_class) && !mono_class_has_variant_generic_params (element_class)) -#ifdef COMPRESSED_INTERFACE_BITMAP - return STELEMREF_COMPLEX; -#else - return STELEMREF_INTERFACE; -#endif + return mono_opt_compressed_interface_bitmap ? STELEMREF_COMPLEX : STELEMREF_INTERFACE; + /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/ if (m_class_get_rank (element_class) || mono_class_has_variant_generic_params (element_class)) return STELEMREF_COMPLEX; diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 8a96c1ead4c337..698c9581d6245d 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -1975,6 +1975,15 @@ mono_metadata_init (void) g_hash_table_insert (type_cache, (gpointer) &builtin_types [i], (gpointer) &builtin_types [i]); mono_metadata_update_init (); + + char *compressed_bmap = g_getenv ("MONO_COMPRESSED_INTERFACE_BITMAP"); + if (compressed_bmap) { + if (compressed_bmap [0] == '1') + mono_opt_compressed_interface_bitmap = TRUE; + else if (compressed_bmap [0] == '0') + mono_opt_compressed_interface_bitmap = FALSE; + g_free (compressed_bmap); + } } /* diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index df45813a2e30d0..e65557514ce337 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -15120,6 +15120,9 @@ aot_assembly (MonoAssembly *ass, guint32 jit_opts, MonoAotOptions *aot_options) acfg->is_full_aot = TRUE; } + if (mono_opt_compressed_interface_bitmap) + acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_COMPRESSED_INTERFACE_BITMAP); + if (mini_safepoints_enabled ()) acfg->flags = (MonoAotFileFlags)(acfg->flags | MONO_AOT_FILE_FLAG_SAFEPOINTS); diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index 11c8888d17b038..8ce917fb79b9aa 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -1631,7 +1631,7 @@ check_usable (MonoAssembly *assembly, MonoAotFileInfo *info, guint8 *blob, char char *build_info; char *msg = NULL; gboolean usable = TRUE; - gboolean full_aot, interp, safepoints; + gboolean full_aot, interp, safepoints, compressed_interface_bmap; guint32 excluded_cpu_optimizations; if (strcmp (assembly->image->guid, (const char*)info->assembly_guid)) { @@ -1713,6 +1713,13 @@ check_usable (MonoAssembly *assembly, MonoAotFileInfo *info, guint8 *blob, char } #endif + compressed_interface_bmap = info->flags & MONO_AOT_FILE_FLAG_COMPRESSED_INTERFACE_BITMAP; + if ((mono_opt_compressed_interface_bitmap && !compressed_interface_bmap) || + (!mono_opt_compressed_interface_bitmap && compressed_interface_bmap)) { + msg = g_strdup ("mismatch with compressed interface bitmap feature"); + usable = FALSE; + } + *out_msg = msg; return usable; } diff --git a/src/mono/mono/mini/aot-runtime.h b/src/mono/mono/mini/aot-runtime.h index 13690e31904d4a..706cde519ecf62 100644 --- a/src/mono/mono/mini/aot-runtime.h +++ b/src/mono/mono/mini/aot-runtime.h @@ -11,7 +11,7 @@ #include "mini.h" /* Version number of the AOT file format */ -#define MONO_AOT_FILE_VERSION 186 +#define MONO_AOT_FILE_VERSION 187 #define MONO_AOT_TRAMP_PAGE_SIZE 16384 @@ -74,7 +74,8 @@ typedef enum { MONO_AOT_FILE_FLAG_SEPARATE_DATA = 64, MONO_AOT_FILE_FLAG_EAGER_LOAD = 128, MONO_AOT_FILE_FLAG_INTERP = 256, - MONO_AOT_FILE_FLAG_CODE_EXEC_ONLY = 512 + MONO_AOT_FILE_FLAG_CODE_EXEC_ONLY = 512, + MONO_AOT_FILE_FLAG_COMPRESSED_INTERFACE_BITMAP = 1024 } MonoAotFileFlags; typedef enum { diff --git a/src/mono/mono/mini/interp/interp-internals.h b/src/mono/mono/mini/interp/interp-internals.h index 5fe04bf314c8c7..41407a2fd67235 100644 --- a/src/mono/mono/mini/interp/interp-internals.h +++ b/src/mono/mono/mini/interp/interp-internals.h @@ -148,6 +148,7 @@ struct InterpMethod { /* locals_size is equal to the offset of the param_area */ guint32 locals_size; guint32 alloca_size; + int n_data_items; int num_clauses; // clauses int transformed; // boolean unsigned int param_count; diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 011d99a9625dda..91966a0b18e782 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -3565,12 +3565,17 @@ interp_free_method (MonoMethod *method) jit_mm_lock (jit_mm); -#if HOST_BROWSER InterpMethod *imethod = (InterpMethod*)mono_internal_hash_table_lookup (&jit_mm->interp_code_hash, method); - mono_jiterp_free_method_data (method, imethod); + if (imethod) { +#if HOST_BROWSER + mono_jiterp_free_method_data (method, imethod); #endif - mono_internal_hash_table_remove (&jit_mm->interp_code_hash, method); + mono_interp_clear_data_items_patch_sites (imethod->data_items, imethod->n_data_items); + + mono_internal_hash_table_remove (&jit_mm->interp_code_hash, method); + } + jit_mm_unlock (jit_mm); if (dmethod->mp) { diff --git a/src/mono/mono/mini/interp/tiering.c b/src/mono/mono/mini/interp/tiering.c index a49b591e9d090e..54708d4f4a0510 100644 --- a/src/mono/mono/mini/interp/tiering.c +++ b/src/mono/mono/mini/interp/tiering.c @@ -128,6 +128,58 @@ register_imethod_data_item (gpointer data, gpointer user_data) } } +void +mono_interp_clear_data_items_patch_sites (gpointer *data_items, int n_data_items) +{ + if (!enable_tiering) + return; + // data_items is part of the memory of a dynamic method that is being freed. + // slots within this memory can be registered as patch sites for other imethods + // We conservatively assume each slot could be an imethod slot, then look it up + // in imethod to patch_sites hashtable. If we find it in the hashtable, we remove + // the slot from the patch site list. + mono_os_mutex_lock (&tiering_mutex); + + for (int i = 0; i < n_data_items; i++) { + GSList *sites; + gpointer *slot = data_items + i; + gpointer imethod_candidate = *slot; + + if (dn_simdhash_ptr_ptr_try_get_value (patch_sites_table, imethod_candidate, (void **)&sites)) { + GSList *prev = NULL; + + // Remove slot from sites list + if (sites->data == slot) { + // If the slot is found in the first element we will also need to update the hash table since + // the list head changes + if (!sites->next) { + g_slist_free_1 (sites); + dn_simdhash_ptr_ptr_try_remove (patch_sites_table, imethod_candidate); + } else { + prev = sites; + sites = sites->next; + g_slist_free_1 (prev); + dn_simdhash_ptr_ptr_try_replace_value (patch_sites_table, imethod_candidate, sites); + } + } else { + prev = sites; + sites = sites->next; + while (sites != NULL) { + if (sites->data == slot) { + prev->next = sites->next; + g_slist_free_1 (sites); + // duplicates not allowed + break; + } + prev = sites; + sites = sites->next; + } + } + } + } + mono_os_mutex_unlock (&tiering_mutex); +} + void mono_interp_register_imethod_data_items (gpointer *data_items, GSList *indexes) { diff --git a/src/mono/mono/mini/interp/tiering.h b/src/mono/mono/mini/interp/tiering.h index dbd7da87ecd4d9..c50e4988b43972 100644 --- a/src/mono/mono/mini/interp/tiering.h +++ b/src/mono/mono/mini/interp/tiering.h @@ -14,6 +14,9 @@ mono_interp_tiering_enabled (void); void mono_interp_register_imethod_data_items (gpointer *data_items, GSList *indexes); +void +mono_interp_clear_data_items_patch_sites (gpointer *data_items, int n_data_items); + void mono_interp_register_imethod_patch_site (gpointer *imethod_ptr); diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index a74e9baafb300b..10fbe877db711c 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -3176,6 +3176,8 @@ interp_inline_newobj (TransformData *td, MonoMethod *target_method, MonoMethodSi if (!interp_inline_method (td, target_method, mheader, error)) goto fail; + td->headers_to_free = g_slist_prepend_mempool (td->mempool, td->headers_to_free, mheader); + push_var (td, dreg); return TRUE; fail: @@ -3760,6 +3762,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target return_val_if_nok (error, FALSE); if (interp_inline_method (td, target_method, mheader, error)) { + td->headers_to_free = g_slist_prepend_mempool (td->mempool, td->headers_to_free, mheader); td->ip += 5; goto done; } @@ -4510,7 +4513,7 @@ interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMet // 64 vars * 72 bytes = 4608 bytes. Many methods need less than this int target_vars_capacity = num_locals + 64; - imethod->local_offsets = (guint32*)g_malloc (num_il_locals * sizeof(guint32)); + imethod->local_offsets = (guint32*)imethod_alloc0 (td, num_il_locals * sizeof(guint32)); td->vars = (InterpVar*)g_malloc0 (target_vars_capacity * sizeof (InterpVar)); td->vars_size = num_locals; td->vars_capacity = target_vars_capacity; @@ -4608,7 +4611,7 @@ interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMet } #endif - imethod->clause_data_offsets = (guint32*)g_malloc (header->num_clauses * sizeof (guint32)); + imethod->clause_data_offsets = (guint32*)imethod_alloc0 (td, header->num_clauses * sizeof (guint32)); td->clause_vars = (int*)mono_mempool_alloc (td->mempool, sizeof (int) * header->num_clauses); for (guint i = 0; i < header->num_clauses; i++) { int var = interp_create_var (td, mono_get_object_type ()); @@ -9424,7 +9427,7 @@ get_native_offset (TransformData *td, int il_offset) } } -static void +static GSList* generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoGenericContext *generic_context, MonoError *error) { TransformData transform_data; @@ -9609,12 +9612,10 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG rtm->alloca_size = td->total_locals_size + td->max_stack_size; g_assert ((rtm->alloca_size % MINT_STACK_ALIGNMENT) == 0); rtm->locals_size = td->param_area_offset; - // FIXME: Can't allocate this using imethod_alloc0 as its registered with mono_interp_register_imethod_data_items () - //rtm->data_items = (gpointer*)imethod_alloc0 (td, td->n_data_items * sizeof (td->data_items [0])); - rtm->data_items = (gpointer*)mono_mem_manager_alloc0 (td->mem_manager, td->n_data_items * sizeof (td->data_items [0])); + rtm->data_items = (gpointer*)imethod_alloc0 (td, td->n_data_items * sizeof (td->data_items [0])); memcpy (rtm->data_items, td->data_items, td->n_data_items * sizeof (td->data_items [0])); + rtm->n_data_items = td->n_data_items; - mono_interp_register_imethod_data_items (rtm->data_items, td->imethod_items); rtm->patchpoint_data = td->patchpoint_data; if (td->ref_slots) { @@ -9688,7 +9689,8 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG g_ptr_array_free (td->seq_points, TRUE); if (td->line_numbers) g_array_free (td->line_numbers, TRUE); - g_slist_free (td->imethod_items); + for (GSList *l = td->headers_to_free; l; l = l->next) + mono_metadata_free_mh ((MonoMethodHeader *)l->data); mono_mempool_destroy (td->mempool); mono_interp_pgo_generate_end (); if (td->retry_compilation) { @@ -9696,6 +9698,8 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG retry_with_inlining = td->retry_with_inlining; goto retry; } + + return td->imethod_items; } gboolean @@ -9841,7 +9845,8 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, Mon memcpy (&tmp_imethod, imethod, sizeof (InterpMethod)); imethod = &tmp_imethod; - MONO_TIME_TRACK (mono_interp_stats.transform_time, generate (method, header, imethod, generic_context, error)); + GSList *imethod_data_items; + MONO_TIME_TRACK (mono_interp_stats.transform_time, imethod_data_items = generate (method, header, imethod, generic_context, error)); mono_metadata_free_mh (header); @@ -9862,6 +9867,8 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, Mon mono_interp_stats.methods_transformed++; mono_atomic_fetch_add_i32 (&mono_jit_stats.methods_with_interp, 1); + mono_interp_register_imethod_data_items (imethod->data_items, imethod_data_items); + // FIXME Publishing of seq points seems to be racy with tiereing. We can have both tiered and untiered method // running at the same time. We could therefore get the optimized imethod seq points for the unoptimized method. gpointer seq_points = NULL; @@ -9871,6 +9878,8 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context, Mon } jit_mm_unlock (jit_mm); + g_slist_free (imethod_data_items); + if (mono_stats_method_desc && mono_method_desc_full_match (mono_stats_method_desc, imethod->method)) { g_printf ("Printing runtime stats at method: %s\n", mono_method_get_full_name (imethod->method)); mono_runtime_print_stats (); diff --git a/src/mono/mono/mini/interp/transform.h b/src/mono/mono/mini/interp/transform.h index 0379cf1682f6a3..d851f51762e338 100644 --- a/src/mono/mono/mini/interp/transform.h +++ b/src/mono/mono/mini/interp/transform.h @@ -314,6 +314,7 @@ typedef struct // FIXME: ptr_u32 dn_simdhash_ptr_ptr_t *data_hash; GSList *imethod_items; + GSList *headers_to_free; #ifdef ENABLE_EXPERIMENT_TIERED // FIXME: ptr_u32 dn_simdhash_ptr_ptr_t *patchsite_hash; diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index bcd7754da660a6..14d235bd2cd0a5 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -5091,9 +5091,9 @@ register_icalls (void) #endif register_icall (mono_ckfinite, mono_icall_sig_double_double, FALSE); -#ifdef COMPRESSED_INTERFACE_BITMAP - register_icall (mono_class_interface_match, mono_icall_sig_uint32_ptr_int32, TRUE); -#endif + // opt is initialized because mono_metadata_init is ran before this + if (mono_opt_compressed_interface_bitmap) + register_icall (mono_class_interface_match_compressed, mono_icall_sig_uint32_ptr_int32, TRUE); /* other jit icalls */ register_icall (ves_icall_mono_delegate_ctor, mono_icall_sig_void_object_object_ptr, FALSE); diff --git a/src/mono/mono/mini/type-checking.c b/src/mono/mono/mini/type-checking.c index a847cb8e720d27..4fad4d00622c4c 100644 --- a/src/mono/mono/mini/type-checking.c +++ b/src/mono/mono/mini/type-checking.c @@ -133,40 +133,41 @@ static void mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, intptr_t offset, MonoClass *klass) { int ibitmap_reg = alloc_preg (cfg); -#ifdef COMPRESSED_INTERFACE_BITMAP - MonoInst *args [2]; - MonoInst *res, *ins; - NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset); - MONO_ADD_INS (cfg->cbb, ins); - args [0] = ins; - args [1] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass); - res = mono_emit_jit_icall (cfg, mono_class_interface_match, args); - MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg); -#else - int ibitmap_byte_reg = alloc_preg (cfg); - - MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, GINTPTR_TO_TMREG (offset)); - if (cfg->compile_aot) { - int iid_reg = alloc_preg (cfg); - int shifted_iid_reg = alloc_preg (cfg); - int ibitmap_byte_address_reg = alloc_preg (cfg); - int masked_iid_reg = alloc_preg (cfg); - int iid_one_bit_reg = alloc_preg (cfg); - int iid_bit_reg = alloc_preg (cfg); - MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID); - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3); - MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg); - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0); - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7); - MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1); - MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg); - MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg); + if (mono_opt_compressed_interface_bitmap) { + MonoInst *args [2]; + MonoInst *res, *ins; + NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, (target_mgreg_t)offset); + MONO_ADD_INS (cfg->cbb, ins); + args [0] = ins; + args [1] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass); + res = mono_emit_jit_icall (cfg, mono_class_interface_match_compressed, args); + MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg); } else { - MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, m_class_get_interface_id (klass) >> 3); - MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, ((target_mgreg_t)1) << (m_class_get_interface_id (klass) & 7)); + int ibitmap_byte_reg = alloc_preg (cfg); + + MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, GINTPTR_TO_TMREG (offset)); + + if (cfg->compile_aot) { + int iid_reg = alloc_preg (cfg); + int shifted_iid_reg = alloc_preg (cfg); + int ibitmap_byte_address_reg = alloc_preg (cfg); + int masked_iid_reg = alloc_preg (cfg); + int iid_one_bit_reg = alloc_preg (cfg); + int iid_bit_reg = alloc_preg (cfg); + MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3); + MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg); + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7); + MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1); + MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg); + MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg); + } else { + MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, m_class_get_interface_id (klass) >> 3); + MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, ((target_mgreg_t)1) << (m_class_get_interface_id (klass) & 7)); + } } -#endif } /* diff --git a/src/mono/mono/sgen/sgen-memory-governor.c b/src/mono/mono/sgen/sgen-memory-governor.c index 487a0e418ad7f3..d28ec1f9668533 100644 --- a/src/mono/mono/sgen/sgen-memory-governor.c +++ b/src/mono/mono/sgen/sgen-memory-governor.c @@ -141,7 +141,7 @@ sgen_need_major_collection_conservative (void) size_t max_allowance = GDOUBLE_TO_SIZE (max_last_collection_heap_size * SGEN_DEFAULT_ALLOWANCE_HEAP_SIZE_RATIO); max_allowance = MAX (max_allowance, GDOUBLE_TO_SIZE (MIN_MINOR_COLLECTION_ALLOWANCE)); - return min_heap_size > max_allowance; + return min_heap_size > (max_last_collection_heap_size + max_allowance); } static size_t diff --git a/src/mono/mono/utils/options-def.h b/src/mono/mono/utils/options-def.h index 7c1b2c3ff06ee8..1e70f507e13ba8 100644 --- a/src/mono/mono/utils/options-def.h +++ b/src/mono/mono/utils/options-def.h @@ -183,6 +183,8 @@ DEFINE_BOOL_READONLY(experimental_gshared_mrgctx, "experimental-gshared-mrgctx", DEFINE_BOOL(experimental_gshared_mrgctx, "experimental-gshared-mrgctx", FALSE, "Use a mrgctx for all gshared methods") #endif +DEFINE_BOOL(compressed_interface_bitmap, "compressed-interface-bitmap", FALSE, "Use compressed bitmap for storing implemented interfaces in vtables and classes") + #if defined(TARGET_WASI) DEFINE_BOOL_READONLY(llvm_emulate_unwind, "emulate-unwind", TRUE, "") #else diff --git a/src/native/corehost/hostmisc/pal.windows.cpp b/src/native/corehost/hostmisc/pal.windows.cpp index dacafb182899ec..15ef33e7d99900 100644 --- a/src/native/corehost/hostmisc/pal.windows.cpp +++ b/src/native/corehost/hostmisc/pal.windows.cpp @@ -22,6 +22,14 @@ void pal::file_vprintf(FILE* f, const pal::char_t* format, va_list vl) } namespace { + void file_printf(FILE* fallbackFileHandle, const pal::char_t* format, ...) + { + va_list args; + va_start(args, format); + pal::file_vprintf(fallbackFileHandle, format, args); + va_end(args); + } + void print_line_to_handle(const pal::char_t* message, HANDLE handle, FILE* fallbackFileHandle) { // String functions like vfwprintf convert wide to multi-byte characters as if wcrtomb were called - that is, using the current C locale (LC_TYPE). // In order to properly print UTF-8 and GB18030 characters to the console without requiring the user to use chcp to a compatible locale, we use WriteConsoleW. @@ -33,7 +41,7 @@ namespace { { // We use file_vprintf to handle UTF-8 formatting. The WriteFile api will output the bytes directly with Unicode bytes, // while pal::file_vprintf will convert the characters to UTF-8. - pal::file_vprintf(fallbackFileHandle, message, va_list()); + file_printf(fallbackFileHandle, _X("%s"), message); } else { ::WriteConsoleW(handle, message, (int)pal::strlen(message), NULL, NULL); diff --git a/src/tasks/Directory.Build.targets b/src/tasks/Directory.Build.targets index b6a5059ec468c0..9393bf199cd03a 100644 --- a/src/tasks/Directory.Build.targets +++ b/src/tasks/Directory.Build.targets @@ -12,8 +12,14 @@ - - + + + + + + + + diff --git a/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs b/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs index 311550810224c8..1504a87af72850 100644 --- a/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs +++ b/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.Generics.cs @@ -181,21 +181,76 @@ public static void Verify_Generic_AccessFieldClass() } } + class AmbiguousMethodName + { + private void M() { } + private void M() { } + private void N() { } + + private static void SM() { } + private static void SM() { } + private static void SN() { } + } + + static class AccessorsAmbiguousMethodName + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "M")] + public extern static void CallM(AmbiguousMethodName a); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "M")] + public extern static void CallM(AmbiguousMethodName a); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "N")] + public extern static void CallN_MissingMethod(AmbiguousMethodName a); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SM")] + public extern static void CallSM(AmbiguousMethodName a); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SM")] + public extern static void CallSM(AmbiguousMethodName a); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "SN")] + public extern static void CallSN_MissingMethod(AmbiguousMethodName a); + } + + [Fact] + public static void Verify_Generic_AmbiguousMethodName() + { + Console.WriteLine($"Running {nameof(Verify_Generic_AmbiguousMethodName)}"); + + { + AmbiguousMethodName a = new(); + AccessorsAmbiguousMethodName.CallM(a); + AccessorsAmbiguousMethodName.CallM(a); + AccessorsAmbiguousMethodName.CallM(a); + AccessorsAmbiguousMethodName.CallM(a); + Assert.Throws(() => AccessorsAmbiguousMethodName.CallN_MissingMethod(a)); + } + + { + AccessorsAmbiguousMethodName.CallSM(null); + AccessorsAmbiguousMethodName.CallSM(null); + AccessorsAmbiguousMethodName.CallSM(null); + AccessorsAmbiguousMethodName.CallSM(null); + Assert.Throws(() => AccessorsAmbiguousMethodName.CallSN_MissingMethod(null)); + } + } + class Base { - protected virtual string CreateMessageGeneric(T t) => $"{nameof(Base)}:{t}"; + protected virtual string CreateMessage(T t) => $"{nameof(Base)}<>:{t}"; } - class GenericBase : Base + class GenericBase : Base { - protected virtual string CreateMessage(T t) => $"{nameof(GenericBase)}:{t}"; - protected override string CreateMessageGeneric(U u) => $"{nameof(GenericBase)}:{u}"; + protected virtual string CreateMessage(U u) => $"{nameof(GenericBase)}:{u}"; + protected override string CreateMessage(V v) => $"{nameof(GenericBase)}<>:{v}"; } sealed class Derived1 : GenericBase { protected override string CreateMessage(string u) => $"{nameof(Derived1)}:{u}"; - protected override string CreateMessageGeneric(U t) => $"{nameof(Derived1)}:{t}"; + protected override string CreateMessage(W w) => $"{nameof(Derived1)}<>:{w}"; } sealed class Derived2 : GenericBase @@ -209,33 +264,33 @@ public static void Verify_Generic_InheritanceMethodResolution() Console.WriteLine($"Running {nameof(Verify_Generic_InheritanceMethodResolution)}"); { Base a = new(); - Assert.Equal($"{nameof(Base)}:1", CreateMessage(a, 1)); - Assert.Equal($"{nameof(Base)}:{expect}", CreateMessage(a, expect)); - Assert.Equal($"{nameof(Base)}:{nameof(Struct)}", CreateMessage(a, new Struct())); + Assert.Equal($"{nameof(Base)}<>:1", CreateMessage(a, 1)); + Assert.Equal($"{nameof(Base)}<>:{expect}", CreateMessage(a, expect)); + Assert.Equal($"{nameof(Base)}<>:{nameof(Struct)}", CreateMessage(a, new Struct())); } { GenericBase a = new(); - Assert.Equal($"{nameof(GenericBase)}:1", CreateMessage(a, 1)); - Assert.Equal($"{nameof(GenericBase)}:{expect}", CreateMessage(a, expect)); - Assert.Equal($"{nameof(GenericBase)}:{nameof(Struct)}", CreateMessage(a, new Struct())); + Assert.Equal($"{nameof(GenericBase)}<>:1", CreateMessage(a, 1)); + Assert.Equal($"{nameof(GenericBase)}<>:{expect}", CreateMessage(a, expect)); + Assert.Equal($"{nameof(GenericBase)}<>:{nameof(Struct)}", CreateMessage(a, new Struct())); } { GenericBase a = new(); - Assert.Equal($"{nameof(GenericBase)}:1", CreateMessage(a, 1)); - Assert.Equal($"{nameof(GenericBase)}:{expect}", CreateMessage(a, expect)); - Assert.Equal($"{nameof(GenericBase)}:{nameof(Struct)}", CreateMessage(a, new Struct())); + Assert.Equal($"{nameof(GenericBase)}<>:1", CreateMessage(a, 1)); + Assert.Equal($"{nameof(GenericBase)}<>:{expect}", CreateMessage(a, expect)); + Assert.Equal($"{nameof(GenericBase)}<>:{nameof(Struct)}", CreateMessage(a, new Struct())); } { GenericBase a = new(); - Assert.Equal($"{nameof(GenericBase)}:1", CreateMessage(a, 1)); - Assert.Equal($"{nameof(GenericBase)}:{expect}", CreateMessage(a, expect)); - Assert.Equal($"{nameof(GenericBase)}:{nameof(Struct)}", CreateMessage(a, new Struct())); + Assert.Equal($"{nameof(GenericBase)}<>:1", CreateMessage(a, 1)); + Assert.Equal($"{nameof(GenericBase)}<>:{expect}", CreateMessage(a, expect)); + Assert.Equal($"{nameof(GenericBase)}<>:{nameof(Struct)}", CreateMessage(a, new Struct())); } { Derived1 a = new(); - Assert.Equal($"{nameof(Derived1)}:1", CreateMessage(a, 1)); - Assert.Equal($"{nameof(Derived1)}:{expect}", CreateMessage(a, expect)); - Assert.Equal($"{nameof(Derived1)}:{nameof(Struct)}", CreateMessage(a, new Struct())); + Assert.Equal($"{nameof(Derived1)}<>:1", CreateMessage(a, 1)); + Assert.Equal($"{nameof(Derived1)}<>:{expect}", CreateMessage(a, expect)); + Assert.Equal($"{nameof(Derived1)}<>:{nameof(Struct)}", CreateMessage(a, new Struct())); } { // Verify resolution of generic override logic. @@ -245,7 +300,7 @@ public static void Verify_Generic_InheritanceMethodResolution() Assert.Equal($"{nameof(GenericBase)}:{expect}", Accessors.CreateMessage(a2, expect)); } - [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "CreateMessageGeneric")] + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "CreateMessage")] extern static string CreateMessage(Base b, W w); }