Update libraries (#8155)
* Update libraries * Fix library names on Unix * CppCodeGen workaround * Disabled outdated test
This commit is contained in:
Родитель
43e327cbc0
Коммит
06c964a218
|
@ -3,7 +3,7 @@
|
|||
<RyuJITVersion Condition="'$(RyuJITVersion)' == ''">5.0.0-preview.5.20230.9</RyuJITVersion>
|
||||
<ObjectWriterVersion Condition="'$(ObjectWriterVersion)' == ''">1.0.0-alpha-28820-01</ObjectWriterVersion>
|
||||
<CoreDisToolsVersion Condition="'$(CoreDisToolsVersion)' == ''">1.0.1-prerelease-00005</CoreDisToolsVersion>
|
||||
<RuntimeLibrariesVersion Condition="'$(RuntimeLibrariesVersion)' == ''">5.0.0-preview.2.20153.3</RuntimeLibrariesVersion>
|
||||
<RuntimeLibrariesVersion Condition="'$(RuntimeLibrariesVersion)' == ''">5.0.0-preview.5.20263.12</RuntimeLibrariesVersion>
|
||||
<CoreFxUapVersion Condition="'$(CoreFxUapVersion)' == ''">4.7.0-preview6.19265.2</CoreFxUapVersion>
|
||||
<MicrosoftNETCoreAppPackageVersion Condition="'$(MicrosoftNETCoreAppPackageVersion)' == ''">2.1.14</MicrosoftNETCoreAppPackageVersion>
|
||||
<MicrosoftDotNetTestSdkVersion Condition="'$(MicrosoftDotNetTestSdkVersion)' == ''">15.8.0</MicrosoftDotNetTestSdkVersion>
|
||||
|
|
|
@ -57,12 +57,12 @@ See the LICENSE file in the project root for more information.
|
|||
<ItemGroup>
|
||||
<NativeLibrary Include="$(IlcPath)/sdk/libSystem.Private.CoreLib.Native$(NativeLibraryExtension)" />
|
||||
<NativeLibrary Condition="$(NativeCodeGen) == ''" Include="$(IlcPath)/sdk/libSystem.Private.TypeLoader.Native$(NativeLibraryExtension)" />
|
||||
<NativeLibrary Include="$(IlcPath)/framework/System.Native$(NativeLibraryExtension)" />
|
||||
<NativeLibrary Include="$(IlcPath)/framework/System.Globalization.Native$(NativeLibraryExtension)" />
|
||||
<NativeLibrary Include="$(IlcPath)/framework/System.IO.Compression.Native$(NativeLibraryExtension)" />
|
||||
<NativeLibrary Include="$(IlcPath)/framework/System.Net.Security.Native$(NativeLibraryExtension)" />
|
||||
<NativeLibrary Include="$(IlcPath)/framework/System.Security.Cryptography.Native.Apple$(NativeLibraryExtension)" Condition="'$(TargetOS)' == 'OSX'"/>
|
||||
<NativeLibrary Include="$(IlcPath)/framework/System.Security.Cryptography.Native.OpenSsl$(NativeLibraryExtension)" Condition="'$(TargetOS)' != 'OSX'"/>
|
||||
<NativeLibrary Include="$(IlcPath)/framework/libSystem.Native$(NativeLibraryExtension)" />
|
||||
<NativeLibrary Include="$(IlcPath)/framework/libSystem.Globalization.Native$(NativeLibraryExtension)" />
|
||||
<NativeLibrary Include="$(IlcPath)/framework/libSystem.IO.Compression.Native$(NativeLibraryExtension)" />
|
||||
<NativeLibrary Include="$(IlcPath)/framework/libSystem.Net.Security.Native$(NativeLibraryExtension)" />
|
||||
<NativeLibrary Include="$(IlcPath)/framework/libSystem.Security.Cryptography.Native.Apple$(NativeLibraryExtension)" Condition="'$(TargetOS)' == 'OSX'"/>
|
||||
<NativeLibrary Include="$(IlcPath)/framework/libSystem.Security.Cryptography.Native.OpenSsl$(NativeLibraryExtension)" Condition="'$(TargetOS)' != 'OSX'"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetOS)' == 'OSX'">
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
|
@ -2,10 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
|
@ -5,7 +5,6 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
|
@ -24,7 +23,7 @@ internal static partial class Interop
|
|||
internal static extern unsafe int IndexOf(IntPtr sortHandle, char* target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options, int* matchLengthPtr);
|
||||
|
||||
[DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_LastIndexOf")]
|
||||
internal static extern unsafe int LastIndexOf(IntPtr sortHandle, char* target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options);
|
||||
internal static extern unsafe int LastIndexOf(IntPtr sortHandle, char* target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options, int* matchLengthPtr);
|
||||
|
||||
[DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")]
|
||||
internal static extern unsafe int IndexOfOrdinalIgnoreCase(string target, int cwTargetLength, char* pSource, int cwSourceLength, bool findLast);
|
|
@ -2,9 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
|
@ -2,7 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
|
@ -0,0 +1,11 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
internal static partial class Libraries
|
||||
{
|
||||
internal const string GlobalizationNative = "libSystem.Globalization.Native";
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
|
@ -2,7 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
|
@ -11,9 +10,9 @@ internal static partial class Interop
|
|||
internal static partial class Globalization
|
||||
{
|
||||
[DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IsNormalized")]
|
||||
internal static extern int IsNormalized(NormalizationForm normalizationForm, string src, int srcLen);
|
||||
internal static extern unsafe int IsNormalized(NormalizationForm normalizationForm, char* src, int srcLen);
|
||||
|
||||
[DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_NormalizeString")]
|
||||
internal static extern int NormalizeString(NormalizationForm normalizationForm, string src, int srcLen, [Out] char[] dstBuffer, int dstBufferCapacity);
|
||||
internal static extern unsafe int NormalizeString(NormalizationForm normalizationForm, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity);
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
|
@ -3,9 +3,7 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Buffers;
|
||||
using System.Text;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
|
@ -115,7 +115,7 @@ internal static partial class Interop
|
|||
// Represents a platform-agnostic Error and underlying platform-specific errno
|
||||
internal struct ErrorInfo
|
||||
{
|
||||
private Error _error;
|
||||
private readonly Error _error;
|
||||
private int _rawErrno;
|
||||
|
||||
internal ErrorInfo(int errno)
|
||||
|
|
|
@ -7,12 +7,12 @@ internal static partial class Interop
|
|||
internal static partial class Libraries
|
||||
{
|
||||
// Shims
|
||||
internal const string SystemNative = "System.Native";
|
||||
internal const string GlobalizationNative = "System.Globalization.Native";
|
||||
internal const string NetSecurityNative = "System.Net.Security.Native";
|
||||
internal const string CryptoNative = "System.Security.Cryptography.Native.OpenSsl";
|
||||
internal const string CompressionNative = "System.IO.Compression.Native";
|
||||
internal const string IOPortsNative = "System.IO.Ports.Native";
|
||||
internal const string SystemNative = "libSystem.Native";
|
||||
internal const string NetSecurityNative = "libSystem.Net.Security.Native";
|
||||
internal const string CryptoNative = "libSystem.Security.Cryptography.Native.OpenSsl";
|
||||
internal const string CompressionNative = "libSystem.IO.Compression.Native";
|
||||
internal const string IOPortsNative = "libSystem.IO.Ports.Native";
|
||||
internal const string Libdl = "libdl";
|
||||
internal const string HostPolicy = "libhostpolicy";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
|
|
|
@ -51,8 +51,8 @@ internal static partial class Interop
|
|||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_EnumerateInterfaceAddresses")]
|
||||
public static extern int EnumerateInterfaceAddresses(
|
||||
IPv4AddressDiscoveredCallback ipv4Found,
|
||||
IPv6AddressDiscoveredCallback ipv6Found,
|
||||
LinkLayerAddressDiscoveredCallback linkLayerFound);
|
||||
IPv6AddressDiscoveredCallback? ipv6Found,
|
||||
LinkLayerAddressDiscoveredCallback? linkLayerFound);
|
||||
|
||||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_EnumerateGatewayAddressesForInterface")]
|
||||
public static extern int EnumerateGatewayAddressesForInterface(uint interfaceIndex, DnsAddessDiscoveredCallback onGatewayFound);
|
||||
|
|
|
@ -17,6 +17,9 @@ internal static partial class Interop
|
|||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FcntlSetIsNonBlocking", SetLastError=true)]
|
||||
internal static extern int SetIsNonBlocking(SafeHandle fd, int isNonBlocking);
|
||||
|
||||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FcntlGetIsNonBlocking", SetLastError = true)]
|
||||
internal static extern int GetIsNonBlocking(SafeHandle fd, out bool isNonBlocking);
|
||||
|
||||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FcntlSetFD", SetLastError=true)]
|
||||
internal static extern int SetFD(SafeHandle fd, int flags);
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
|
|
|
@ -15,5 +15,8 @@ internal static partial class Interop
|
|||
|
||||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetSockOpt")]
|
||||
internal static extern unsafe Error GetSockOpt(IntPtr socket, SocketOptionLevel optionLevel, SocketOptionName optionName, byte* optionValue, int* optionLen);
|
||||
|
||||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetRawSockOpt")]
|
||||
internal static extern unsafe Error GetRawSockOpt(SafeHandle socket, int optionLevel, int optionName, byte* optionValue, int* optionLen);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
|
|
|
@ -44,6 +44,7 @@ internal static partial class Interop
|
|||
bdevfs = 0x62646576,
|
||||
bfs = 0x1BADFACE,
|
||||
binfmt_misc = 0x42494E4D,
|
||||
bootfs = 0xA56D3FF9,
|
||||
btrfs = 0x9123683E,
|
||||
ceph = 0x00C36400,
|
||||
cgroupfs = 0x0027E0EB,
|
||||
|
@ -65,6 +66,7 @@ internal static partial class Interop
|
|||
ext3 = 0xEF53,
|
||||
ext4 = 0xEF53,
|
||||
fat = 0x4006,
|
||||
fd = 0xF00D1E,
|
||||
fhgfs = 0x19830326,
|
||||
fuse = 0x65735546,
|
||||
fuseblk = 0x65735546,
|
||||
|
@ -86,6 +88,7 @@ internal static partial class Interop
|
|||
jffs2 = 0x72B6,
|
||||
jfs = 0x3153464A,
|
||||
kafs = 0x6B414653,
|
||||
lofs = 0xEF53, /* loopback filesystem, magic same as ext2 */
|
||||
logfs = 0xC97E8168,
|
||||
lustre = 0x0BD00BD0,
|
||||
minix_old = 0x137F, /* orig. minix */
|
||||
|
@ -227,6 +230,7 @@ internal static partial class Interop
|
|||
case "bdevfs":
|
||||
case "befs":
|
||||
case "bfs":
|
||||
case "bootfs":
|
||||
case "bpf_fs":
|
||||
case "btrfs":
|
||||
case "btrfs_test":
|
||||
|
@ -261,6 +265,7 @@ internal static partial class Interop
|
|||
case "jffs":
|
||||
case "jffs2":
|
||||
case "jfs":
|
||||
case "lofs":
|
||||
case "logfs":
|
||||
case "lxfs":
|
||||
case "minix (30 char.)":
|
||||
|
@ -384,15 +389,18 @@ internal static partial class Interop
|
|||
case "cgroupfs":
|
||||
case "cgroup2fs":
|
||||
case "configfs":
|
||||
case "cpuset":
|
||||
case "cramfs":
|
||||
case "cramfs-wend":
|
||||
case "cryptkeeper":
|
||||
case "cpuset":
|
||||
case "ctfs":
|
||||
case "debugfs":
|
||||
case "dev":
|
||||
case "devfs":
|
||||
case "devpts":
|
||||
case "devtmpfs":
|
||||
case "encfs":
|
||||
case "fd":
|
||||
case "fdesc":
|
||||
case "fuse.gvfsd-fuse":
|
||||
case "fusectl":
|
||||
|
@ -400,9 +408,11 @@ internal static partial class Interop
|
|||
case "hugetlbfs":
|
||||
case "libpam-encfs":
|
||||
case "ibpam-mount":
|
||||
case "mntfs":
|
||||
case "mqueue":
|
||||
case "mtpfs":
|
||||
case "mythtvfs":
|
||||
case "mqueue":
|
||||
case "objfs":
|
||||
case "openprom":
|
||||
case "openpromfs":
|
||||
case "pipefs":
|
||||
|
@ -417,6 +427,7 @@ internal static partial class Interop
|
|||
case "securityfs":
|
||||
case "selinux":
|
||||
case "selinuxfs":
|
||||
case "sharefs":
|
||||
case "sockfs":
|
||||
case "sysfs":
|
||||
case "tmpfs":
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
internal static partial class Interop
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
|
|
|
@ -15,5 +15,8 @@ internal static partial class Interop
|
|||
|
||||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_SetSockOpt")]
|
||||
internal static extern unsafe Error SetSockOpt(IntPtr socket, SocketOptionLevel optionLevel, SocketOptionName optionName, byte* optionValue, int optionLen);
|
||||
|
||||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_SetRawSockOpt")]
|
||||
internal static extern unsafe Error SetRawSockOpt(SafeHandle socket, int optionLevel, int optionName, byte* optionValue, int optionLen);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ internal static partial class Interop
|
|||
}
|
||||
|
||||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FStat", SetLastError = true)]
|
||||
internal static extern int FStat(SafeFileHandle fd, out FileStatus output);
|
||||
internal static extern int FStat(SafeHandle fd, out FileStatus output);
|
||||
|
||||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Stat", SetLastError = true)]
|
||||
internal static extern int Stat(string path, out FileStatus output);
|
||||
|
|
|
@ -19,28 +19,6 @@ internal static partial class Interop
|
|||
LOG_NOTICE = 5, /* normal but significant condition */
|
||||
LOG_INFO = 6, /* informational */
|
||||
LOG_DEBUG = 7, /* debug-level messages */
|
||||
// Facilities
|
||||
LOG_KERN = (0<<3), /* kernel messages */
|
||||
LOG_USER = (1<<3), /* random user-level messages */
|
||||
LOG_MAIL = (2<<3), /* mail system */
|
||||
LOG_DAEMON = (3<<3), /* system daemons */
|
||||
LOG_AUTH = (4<<3), /* authorization messages */
|
||||
LOG_SYSLOG = (5<<3), /* messages generated internally by syslogd */
|
||||
LOG_LPR = (6<<3), /* line printer subsystem */
|
||||
LOG_NEWS = (7<<3), /* network news subsystem */
|
||||
LOG_UUCP = (8<<3), /* UUCP subsystem */
|
||||
LOG_CRON = (9<<3), /* clock daemon */
|
||||
LOG_AUTHPRIV = (10<<3), /* authorization messages (private) */
|
||||
LOG_FTP = (11<<3), /* ftp daemon */
|
||||
// Between FTP and Local is reserved for system use
|
||||
LOG_LOCAL0 = (16<<3), /* reserved for local use */
|
||||
LOG_LOCAL1 = (17<<3), /* reserved for local use */
|
||||
LOG_LOCAL2 = (18<<3), /* reserved for local use */
|
||||
LOG_LOCAL3 = (19<<3), /* reserved for local use */
|
||||
LOG_LOCAL4 = (20<<3), /* reserved for local use */
|
||||
LOG_LOCAL5 = (21<<3), /* reserved for local use */
|
||||
LOG_LOCAL6 = (22<<3), /* reserved for local use */
|
||||
LOG_LOCAL7 = (23<<3), /* reserved for local use */
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
|
@ -22,6 +22,6 @@ internal static partial class Interop
|
|||
internal static extern unsafe int Write(SafeHandle fd, byte* buffer, int bufferSize);
|
||||
|
||||
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Write", SetLastError = true)]
|
||||
internal static extern unsafe int Write(int fd, byte* buffer, int bufferSize);
|
||||
internal static extern unsafe int Write(IntPtr fd, byte* buffer, int bufferSize);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ internal partial class Interop
|
|||
internal partial class Advapi32
|
||||
{
|
||||
[DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern bool CryptImportKey(
|
||||
internal static extern unsafe bool CryptImportKey(
|
||||
SafeProvHandle hProv,
|
||||
byte[] pbData,
|
||||
byte* pbData,
|
||||
int dwDataLen,
|
||||
SafeKeyHandle hPubKey,
|
||||
int dwFlags,
|
||||
|
|
|
@ -39,5 +39,6 @@ internal static partial class Interop
|
|||
internal const string CompressionNative = "clrcompression.dll";
|
||||
internal const string CoreWinRT = "api-ms-win-core-winrt-l1-1-0.dll";
|
||||
internal const string MsQuic = "msquic.dll";
|
||||
internal const string HostPolicy = "hostpolicy.dll";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@ internal partial class Interop
|
|||
internal partial class Kernel32
|
||||
{
|
||||
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "K32EnumProcessModules")]
|
||||
internal static extern bool EnumProcessModules(SafeProcessHandle handle, IntPtr modules, int size, ref int needed);
|
||||
internal static extern bool EnumProcessModules(SafeProcessHandle handle, IntPtr[]? modules, int size, out int needed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,15 @@ internal static partial class Interop
|
|||
{
|
||||
internal static unsafe partial class Kernel32
|
||||
{
|
||||
// Under debug mode only, we'll want to check the error codes
|
||||
// of some of the p/invokes we make.
|
||||
|
||||
#if DEBUG
|
||||
private const bool SetLastErrorForDebug = true;
|
||||
#else
|
||||
private const bool SetLastErrorForDebug = false;
|
||||
#endif
|
||||
|
||||
internal const uint LOCALE_ALLOW_NEUTRAL_NAMES = 0x08000000; // Flag to allow returning neutral names/lcids for name conversion
|
||||
internal const uint LOCALE_ILANGUAGE = 0x00000001;
|
||||
internal const uint LOCALE_SUPPLEMENTAL = 0x00000002;
|
||||
|
@ -31,6 +40,10 @@ internal static partial class Interop
|
|||
|
||||
internal const uint TIME_NOSECONDS = 0x00000002;
|
||||
|
||||
internal const int GEOCLASS_NATION = 16;
|
||||
internal const int GEO_ISO2 = 4;
|
||||
internal const int GEOID_NOT_AVAILABLE = -1;
|
||||
|
||||
internal const string LOCALE_NAME_USER_DEFAULT = null;
|
||||
internal const string LOCALE_NAME_SYSTEM_DEFAULT = "!x-sys-default-locale";
|
||||
|
||||
|
@ -40,7 +53,7 @@ internal static partial class Interop
|
|||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
internal static extern int LocaleNameToLCID(string lpName, uint dwFlags);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern int LCMapStringEx(
|
||||
string? lpLocaleName,
|
||||
uint dwMapFlags,
|
||||
|
@ -52,7 +65,7 @@ internal static partial class Interop
|
|||
void* lpReserved,
|
||||
IntPtr sortHandle);
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "FindNLSStringEx")]
|
||||
[DllImport("kernel32.dll", EntryPoint = "FindNLSStringEx", SetLastError = SetLastErrorForDebug)]
|
||||
internal static extern int FindNLSStringEx(
|
||||
char* lpLocaleName,
|
||||
uint dwFindNLSStringFlags,
|
||||
|
@ -85,14 +98,14 @@ internal static partial class Interop
|
|||
int cchCount2,
|
||||
bool bIgnoreCase);
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "FindStringOrdinal")]
|
||||
[DllImport("kernel32.dll", EntryPoint = "FindStringOrdinal", SetLastError = SetLastErrorForDebug)]
|
||||
internal static extern int FindStringOrdinal(
|
||||
uint dwFindStringOrdinalFlags,
|
||||
char* lpStringSource,
|
||||
int cchSource,
|
||||
char* lpStringValue,
|
||||
int cchValue,
|
||||
int bIgnoreCase);
|
||||
BOOL bIgnoreCase);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
internal static extern bool IsNLSDefinedString(
|
||||
|
@ -124,6 +137,12 @@ internal static partial class Interop
|
|||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
internal static extern int GetCalendarInfoEx(string? lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, IntPtr lpValue);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
internal static extern int GetUserGeoID(int geoClass);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
internal static extern int GetGeoInfo(int location, int geoType, char* lpGeoData, int cchData, int LangId);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
internal static extern bool EnumCalendarInfoExEx(EnumCalendarInfoProcExEx pCalInfoEnumProcExEx, string lpLocaleName, uint Calendar, string? lpReserved, uint CalType, void* lParam);
|
||||
|
||||
|
|
|
@ -10,6 +10,6 @@ internal partial class Interop
|
|||
internal partial class Kernel32
|
||||
{
|
||||
[DllImport(Libraries.Kernel32, SetLastError = true)]
|
||||
internal static extern bool IsWow64Process(SafeProcessHandle hProcess, ref bool Wow64Process);
|
||||
internal static extern bool IsWow64Process(SafeProcessHandle hProcess, out bool Wow64Process);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,21 +3,21 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
internal static partial class Interop
|
||||
{
|
||||
internal static partial class Normaliz
|
||||
{
|
||||
[DllImport("Normaliz.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern bool IsNormalizedString(int normForm, string source, int length);
|
||||
internal static extern unsafe BOOL IsNormalizedString(NormalizationForm normForm, char* source, int length);
|
||||
|
||||
[DllImport("Normaliz.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern int NormalizeString(
|
||||
int normForm,
|
||||
string source,
|
||||
internal static extern unsafe int NormalizeString(
|
||||
NormalizationForm normForm,
|
||||
char* source,
|
||||
int sourceLength,
|
||||
[System.Runtime.InteropServices.OutAttribute]
|
||||
char[]? destination,
|
||||
char* destination,
|
||||
int destinationLength);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
|
@ -7,15 +7,16 @@ internal static partial class Interop
|
|||
internal class StatusOptions
|
||||
{
|
||||
// Error codes from ntstatus.h
|
||||
internal const uint STATUS_SUCCESS = 0x00000000;
|
||||
internal const uint STATUS_SOME_NOT_MAPPED = 0x00000107;
|
||||
internal const uint STATUS_NO_MORE_FILES = 0x80000006;
|
||||
internal const uint STATUS_INVALID_PARAMETER = 0xC000000D;
|
||||
internal const uint STATUS_NO_MEMORY = 0xC0000017;
|
||||
internal const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034;
|
||||
internal const uint STATUS_NONE_MAPPED = 0xC0000073;
|
||||
internal const uint STATUS_SUCCESS = 0x00000000;
|
||||
internal const uint STATUS_SOME_NOT_MAPPED = 0x00000107;
|
||||
internal const uint STATUS_NO_MORE_FILES = 0x80000006;
|
||||
internal const uint STATUS_INVALID_PARAMETER = 0xC000000D;
|
||||
internal const uint STATUS_FILE_NOT_FOUND = 0xC000000F;
|
||||
internal const uint STATUS_NO_MEMORY = 0xC0000017;
|
||||
internal const uint STATUS_ACCESS_DENIED = 0xC0000022;
|
||||
internal const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034;
|
||||
internal const uint STATUS_ACCOUNT_RESTRICTION = 0xC000006E;
|
||||
internal const uint STATUS_NONE_MAPPED = 0xC0000073;
|
||||
internal const uint STATUS_INSUFFICIENT_RESOURCES = 0xC000009A;
|
||||
internal const uint STATUS_ACCESS_DENIED = 0xC0000022;
|
||||
internal const uint STATUS_ACCOUNT_RESTRICTION = 0xc000006e;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,19 +18,15 @@ internal partial class Interop
|
|||
return RtlGetVersion(ref osvi);
|
||||
}
|
||||
|
||||
internal static unsafe string RtlGetVersion()
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
internal unsafe struct RTL_OSVERSIONINFOEX
|
||||
{
|
||||
const string Version = "Microsoft Windows";
|
||||
if (RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi) == 0)
|
||||
{
|
||||
return osvi.szCSDVersion[0] != '\0' ?
|
||||
string.Format("{0} {1}.{2}.{3} {4}", Version, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber, new string(&(osvi.szCSDVersion[0]))) :
|
||||
string.Format("{0} {1}.{2}.{3}", Version, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Version;
|
||||
}
|
||||
internal uint dwOSVersionInfoSize;
|
||||
internal uint dwMajorVersion;
|
||||
internal uint dwMinorVersion;
|
||||
internal uint dwBuildNumber;
|
||||
internal uint dwPlatformId;
|
||||
internal fixed char szCSDVersion[128];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -220,7 +220,7 @@ namespace System.Diagnostics
|
|||
StringBuilder installBuilder = new StringBuilder();
|
||||
installBuilder.Append(installRoot);
|
||||
if (!installRoot.EndsWith("\\", StringComparison.Ordinal))
|
||||
installBuilder.Append("\\");
|
||||
installBuilder.Append('\\');
|
||||
installBuilder.Append(version);
|
||||
dllDir = installBuilder.ToString();
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#nullable enable
|
||||
namespace System.Diagnostics
|
||||
{
|
||||
internal static partial class TraceListenerHelpers
|
||||
{
|
||||
private static volatile string s_processName;
|
||||
private static volatile string? s_processName;
|
||||
|
||||
internal static int GetThreadId()
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#nullable enable
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -11,8 +12,8 @@ namespace System.IO
|
|||
/// <summary>Provides an in-memory stream composed of non-contiguous chunks.</summary>
|
||||
internal sealed class ChunkedMemoryStream : Stream
|
||||
{
|
||||
private MemoryChunk _headChunk;
|
||||
private MemoryChunk _currentChunk;
|
||||
private MemoryChunk? _headChunk;
|
||||
private MemoryChunk? _currentChunk;
|
||||
|
||||
private const int InitialChunkDefaultSize = 1024;
|
||||
private const int MaxChunkSize = 1024 * InitialChunkDefaultSize;
|
||||
|
@ -24,7 +25,7 @@ namespace System.IO
|
|||
{
|
||||
byte[] result = new byte[_totalLength];
|
||||
int offset = 0;
|
||||
for (MemoryChunk chunk = _headChunk; chunk != null; chunk = chunk._next)
|
||||
for (MemoryChunk? chunk = _headChunk; chunk != null; chunk = chunk._next)
|
||||
{
|
||||
Debug.Assert(chunk._next == null || chunk._freeOffset == chunk._buffer.Length);
|
||||
Buffer.BlockCopy(chunk._buffer, 0, result, offset, chunk._freeOffset);
|
||||
|
@ -109,7 +110,7 @@ namespace System.IO
|
|||
{
|
||||
internal readonly byte[] _buffer;
|
||||
internal int _freeOffset;
|
||||
internal MemoryChunk _next;
|
||||
internal MemoryChunk? _next;
|
||||
|
||||
internal MemoryChunk(int bufferSize) { _buffer = new byte[bufferSize]; }
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#nullable enable
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
@ -113,7 +114,7 @@ namespace System.Net.Http
|
|||
return _innerStream.ReadAsync(buffer, cancellationToken);
|
||||
}
|
||||
|
||||
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
|
||||
{
|
||||
return _innerStream.BeginRead(buffer, offset, count, callback, state);
|
||||
}
|
||||
|
@ -167,7 +168,7 @@ namespace System.Net.Http
|
|||
return _innerStream.WriteAsync(buffer, cancellationToken);
|
||||
}
|
||||
|
||||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
|
||||
{
|
||||
return _innerStream.BeginWrite(buffer, offset, count, callback, state);
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace System.IO
|
|||
)
|
||||
{
|
||||
// Assert so we can track down other cases (if any) to add to our test suite
|
||||
Debug.Assert(errorCode == Interop.Errors.ERROR_ACCESS_DENIED || errorCode == Interop.Errors.ERROR_SHARING_VIOLATION,
|
||||
Debug.Assert(errorCode == Interop.Errors.ERROR_ACCESS_DENIED || errorCode == Interop.Errors.ERROR_SHARING_VIOLATION || errorCode == Interop.Errors.ERROR_SEM_TIMEOUT,
|
||||
$"Unexpected error code getting attributes {errorCode} from path {path}");
|
||||
|
||||
// Files that are marked for deletion will not let you GetFileAttributes,
|
||||
|
|
|
@ -105,7 +105,7 @@ namespace System.IO
|
|||
new ValueTask<int>(Task.FromCanceled<int>(cancellationToken)) :
|
||||
new ValueTask<int>(Read(buffer.Span));
|
||||
|
||||
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) =>
|
||||
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) =>
|
||||
TaskToApm.Begin(ReadAsync(buffer, offset, count), callback, state);
|
||||
|
||||
public override int EndRead(IAsyncResult asyncResult) =>
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#nullable enable
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
|
||||
namespace System.IO
|
||||
|
@ -47,8 +49,7 @@ namespace System.IO
|
|||
/// </summary>
|
||||
public string GetNextValue(string key)
|
||||
{
|
||||
string value;
|
||||
if (!TryGetNextValue(key, out value))
|
||||
if (!TryGetNextValue(key, out string? value))
|
||||
{
|
||||
throw new InvalidOperationException("Couldn't get next value with key " + key);
|
||||
}
|
||||
|
@ -62,7 +63,7 @@ namespace System.IO
|
|||
/// Tries to get the next occurrence of the given key from the current position of the reader.
|
||||
/// If successful, returns true and stores the result in 'value'. Otherwise, returns false.
|
||||
/// </summary>
|
||||
public bool TryGetNextValue(string key, out string value)
|
||||
public bool TryGetNextValue(string key, [NotNullWhen(true)] out string? value)
|
||||
{
|
||||
Debug.Assert(_buffer != null);
|
||||
if (_currentIndex >= _buffer.Length)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#nullable enable
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
|
||||
|
@ -16,12 +17,12 @@ namespace System.Runtime.ExceptionServices
|
|||
Debug.Assert(exception != null, "Expected non-null Exception");
|
||||
|
||||
const string ExceptionRemoteStackTraceStringName = "_remoteStackTraceString";
|
||||
FieldInfo fi = typeof(Exception).GetField(ExceptionRemoteStackTraceStringName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
FieldInfo? fi = typeof(Exception).GetField(ExceptionRemoteStackTraceStringName, BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
if (fi != null)
|
||||
{
|
||||
string text =
|
||||
(string)fi.GetValue(exception) +
|
||||
(string?)fi.GetValue(exception) +
|
||||
Environment.StackTrace + Environment.NewLine +
|
||||
"--- End of stack trace from AddCurrentStack ---" + Environment.NewLine;
|
||||
fi.SetValue(exception, text);
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace System
|
|||
/// <summary>Provides an object wrapper that can transition between strong and weak references to the object.</summary>
|
||||
internal sealed class StrongToWeakReference<T> : WeakReference where T : class
|
||||
{
|
||||
private T _strongRef;
|
||||
private T? _strongRef;
|
||||
|
||||
/// <summary>Initializes the instance with a strong reference to the specified object.</summary>
|
||||
/// <param name="obj">The object to wrap.</param>
|
||||
|
@ -30,9 +30,9 @@ namespace System
|
|||
}
|
||||
|
||||
/// <summary>Gets the wrapped object.</summary>
|
||||
public new T Target => _strongRef ?? WeakTarget;
|
||||
public new T? Target => _strongRef ?? WeakTarget;
|
||||
|
||||
/// <summary>Gets the wrapped object via its weak reference.</summary>
|
||||
private T WeakTarget => base.Target as T;
|
||||
private T? WeakTarget => base.Target as T;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace System.Text
|
|||
// The value 360 was chosen in discussion with performance experts as a compromise between using
|
||||
// as litle memory per thread as possible and still covering a large part of short-lived
|
||||
// StringBuilder creations on the startup path of VS designers.
|
||||
private const int MaxBuilderSize = 360;
|
||||
internal const int MaxBuilderSize = 360;
|
||||
private const int DefaultCapacity = 16; // == StringBuilder.DefaultCapacity
|
||||
|
||||
// WARNING: We allow diagnostic tools to directly inspect this member (t_cachedInstance).
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#nullable enable
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ExceptionServices;
|
||||
|
||||
|
@ -19,11 +21,11 @@ namespace System.Threading.Tasks
|
|||
/// The continuation to invoke when the operation completes, or <see cref="s_completionSentinel"/> if the operation
|
||||
/// has completed before OnCompleted is called.
|
||||
/// </summary>
|
||||
private Action _continuation;
|
||||
private Action? _continuation;
|
||||
/// <summary>The exception representing the failed async operation, if it failed.</summary>
|
||||
private ExceptionDispatchInfo _error;
|
||||
private ExceptionDispatchInfo? _error;
|
||||
/// <summary>The result of the async operation, if it succeeded.</summary>
|
||||
private TResult _result;
|
||||
[AllowNull] private TResult _result = default;
|
||||
#if DEBUG
|
||||
private bool _resultSet;
|
||||
#endif
|
||||
|
@ -39,7 +41,7 @@ namespace System.Threading.Tasks
|
|||
{
|
||||
get
|
||||
{
|
||||
Action c = Volatile.Read(ref _continuation);
|
||||
Action? c = Volatile.Read(ref _continuation);
|
||||
Debug.Assert(c == null || c == s_completionSentinel);
|
||||
return c != null;
|
||||
}
|
||||
|
@ -55,7 +57,7 @@ namespace System.Threading.Tasks
|
|||
|
||||
// Propagate any error if there is one, clearing it out first to prepare for reuse.
|
||||
// We don't need to clear a result, as result and error are mutually exclusive.
|
||||
ExceptionDispatchInfo error = _error;
|
||||
ExceptionDispatchInfo? error = _error;
|
||||
if (error != null)
|
||||
{
|
||||
_error = null;
|
||||
|
@ -101,7 +103,7 @@ namespace System.Threading.Tasks
|
|||
/// <summary>Alerts any awaiter that the operation has completed.</summary>
|
||||
private void NotifyAwaiter()
|
||||
{
|
||||
Action c = _continuation ?? Interlocked.CompareExchange(ref _continuation, s_completionSentinel, null);
|
||||
Action? c = _continuation ?? Interlocked.CompareExchange(ref _continuation, s_completionSentinel, null);
|
||||
if (c != null)
|
||||
{
|
||||
Debug.Assert(c != s_completionSentinel);
|
||||
|
@ -122,7 +124,7 @@ namespace System.Threading.Tasks
|
|||
{
|
||||
Debug.Assert(continuation != null);
|
||||
|
||||
Action c = _continuation ?? Interlocked.CompareExchange(ref _continuation, continuation, null);
|
||||
Action? c = _continuation ?? Interlocked.CompareExchange(ref _continuation, continuation, null);
|
||||
if (c != null)
|
||||
{
|
||||
Debug.Assert(c == s_completionSentinel);
|
||||
|
|
|
@ -71,6 +71,8 @@
|
|||
<_filteredNuGetDeployByFileName Include="@(_nuGetDeployByFileName)" Condition="'%(Identity)' == 'netstandard'" />
|
||||
<_filteredNuGetDeployByFileName Include="@(_nuGetDeployByFileName)" Condition="'%(Identity)' == 'mscorlib'" />
|
||||
|
||||
<_filteredNuGetDeployByFileName Include="@(_nuGetDeployByFileName)" Condition="$([System.String]::new('%(Identity)').StartsWith('libSystem'))" />
|
||||
|
||||
<!-- TODO: https://github.com/dotnet/corert/issues/5496 -->
|
||||
<_filteredNuGetDeployByFileName Include="@(_nuGetDeployByFileName)" Condition="'%(Identity)' == 'clrcompression'" />
|
||||
|
||||
|
|
|
@ -589,6 +589,16 @@ namespace ILCompiler.CppCodeGen
|
|||
sb.AppendLine();
|
||||
AppendCppMethodDeclaration(sb, method, true);
|
||||
sb.AppendLine();
|
||||
|
||||
// TODO: workaround unreachable globalization methods
|
||||
string moduleName = method.GetPInvokeMethodMetadata().Module;
|
||||
if (moduleName == (_compilation.TypeSystemContext.Target.IsWindows ? "libSystem.Globalization.Native" : "kernel32.dll"))
|
||||
{
|
||||
sb.Append("{ throw 0; }");
|
||||
methodCodeNodeNeedingCode.SetCode(sb.ToString(), Array.Empty<Object>());
|
||||
return;
|
||||
}
|
||||
|
||||
sb.Append("{");
|
||||
sb.Indent();
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace ILCompiler
|
|||
else
|
||||
{
|
||||
// Account for System.Private.CoreLib.Native / System.Globalization.Native / System.Native / etc
|
||||
return importModule.StartsWith("System.");
|
||||
return importModule.StartsWith("libSystem.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Internal.Resources
|
|||
{
|
||||
public abstract bool Initialize(string libpath, string reswFilename, out PRIExceptionInfo? exceptionInfo);
|
||||
|
||||
public abstract string GetString(string stringName, string? startingCulture, string? neutralResourcesCulture);
|
||||
public abstract string? GetString(string stringName, string? startingCulture, string? neutralResourcesCulture);
|
||||
|
||||
public abstract CultureInfo? GlobalResourceContextBestFitCultureInfo
|
||||
{
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Win32.SafeHandles
|
||||
{
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -149,6 +149,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\IReadOnlyDictionary.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\IReadOnlyList.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\ISet.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\IReadOnlySet.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\KeyNotFoundException.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\KeyValuePair.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\List.cs" />
|
||||
|
@ -239,16 +240,24 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Calendar.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarAlgorithmType.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Icu.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Nls.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarWeekRule.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendricalCalculationsHelper.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CharUnicodeInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CharUnicodeInfoData.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\ChineseLunisolarCalendar.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Icu.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Invariant.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Nls.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareOptions.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Icu.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Nls.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Icu.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Nls.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureNotFoundException.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureTypes.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\DateTimeFormat.cs" />
|
||||
|
@ -266,14 +275,22 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HebrewCalendar.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HebrewNumber.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IcuLocaleData.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Icu.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Nls.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\InternalGlobalizationHelper.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\ISOWeek.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Icu.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Nls.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseLunisolarCalendar.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JulianCalendar.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\KoreanCalendar.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\KoreanLunisolarCalendar.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Icu.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Nls.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\NumberFormatInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\NumberStyles.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\PersianCalendar.cs" />
|
||||
|
@ -286,6 +303,8 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TaiwanLunisolarCalendar.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextElementEnumerator.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Icu.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Nls.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\ThaiBuddhistCalendar.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TimeSpanFormat.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TimeSpanParse.cs" />
|
||||
|
@ -477,6 +496,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\SignatureToken.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\StackBehaviour.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\StringToken.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\TypeNameBuilder.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\TypeToken.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\EventAttributes.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\EventInfo.cs" />
|
||||
|
@ -735,7 +755,6 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\Vector64_1.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\Vector64DebugView_1.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Intrinsics\X86\Enums.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\AssemblyDependencyResolver.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\AssemblyLoadContext.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\Loader\LibraryNameVariation.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\MemoryFailPoint.cs" />
|
||||
|
@ -859,7 +878,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\Text\Unicode\Utf8Utility.Helpers.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Text\Unicode\Utf8Utility.Transcoding.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Text\Unicode\Utf8Utility.Validation.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Text\Unicode\Utf8Utility.WhiteSpace.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Text\Unicode\Utf8Utility.WhiteSpace.CoreLib.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UnicodeDebug.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UnicodeEncoding.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UnicodeUtility.cs" />
|
||||
|
@ -967,12 +986,64 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\UnauthorizedAccessException.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\UnhandledExceptionEventArgs.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\UnhandledExceptionEventHandler.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\UnitySerializationHolder.cs"/>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\UnitySerializationHolder.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\ValueTuple.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Version.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Void.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\WeakReference.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\WeakReference.T.cs" />
|
||||
<Compile Include="$(CommonPath)Interop\Interop.Libraries.cs">
|
||||
<Link>Common\Interop\Interop.Libraries.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Interop.Calendar.cs">
|
||||
<Link>Common\Interop\Interop.Calendar.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Interop.Casing.cs">
|
||||
<Link>Common\Interop\Interop.Casing.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Interop.Collation.cs">
|
||||
<Link>Common\Interop\Interop.Collation.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Interop.ICU.cs">
|
||||
<Link>Common\Interop\Interop.ICU.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Interop.Idna.cs">
|
||||
<Link>Common\Interop\Interop.Idna.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Interop.Locale.cs">
|
||||
<Link>Common\Interop\Interop.Locale.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Interop.Normalization.cs">
|
||||
<Link>Common\Interop\Interop.Normalization.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Interop.ResultCode.cs">
|
||||
<Link>Common\Interop\Interop.ResultCode.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Interop.TimeZoneInfo.cs">
|
||||
<Link>Common\Interop\Interop.TimeZoneInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Interop.Utils.cs">
|
||||
<Link>Common\Interop\Interop.Utils.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Interop.Errors.cs">
|
||||
<Link>Common\Interop\Interop.Errors.cs</Link>
|
||||
</Compile>
|
||||
<!-- The CLR internally uses a BOOL type analogous to the Windows BOOL type on Unix -->
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Interop.BOOL.cs">
|
||||
<Link>Common\Interop\Windows\Interop.BOOL.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.Globalization.cs">
|
||||
<Link>Common\Interop\Windows\Kernel32\Interop.Globalization.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs">
|
||||
<Link>Common\Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Normaliz\Interop.Idna.cs">
|
||||
<Link>Common\Interop\Windows\Normaliz\Interop.Idna.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Normaliz\Interop.Normalization.cs">
|
||||
<Link>Common\Interop\Windows\Normaliz\Interop.Normalization.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)System\HResults.cs">
|
||||
<Link>Common\System\HResults.cs</Link>
|
||||
</Compile>
|
||||
|
@ -1018,6 +1089,11 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventActivityOptions.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventCounter.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventDescriptor.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipe.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipeEventDispatcher.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipeEventProvider.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipeMetadataGenerator.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventPipePayloadDecoder.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventProvider.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventSource.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\EventSourceException.cs" />
|
||||
|
@ -1025,7 +1101,9 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\IEventProvider.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\IncrementingEventCounter.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\IncrementingPollingCounter.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\NativeRuntimeEventSource.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\PollingCounter.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\RuntimeEventSource.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\StubEnvironment.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\Winmeta.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\ArrayTypeInfo.cs" />
|
||||
|
@ -1052,12 +1130,14 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\Statics.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingDataCollector.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingDataType.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingEventHandleTable.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingEventSource.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingEventTraits.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingEventTypes.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingMetadataCollector.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingTypeInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TypeAnalysis.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\XplatEventLogger.cs" Condition="'$(FeatureXplatEventSource)' == 'true'" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)\..\..\Common\src\System\HexConverter.cs">
|
||||
|
@ -1165,9 +1245,6 @@
|
|||
<Compile Include="$(CommonPath)Interop\Windows\Crypt32\Interop.CryptProtectMemory.cs">
|
||||
<Link>Common\Interop\Windows\Crypt32\Interop.CryptProtectMemory.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Interop.BOOL.cs">
|
||||
<Link>Common\Interop\Windows\Interop.BOOL.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Interop.BOOLEAN.cs">
|
||||
<Link>Common\Interop\Windows\Interop.BOOLEAN.cs</Link>
|
||||
</Compile>
|
||||
|
@ -1282,12 +1359,6 @@
|
|||
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetTempPathW.cs">
|
||||
<Link>Common\Interop\Windows\Kernel32\Interop.GetTempPathW.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetVersionExW.cs">
|
||||
<Link>Common\Interop\Windows\Kernel32\Interop.GetVersionExW.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.Globalization.cs">
|
||||
<Link>Common\Interop\Windows\Kernel32\Interop.Globalization.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GlobalMemoryStatusEx.cs">
|
||||
<Link>Common\Interop\Windows\Kernel32\Interop.GlobalMemoryStatusEx.cs</Link>
|
||||
</Compile>
|
||||
|
@ -1336,9 +1407,6 @@
|
|||
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_NativeOverlapped.cs">
|
||||
<Link>Common\Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_NativeOverlapped.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs">
|
||||
<Link>Common\Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs">
|
||||
<Link>Common\Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs</Link>
|
||||
</Compile>
|
||||
|
@ -1399,18 +1467,15 @@
|
|||
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs">
|
||||
<Link>Common\Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Normaliz\Interop.Idna.cs">
|
||||
<Link>Common\Interop\Windows\Normaliz\Interop.Idna.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Normaliz\Interop.Normalization.cs">
|
||||
<Link>Common\Interop\Windows\Normaliz\Interop.Normalization.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\NtDll\Interop.NtQueryInformationFile.cs">
|
||||
<Link>Common\Interop\Windows\NtDll\Interop.NtQueryInformationFile.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\NtDll\Interop.NtQuerySystemInformation.cs">
|
||||
<Link>Common\Interop\Windows\NtDll\Interop.NtQuerySystemInformation.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\NtDll\Interop.RtlGetVersion.cs">
|
||||
<Link>Common\Interop\Windows\NtDll\Interop.RtlGetVersion.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Windows\NtDll\Interop.SYSTEM_LEAP_SECOND_INFORMATION.cs">
|
||||
<Link>Common\Interop\Windows\NtDll\Interop.SYSTEM_LEAP_SECOND_INFORMATION.cs</Link>
|
||||
</Compile>
|
||||
|
@ -1455,15 +1520,8 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\DebugProvider.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Stopwatch.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\RuntimeEventSourceHelper.Windows.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Win32.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Win32.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Guid.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DriveInfoInternal.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Windows.cs" />
|
||||
|
@ -1486,6 +1544,9 @@
|
|||
<ItemGroup Condition="'$(FeatureAsyncCausalityTracer)' != 'true'">
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\AsyncCausalityTracer.Noop.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(FeatureComWrappers)' != 'true'">
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\ComWrappers.PlatformNotSupported.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(FeatureCominterop)' != 'true'">
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\Marshal.NoCom.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\ComEventsHelpers.NoCom.cs" />
|
||||
|
@ -1500,7 +1561,6 @@
|
|||
<!-- CoreCLR uses PAL layer that emulates Windows API on Unix. This is bridge for that PAL layer. See issue dotnet/runtime/#31721. -->
|
||||
<ItemGroup Condition="'$(TargetsWindows)' == 'true' or '$(FeatureCoreCLR)'=='true'">
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeWaitHandle.Windows.cs" />
|
||||
<Compile Include="$(CommonPath)Interop\Windows\Interop.Errors.cs" />
|
||||
<Compile Include="$(CommonPath)Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs">
|
||||
<Link>Common\Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs</Link>
|
||||
</Compile>
|
||||
|
@ -1545,7 +1605,7 @@
|
|||
</Compile>
|
||||
<Compile Include="$(CommonPath)System\IO\Win32Marshal.cs">
|
||||
<Link>Common\System\IO\Win32Marshal.cs</Link>
|
||||
</Compile>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.Variables.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Mutex.Windows.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Semaphore.Windows.cs" />
|
||||
|
@ -1566,36 +1626,6 @@
|
|||
<Compile Include="$(CommonPath)Interop\Unix\Interop.Libraries.cs">
|
||||
<Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Calendar.cs">
|
||||
<Link>Common\Interop\Unix\System.Globalization.Native\Interop.Calendar.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Casing.cs">
|
||||
<Link>Common\Interop\Unix\System.Globalization.Native\Interop.Casing.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Collation.cs">
|
||||
<Link>Common\Interop\Unix\System.Globalization.Native\Interop.Collation.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.ICU.cs">
|
||||
<Link>Common\Interop\Unix\System.Globalization.Native\Interop.ICU.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Idna.cs">
|
||||
<Link>Common\Interop\Unix\System.Globalization.Native\Interop.Idna.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Locale.cs">
|
||||
<Link>Common\Interop\Unix\System.Globalization.Native\Interop.Locale.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Normalization.cs">
|
||||
<Link>Common\Interop\Unix\System.Globalization.Native\Interop.Normalization.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.ResultCode.cs">
|
||||
<Link>Common\Interop\Unix\System.Globalization.Native\Interop.ResultCode.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.TimeZoneInfo.cs">
|
||||
<Link>Common\Interop\Unix\System.Globalization.Native\Interop.TimeZoneInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Utils.cs">
|
||||
<Link>Common\Interop\Unix\System.Globalization.Native\Interop.Utils.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.Access.cs">
|
||||
<Link>Common\Interop\Unix\System.Native\Interop.Access.cs</Link>
|
||||
</Compile>
|
||||
|
@ -1705,22 +1735,15 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)System\DateTime.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\DebugProvider.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Stopwatch.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\RuntimeEventSourceHelper.Unix.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.NoRegistry.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.Unix.GetFolderPathCore.cs" Condition="'$(TargetsiOS)' != 'true' and '$(TargetstvOS)' != 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\LocaleData.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\Guid.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DriveInfoInternal.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.OSX.cs" Condition="'$(TargetsOSX)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Linux.cs" Condition="'$(TargetsOSX)' != 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.OSX.cs" Condition="'$(TargetsOSX)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Linux.cs" Condition="'$(TargetsOSX)' != 'true' and '$(TargetsiOS)' != 'true' and '$(TargetstvOS)' != 'true'" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.Unix.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.Unix.cs" />
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace System
|
|||
public static string BaseDirectory =>
|
||||
// The value of APP_CONTEXT_BASE_DIRECTORY key has to be a string and it is not allowed to be any other type.
|
||||
// Otherwise the caller will get invalid cast exception
|
||||
(string?)GetData("APP_CONTEXT_BASE_DIRECTORY") ??
|
||||
GetData("APP_CONTEXT_BASE_DIRECTORY") as string ??
|
||||
(s_defaultBaseDirectory ??= GetBaseDirectoryCore());
|
||||
|
||||
public static string? TargetFrameworkName =>
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace System
|
|||
{
|
||||
try
|
||||
{
|
||||
object config = AppContext.GetData(configName);
|
||||
object? config = AppContext.GetData(configName);
|
||||
int result = defaultValue;
|
||||
switch (config)
|
||||
{
|
||||
|
@ -54,7 +54,7 @@ namespace System
|
|||
{
|
||||
try
|
||||
{
|
||||
object config = AppContext.GetData(configName);
|
||||
object? config = AppContext.GetData(configName);
|
||||
short result = defaultValue;
|
||||
switch (config)
|
||||
{
|
||||
|
|
|
@ -149,8 +149,7 @@ namespace System
|
|||
|
||||
public bool? IsCompatibilitySwitchSet(string value)
|
||||
{
|
||||
bool result;
|
||||
return AppContext.TryGetSwitch(value, out result) ? result : default(bool?);
|
||||
return AppContext.TryGetSwitch(value, out bool result) ? result : default(bool?);
|
||||
}
|
||||
|
||||
public bool IsDefaultAppDomain() => true;
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Collections.Generic;
|
|||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -26,6 +27,11 @@ namespace System
|
|||
internal const int MaxArrayLength = 0X7FEFFFFF;
|
||||
internal const int MaxByteArrayLength = 0x7FFFFFC7;
|
||||
|
||||
// This is the threshold where Introspective sort switches to Insertion sort.
|
||||
// Empirically, 16 seems to speed up most cases without slowing down others, at least for integers.
|
||||
// Large value types may benefit from a smaller number.
|
||||
internal const int IntrosortSizeThreshold = 16;
|
||||
|
||||
// This ctor exists solely to prevent C# from generating a protected .ctor that violates the surface area.
|
||||
private protected Array() { }
|
||||
|
||||
|
@ -510,9 +516,7 @@ namespace System
|
|||
if (comparer == Comparer.Default)
|
||||
{
|
||||
CorElementType et = array.GetCorElementTypeOfElementType();
|
||||
if (et.IsPrimitiveType()
|
||||
// IntPtr/UIntPtr does not implement IComparable
|
||||
&& (et != CorElementType.ELEMENT_TYPE_I) && (et != CorElementType.ELEMENT_TYPE_U))
|
||||
if (et.IsPrimitiveType())
|
||||
{
|
||||
if (value == null)
|
||||
return ~index;
|
||||
|
@ -538,15 +542,27 @@ namespace System
|
|||
result = GenericBinarySearch<ushort>(array, adjustedIndex, length, value);
|
||||
break;
|
||||
case CorElementType.ELEMENT_TYPE_I4:
|
||||
#if TARGET_32BIT
|
||||
case CorElementType.ELEMENT_TYPE_I:
|
||||
#endif
|
||||
result = GenericBinarySearch<int>(array, adjustedIndex, length, value);
|
||||
break;
|
||||
case CorElementType.ELEMENT_TYPE_U4:
|
||||
#if TARGET_32BIT
|
||||
case CorElementType.ELEMENT_TYPE_U:
|
||||
#endif
|
||||
result = GenericBinarySearch<uint>(array, adjustedIndex, length, value);
|
||||
break;
|
||||
case CorElementType.ELEMENT_TYPE_I8:
|
||||
#if TARGET_64BIT
|
||||
case CorElementType.ELEMENT_TYPE_I:
|
||||
#endif
|
||||
result = GenericBinarySearch<long>(array, adjustedIndex, length, value);
|
||||
break;
|
||||
case CorElementType.ELEMENT_TYPE_U8:
|
||||
#if TARGET_64BIT
|
||||
case CorElementType.ELEMENT_TYPE_U:
|
||||
#endif
|
||||
result = GenericBinarySearch<ulong>(array, adjustedIndex, length, value);
|
||||
break;
|
||||
case CorElementType.ELEMENT_TYPE_R4:
|
||||
|
@ -1674,15 +1690,27 @@ namespace System
|
|||
GenericSort<ushort>(keys, items, adjustedIndex, length);
|
||||
return;
|
||||
case CorElementType.ELEMENT_TYPE_I4:
|
||||
#if TARGET_32BIT
|
||||
case CorElementType.ELEMENT_TYPE_I:
|
||||
#endif
|
||||
GenericSort<int>(keys, items, adjustedIndex, length);
|
||||
return;
|
||||
case CorElementType.ELEMENT_TYPE_U4:
|
||||
#if TARGET_32BIT
|
||||
case CorElementType.ELEMENT_TYPE_U:
|
||||
#endif
|
||||
GenericSort<uint>(keys, items, adjustedIndex, length);
|
||||
return;
|
||||
case CorElementType.ELEMENT_TYPE_I8:
|
||||
#if TARGET_64BIT
|
||||
case CorElementType.ELEMENT_TYPE_I:
|
||||
#endif
|
||||
GenericSort<long>(keys, items, adjustedIndex, length);
|
||||
return;
|
||||
case CorElementType.ELEMENT_TYPE_U8:
|
||||
#if TARGET_64BIT
|
||||
case CorElementType.ELEMENT_TYPE_U:
|
||||
#endif
|
||||
GenericSort<ulong>(keys, items, adjustedIndex, length);
|
||||
return;
|
||||
case CorElementType.ELEMENT_TYPE_R4:
|
||||
|
@ -1691,10 +1719,6 @@ namespace System
|
|||
case CorElementType.ELEMENT_TYPE_R8:
|
||||
GenericSort<double>(keys, items, adjustedIndex, length);
|
||||
return;
|
||||
case CorElementType.ELEMENT_TYPE_I:
|
||||
case CorElementType.ELEMENT_TYPE_U:
|
||||
// IntPtr/UIntPtr does not implement IComparable
|
||||
break;
|
||||
}
|
||||
|
||||
static void GenericSort<T>(Array keys, Array? items, int adjustedIndex, int length) where T: struct
|
||||
|
@ -1898,11 +1922,11 @@ namespace System
|
|||
|
||||
try
|
||||
{
|
||||
IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length));
|
||||
IntroSort(left, length + left - 1, 2 * (BitOperations.Log2((uint)length) + 1));
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
|
||||
ThrowHelper.ThrowArgumentException_BadComparer(comparer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -1912,20 +1936,22 @@ namespace System
|
|||
|
||||
private void IntroSort(int lo, int hi, int depthLimit)
|
||||
{
|
||||
Debug.Assert(hi >= lo);
|
||||
Debug.Assert(depthLimit >= 0);
|
||||
|
||||
while (hi > lo)
|
||||
{
|
||||
int partitionSize = hi - lo + 1;
|
||||
if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
|
||||
if (partitionSize <= IntrosortSizeThreshold)
|
||||
{
|
||||
if (partitionSize == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Debug.Assert(partitionSize >= 2);
|
||||
|
||||
if (partitionSize == 2)
|
||||
{
|
||||
SwapIfGreater(lo, hi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (partitionSize == 3)
|
||||
{
|
||||
SwapIfGreater(lo, hi - 1);
|
||||
|
@ -1953,8 +1979,11 @@ namespace System
|
|||
|
||||
private int PickPivotAndPartition(int lo, int hi)
|
||||
{
|
||||
Debug.Assert(hi - lo >= IntrosortSizeThreshold);
|
||||
|
||||
// Compute median-of-three. But also partition them, since we've done the comparison.
|
||||
int mid = lo + (hi - lo) / 2;
|
||||
|
||||
// Sort lo, mid and hi appropriately, then pick mid as the pivot.
|
||||
SwapIfGreater(lo, mid);
|
||||
SwapIfGreater(lo, hi);
|
||||
|
@ -1976,7 +2005,10 @@ namespace System
|
|||
}
|
||||
|
||||
// Put pivot in the right location.
|
||||
Swap(left, hi - 1);
|
||||
if (left != hi - 1)
|
||||
{
|
||||
Swap(left, hi - 1);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
|
@ -2104,11 +2136,11 @@ namespace System
|
|||
|
||||
try
|
||||
{
|
||||
IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length));
|
||||
IntroSort(left, length + left - 1, 2 * (BitOperations.Log2((uint)length) + 1));
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
|
||||
ThrowHelper.ThrowArgumentException_BadComparer(comparer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -2118,20 +2150,22 @@ namespace System
|
|||
|
||||
private void IntroSort(int lo, int hi, int depthLimit)
|
||||
{
|
||||
Debug.Assert(hi >= lo);
|
||||
Debug.Assert(depthLimit >= 0);
|
||||
|
||||
while (hi > lo)
|
||||
{
|
||||
int partitionSize = hi - lo + 1;
|
||||
if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
|
||||
if (partitionSize <= IntrosortSizeThreshold)
|
||||
{
|
||||
if (partitionSize == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Debug.Assert(partitionSize >= 2);
|
||||
|
||||
if (partitionSize == 2)
|
||||
{
|
||||
SwapIfGreater(lo, hi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (partitionSize == 3)
|
||||
{
|
||||
SwapIfGreater(lo, hi - 1);
|
||||
|
@ -2159,6 +2193,8 @@ namespace System
|
|||
|
||||
private int PickPivotAndPartition(int lo, int hi)
|
||||
{
|
||||
Debug.Assert(hi - lo >= IntrosortSizeThreshold);
|
||||
|
||||
// Compute median-of-three. But also partition them, since we've done the comparison.
|
||||
int mid = lo + (hi - lo) / 2;
|
||||
|
||||
|
@ -2182,7 +2218,10 @@ namespace System
|
|||
}
|
||||
|
||||
// Put pivot in the right location.
|
||||
Swap(left, hi - 1);
|
||||
if (left != hi - 1)
|
||||
{
|
||||
Swap(left, hi - 1);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
using Internal.Runtime.CompilerServices;
|
||||
|
||||
|
@ -449,24 +451,52 @@ namespace System
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe long DoubleToInt64Bits(double value)
|
||||
{
|
||||
// Workaround for https://github.com/dotnet/runtime/issues/11413
|
||||
if (Sse2.X64.IsSupported)
|
||||
{
|
||||
Vector128<long> vec = Vector128.CreateScalarUnsafe(value).AsInt64();
|
||||
return Sse2.X64.ConvertToInt64(vec);
|
||||
}
|
||||
|
||||
return *((long*)&value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe double Int64BitsToDouble(long value)
|
||||
{
|
||||
// Workaround for https://github.com/dotnet/runtime/issues/11413
|
||||
if (Sse2.X64.IsSupported)
|
||||
{
|
||||
Vector128<double> vec = Vector128.CreateScalarUnsafe(value).AsDouble();
|
||||
return vec.ToScalar();
|
||||
}
|
||||
|
||||
return *((double*)&value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe int SingleToInt32Bits(float value)
|
||||
{
|
||||
// Workaround for https://github.com/dotnet/runtime/issues/11413
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
Vector128<int> vec = Vector128.CreateScalarUnsafe(value).AsInt32();
|
||||
return Sse2.ConvertToInt32(vec);
|
||||
}
|
||||
|
||||
return *((int*)&value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe float Int32BitsToSingle(int value)
|
||||
{
|
||||
// Workaround for https://github.com/dotnet/runtime/issues/11413
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
Vector128<float> vec = Vector128.CreateScalarUnsafe(value).AsSingle();
|
||||
return vec.ToScalar();
|
||||
}
|
||||
|
||||
return *((float*)&value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
**
|
||||
===========================================================*/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
|
@ -223,7 +224,7 @@ namespace System
|
|||
|
||||
// Determines whether a String represents true or false.
|
||||
//
|
||||
public static bool TryParse(string? value, out bool result)
|
||||
public static bool TryParse([NotNullWhen(true)] string? value, out bool result)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Internal.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Buffers.Text
|
||||
{
|
||||
|
@ -70,5 +73,23 @@ namespace System.Buffers.Text
|
|||
value = default;
|
||||
return TryParseThrowFormatException(out bytesConsumed);
|
||||
}
|
||||
|
||||
//
|
||||
// Enable use of ThrowHelper from TryParse() routines without introducing dozens of non-code-coveraged "value= default; bytesConsumed = 0; return false" boilerplate.
|
||||
//
|
||||
[DoesNotReturn]
|
||||
[StackTraceHidden]
|
||||
public static bool TryParseThrowFormatException<T>(ReadOnlySpan<byte> source, out T value, out int bytesConsumed) where T : struct
|
||||
{
|
||||
// The parameters to this method are ordered the same as our callers' parameters
|
||||
// allowing the JIT to avoid unnecessary register swapping or spilling.
|
||||
|
||||
Unsafe.SkipInit(out value); // bypass language initialization rules since we're about to throw
|
||||
Unsafe.SkipInit(out bytesConsumed);
|
||||
ThrowHelper.ThrowFormatException_BadFormatSpecifier();
|
||||
|
||||
Debug.Fail("Control should never reach this point.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace System.Buffers.Text
|
|||
public static bool TryParse(ReadOnlySpan<byte> source, out bool value, out int bytesConsumed, char standardFormat = default)
|
||||
{
|
||||
if (!(standardFormat == default(char) || standardFormat == 'G' || standardFormat == 'l'))
|
||||
return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed);
|
||||
ThrowHelper.ThrowFormatException_BadFormatSpecifier();
|
||||
|
||||
if (source.Length >= 4)
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ namespace System.Buffers.Text
|
|||
return true;
|
||||
}
|
||||
|
||||
if (source.Length >= 5)
|
||||
if (4 < (uint)source.Length)
|
||||
{
|
||||
if (dw == 0x534c4146 /* 'SLAF' */ && (source[4] & ~0x20) == 'E')
|
||||
{
|
||||
|
|
|
@ -29,19 +29,25 @@ namespace System.Buffers.Text
|
|||
/// </exceptions>
|
||||
public static bool TryParse(ReadOnlySpan<byte> source, out Guid value, out int bytesConsumed, char standardFormat = default)
|
||||
{
|
||||
FastPath:
|
||||
if (standardFormat == default)
|
||||
{
|
||||
return TryParseGuidCore(source, out value, out bytesConsumed, ends: 0);
|
||||
}
|
||||
|
||||
switch (standardFormat)
|
||||
{
|
||||
case default(char):
|
||||
case 'D':
|
||||
return TryParseGuidCore(source, false, ' ', ' ', out value, out bytesConsumed);
|
||||
standardFormat = default;
|
||||
goto FastPath;
|
||||
case 'B':
|
||||
return TryParseGuidCore(source, true, '{', '}', out value, out bytesConsumed);
|
||||
return TryParseGuidCore(source, out value, out bytesConsumed, ends: '{' | ('}' << 8));
|
||||
case 'P':
|
||||
return TryParseGuidCore(source, true, '(', ')', out value, out bytesConsumed);
|
||||
return TryParseGuidCore(source, out value, out bytesConsumed, ends: '(' | (')' << 8));
|
||||
case 'N':
|
||||
return TryParseGuidN(source, out value, out bytesConsumed);
|
||||
default:
|
||||
return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed);
|
||||
return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,9 +103,9 @@ namespace System.Buffers.Text
|
|||
}
|
||||
|
||||
// {8-4-4-4-12}, where number is the number of hex digits, and {/} are ends.
|
||||
private static bool TryParseGuidCore(ReadOnlySpan<byte> source, bool ends, char begin, char end, out Guid value, out int bytesConsumed)
|
||||
private static bool TryParseGuidCore(ReadOnlySpan<byte> source, out Guid value, out int bytesConsumed, int ends)
|
||||
{
|
||||
int expectedCodingUnits = 36 + (ends ? 2 : 0); // 32 hex digits + 4 delimiters + 2 optional ends
|
||||
int expectedCodingUnits = 36 + ((ends != 0) ? 2 : 0); // 32 hex digits + 4 delimiters + 2 optional ends
|
||||
|
||||
if (source.Length < expectedCodingUnits)
|
||||
{
|
||||
|
@ -108,9 +114,16 @@ namespace System.Buffers.Text
|
|||
return false;
|
||||
}
|
||||
|
||||
if (ends)
|
||||
// The 'ends' parameter is a 16-bit value where the byte denoting the starting
|
||||
// brace is at byte position 0 and the byte denoting the closing brace is at
|
||||
// byte position 1. If no braces are expected, has value 0.
|
||||
// Default: ends = 0
|
||||
// Braces: ends = "}{"
|
||||
// Parens: ends = ")("
|
||||
|
||||
if (ends != 0)
|
||||
{
|
||||
if (source[0] != begin)
|
||||
if (source[0] != (byte)ends)
|
||||
{
|
||||
value = default;
|
||||
bytesConsumed = 0;
|
||||
|
@ -118,6 +131,7 @@ namespace System.Buffers.Text
|
|||
}
|
||||
|
||||
source = source.Slice(1); // skip beginning
|
||||
ends >>= 8; // shift the closing brace to byte position 0
|
||||
}
|
||||
|
||||
if (!TryParseUInt32X(source, out uint i1, out int justConsumed))
|
||||
|
@ -226,7 +240,7 @@ namespace System.Buffers.Text
|
|||
return false; // 12 digits
|
||||
}
|
||||
|
||||
if (ends && source[justConsumed] != end)
|
||||
if (ends != 0 && source[justConsumed] != (byte)ends)
|
||||
{
|
||||
value = default;
|
||||
bytesConsumed = 0;
|
||||
|
|
|
@ -35,26 +35,31 @@ namespace System.Buffers.Text
|
|||
[CLSCompliant(false)]
|
||||
public static bool TryParse(ReadOnlySpan<byte> source, out sbyte value, out int bytesConsumed, char standardFormat = default)
|
||||
{
|
||||
switch (standardFormat)
|
||||
FastPath:
|
||||
if (standardFormat == default)
|
||||
{
|
||||
return TryParseSByteD(source, out value, out bytesConsumed);
|
||||
}
|
||||
|
||||
// There's small but measurable overhead when entering the switch block below.
|
||||
// We optimize for the default case by hoisting it above the switch block.
|
||||
|
||||
switch (standardFormat | 0x20) // convert to lowercase
|
||||
{
|
||||
case default(char):
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'd':
|
||||
case 'D':
|
||||
return TryParseSByteD(source, out value, out bytesConsumed);
|
||||
standardFormat = default;
|
||||
goto FastPath;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
return TryParseSByteN(source, out value, out bytesConsumed);
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
value = default;
|
||||
Unsafe.SkipInit(out value); // will be populated by TryParseByteX
|
||||
return TryParseByteX(source, out Unsafe.As<sbyte, byte>(ref value), out bytesConsumed);
|
||||
|
||||
default:
|
||||
return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed);
|
||||
return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,26 +86,31 @@ namespace System.Buffers.Text
|
|||
/// </exceptions>
|
||||
public static bool TryParse(ReadOnlySpan<byte> source, out short value, out int bytesConsumed, char standardFormat = default)
|
||||
{
|
||||
switch (standardFormat)
|
||||
FastPath:
|
||||
if (standardFormat == default)
|
||||
{
|
||||
return TryParseInt16D(source, out value, out bytesConsumed);
|
||||
}
|
||||
|
||||
// There's small but measurable overhead when entering the switch block below.
|
||||
// We optimize for the default case by hoisting it above the switch block.
|
||||
|
||||
switch (standardFormat | 0x20) // convert to lowercase
|
||||
{
|
||||
case default(char):
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'd':
|
||||
case 'D':
|
||||
return TryParseInt16D(source, out value, out bytesConsumed);
|
||||
standardFormat = default;
|
||||
goto FastPath;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
return TryParseInt16N(source, out value, out bytesConsumed);
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
value = default;
|
||||
Unsafe.SkipInit(out value); // will be populated by TryParseUInt16X
|
||||
return TryParseUInt16X(source, out Unsafe.As<short, ushort>(ref value), out bytesConsumed);
|
||||
|
||||
default:
|
||||
return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed);
|
||||
return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,26 +137,31 @@ namespace System.Buffers.Text
|
|||
/// </exceptions>
|
||||
public static bool TryParse(ReadOnlySpan<byte> source, out int value, out int bytesConsumed, char standardFormat = default)
|
||||
{
|
||||
switch (standardFormat)
|
||||
FastPath:
|
||||
if (standardFormat == default)
|
||||
{
|
||||
return TryParseInt32D(source, out value, out bytesConsumed);
|
||||
}
|
||||
|
||||
// There's small but measurable overhead when entering the switch block below.
|
||||
// We optimize for the default case by hoisting it above the switch block.
|
||||
|
||||
switch (standardFormat | 0x20) // convert to lowercase
|
||||
{
|
||||
case default(char):
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'd':
|
||||
case 'D':
|
||||
return TryParseInt32D(source, out value, out bytesConsumed);
|
||||
standardFormat = default;
|
||||
goto FastPath;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
return TryParseInt32N(source, out value, out bytesConsumed);
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
value = default;
|
||||
Unsafe.SkipInit(out value); // will be populated by TryParseUInt32X
|
||||
return TryParseUInt32X(source, out Unsafe.As<int, uint>(ref value), out bytesConsumed);
|
||||
|
||||
default:
|
||||
return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed);
|
||||
return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,26 +188,31 @@ namespace System.Buffers.Text
|
|||
/// </exceptions>
|
||||
public static bool TryParse(ReadOnlySpan<byte> source, out long value, out int bytesConsumed, char standardFormat = default)
|
||||
{
|
||||
switch (standardFormat)
|
||||
FastPath:
|
||||
if (standardFormat == default)
|
||||
{
|
||||
return TryParseInt64D(source, out value, out bytesConsumed);
|
||||
}
|
||||
|
||||
// There's small but measurable overhead when entering the switch block below.
|
||||
// We optimize for the default case by hoisting it above the switch block.
|
||||
|
||||
switch (standardFormat | 0x20) // convert to lowercase
|
||||
{
|
||||
case default(char):
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'd':
|
||||
case 'D':
|
||||
return TryParseInt64D(source, out value, out bytesConsumed);
|
||||
standardFormat = default;
|
||||
goto FastPath;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
return TryParseInt64N(source, out value, out bytesConsumed);
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
value = default;
|
||||
Unsafe.SkipInit(out value); // will be populated by TryParseUInt64X
|
||||
return TryParseUInt64X(source, out Unsafe.As<long, ulong>(ref value), out bytesConsumed);
|
||||
|
||||
default:
|
||||
return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed);
|
||||
return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,25 +29,30 @@ namespace System.Buffers.Text
|
|||
/// </exceptions>
|
||||
public static bool TryParse(ReadOnlySpan<byte> source, out byte value, out int bytesConsumed, char standardFormat = default)
|
||||
{
|
||||
switch (standardFormat)
|
||||
FastPath:
|
||||
if (standardFormat == default)
|
||||
{
|
||||
return TryParseByteD(source, out value, out bytesConsumed);
|
||||
}
|
||||
|
||||
// There's small but measurable overhead when entering the switch block below.
|
||||
// We optimize for the default case by hoisting it above the switch block.
|
||||
|
||||
switch (standardFormat | 0x20) // convert to lowercase
|
||||
{
|
||||
case default(char):
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'd':
|
||||
case 'D':
|
||||
return TryParseByteD(source, out value, out bytesConsumed);
|
||||
standardFormat = default;
|
||||
goto FastPath;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
return TryParseByteN(source, out value, out bytesConsumed);
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
return TryParseByteX(source, out value, out bytesConsumed);
|
||||
|
||||
default:
|
||||
return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed);
|
||||
return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,25 +80,30 @@ namespace System.Buffers.Text
|
|||
[CLSCompliant(false)]
|
||||
public static bool TryParse(ReadOnlySpan<byte> source, out ushort value, out int bytesConsumed, char standardFormat = default)
|
||||
{
|
||||
switch (standardFormat)
|
||||
FastPath:
|
||||
if (standardFormat == default)
|
||||
{
|
||||
return TryParseUInt16D(source, out value, out bytesConsumed);
|
||||
}
|
||||
|
||||
// There's small but measurable overhead when entering the switch block below.
|
||||
// We optimize for the default case by hoisting it above the switch block.
|
||||
|
||||
switch (standardFormat | 0x20) // convert to lowercase
|
||||
{
|
||||
case default(char):
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'd':
|
||||
case 'D':
|
||||
return TryParseUInt16D(source, out value, out bytesConsumed);
|
||||
standardFormat = default;
|
||||
goto FastPath;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
return TryParseUInt16N(source, out value, out bytesConsumed);
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
return TryParseUInt16X(source, out value, out bytesConsumed);
|
||||
|
||||
default:
|
||||
return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed);
|
||||
return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,25 +131,30 @@ namespace System.Buffers.Text
|
|||
[CLSCompliant(false)]
|
||||
public static bool TryParse(ReadOnlySpan<byte> source, out uint value, out int bytesConsumed, char standardFormat = default)
|
||||
{
|
||||
switch (standardFormat)
|
||||
FastPath:
|
||||
if (standardFormat == default)
|
||||
{
|
||||
return TryParseUInt32D(source, out value, out bytesConsumed);
|
||||
}
|
||||
|
||||
// There's small but measurable overhead when entering the switch block below.
|
||||
// We optimize for the default case by hoisting it above the switch block.
|
||||
|
||||
switch (standardFormat | 0x20) // convert to lowercase
|
||||
{
|
||||
case default(char):
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'd':
|
||||
case 'D':
|
||||
return TryParseUInt32D(source, out value, out bytesConsumed);
|
||||
standardFormat = default;
|
||||
goto FastPath;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
return TryParseUInt32N(source, out value, out bytesConsumed);
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
return TryParseUInt32X(source, out value, out bytesConsumed);
|
||||
|
||||
default:
|
||||
return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed);
|
||||
return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,25 +182,30 @@ namespace System.Buffers.Text
|
|||
[CLSCompliant(false)]
|
||||
public static bool TryParse(ReadOnlySpan<byte> source, out ulong value, out int bytesConsumed, char standardFormat = default)
|
||||
{
|
||||
switch (standardFormat)
|
||||
FastPath:
|
||||
if (standardFormat == default)
|
||||
{
|
||||
return TryParseUInt64D(source, out value, out bytesConsumed);
|
||||
}
|
||||
|
||||
// There's small but measurable overhead when entering the switch block below.
|
||||
// We optimize for the default case by hoisting it above the switch block.
|
||||
|
||||
switch (standardFormat | 0x20) // convert to lowercase
|
||||
{
|
||||
case default(char):
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'd':
|
||||
case 'D':
|
||||
return TryParseUInt64D(source, out value, out bytesConsumed);
|
||||
standardFormat = default;
|
||||
goto FastPath;
|
||||
|
||||
case 'n':
|
||||
case 'N':
|
||||
return TryParseUInt64N(source, out value, out bytesConsumed);
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
return TryParseUInt64X(source, out value, out bytesConsumed);
|
||||
|
||||
default:
|
||||
return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed);
|
||||
return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -117,7 +118,7 @@ namespace System
|
|||
return (byte)i;
|
||||
}
|
||||
|
||||
public static bool TryParse(string? s, out byte result)
|
||||
public static bool TryParse([NotNullWhen(true)] string? s, out byte result)
|
||||
{
|
||||
if (s == null)
|
||||
{
|
||||
|
@ -133,7 +134,7 @@ namespace System
|
|||
return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
|
||||
}
|
||||
|
||||
public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out byte result)
|
||||
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out byte result)
|
||||
{
|
||||
NumberFormatInfo.ValidateParseStyleInteger(style);
|
||||
|
||||
|
@ -166,7 +167,7 @@ namespace System
|
|||
|
||||
public override string ToString()
|
||||
{
|
||||
return Number.UInt32ToDecStr(m_value, -1);
|
||||
return Number.UInt32ToDecStr(m_value);
|
||||
}
|
||||
|
||||
public string ToString(string? format)
|
||||
|
@ -176,7 +177,7 @@ namespace System
|
|||
|
||||
public string ToString(IFormatProvider? provider)
|
||||
{
|
||||
return Number.FormatUInt32(m_value, null, provider);
|
||||
return Number.UInt32ToDecStr(m_value);
|
||||
}
|
||||
|
||||
public string ToString(string? format, IFormatProvider? provider)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
===========================================================*/
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
@ -182,7 +183,7 @@ namespace System
|
|||
return s[0];
|
||||
}
|
||||
|
||||
public static bool TryParse(string? s, out char result)
|
||||
public static bool TryParse([NotNullWhen(true)] string? s, out char result)
|
||||
{
|
||||
result = '\0';
|
||||
if (s == null)
|
||||
|
@ -353,10 +354,7 @@ namespace System
|
|||
}
|
||||
|
||||
// Converts a character to upper-case for invariant culture.
|
||||
public static char ToUpperInvariant(char c)
|
||||
{
|
||||
return TextInfo.Invariant.ToUpper(c);
|
||||
}
|
||||
public static char ToUpperInvariant(char c) => TextInfo.ToUpperInvariant(c);
|
||||
|
||||
/*===================================ToLower====================================
|
||||
**
|
||||
|
@ -382,10 +380,7 @@ namespace System
|
|||
}
|
||||
|
||||
// Converts a character to lower-case for invariant culture.
|
||||
public static char ToLowerInvariant(char c)
|
||||
{
|
||||
return TextInfo.Invariant.ToLower(c);
|
||||
}
|
||||
public static char ToLowerInvariant(char c) => TextInfo.ToLowerInvariant(c);
|
||||
|
||||
//
|
||||
// IConvertible implementation
|
||||
|
|
|
@ -222,9 +222,7 @@ namespace System.Collections.Concurrent
|
|||
public T[] ToArray()
|
||||
{
|
||||
// Snap the current contents for enumeration.
|
||||
ConcurrentQueueSegment<T> head, tail;
|
||||
int headHead, tailTail;
|
||||
SnapForObservation(out head, out headHead, out tail, out tailTail);
|
||||
SnapForObservation(out ConcurrentQueueSegment<T> head, out int headHead, out ConcurrentQueueSegment<T> tail, out int tailTail);
|
||||
|
||||
// Count the number of items in that snapped set, and use it to allocate an
|
||||
// array of the right size.
|
||||
|
@ -450,9 +448,7 @@ namespace System.Collections.Concurrent
|
|||
}
|
||||
|
||||
// Snap for enumeration
|
||||
ConcurrentQueueSegment<T> head, tail;
|
||||
int headHead, tailTail;
|
||||
SnapForObservation(out head, out headHead, out tail, out tailTail);
|
||||
SnapForObservation(out ConcurrentQueueSegment<T> head, out int headHead, out ConcurrentQueueSegment<T> tail, out int tailTail);
|
||||
|
||||
// Get the number of items to be enumerated
|
||||
long count = GetCount(head, headHead, tail, tailTail);
|
||||
|
@ -484,9 +480,7 @@ namespace System.Collections.Concurrent
|
|||
/// </remarks>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
ConcurrentQueueSegment<T> head, tail;
|
||||
int headHead, tailTail;
|
||||
SnapForObservation(out head, out headHead, out tail, out tailTail);
|
||||
SnapForObservation(out ConcurrentQueueSegment<T> head, out int headHead, out ConcurrentQueueSegment<T> tail, out int tailTail);
|
||||
return Enumerate(head, headHead, tail, tailTail);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,50 +2,23 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
/*============================================================
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** Purpose: class to sort arrays
|
||||
**
|
||||
**
|
||||
===========================================================*/
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Internal.Runtime.CompilerServices;
|
||||
|
||||
#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
|
||||
#if TARGET_64BIT
|
||||
using nint = System.Int64;
|
||||
#else
|
||||
using nint = System.Int32;
|
||||
#endif
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
#region ArraySortHelper for single arrays
|
||||
|
||||
internal static class IntrospectiveSortUtilities
|
||||
{
|
||||
// This is the threshold where Introspective sort switches to Insertion sort.
|
||||
// Empirically, 16 seems to speed up most cases without slowing down others, at least for integers.
|
||||
// Large value types may benefit from a smaller number.
|
||||
internal const int IntrosortSizeThreshold = 16;
|
||||
|
||||
internal static int FloorLog2PlusOne(int n)
|
||||
{
|
||||
int result = 0;
|
||||
while (n >= 1)
|
||||
{
|
||||
result++;
|
||||
n /= 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
internal static void ThrowOrIgnoreBadComparer(object? comparer)
|
||||
{
|
||||
throw new ArgumentException(SR.Format(SR.Arg_BogusIComparer, comparer));
|
||||
}
|
||||
}
|
||||
|
||||
internal partial class ArraySortHelper<T>
|
||||
{
|
||||
#region IArraySortHelper<T> Members
|
||||
|
@ -61,11 +34,11 @@ namespace System.Collections.Generic
|
|||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
|
||||
ThrowHelper.ThrowArgumentException_BadComparer(comparer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
|
||||
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +51,8 @@ namespace System.Collections.Generic
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
|
||||
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,11 +69,11 @@ namespace System.Collections.Generic
|
|||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
|
||||
ThrowHelper.ThrowArgumentException_BadComparer(comparer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
|
||||
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,26 +105,24 @@ namespace System.Collections.Generic
|
|||
|
||||
private static void SwapIfGreater(Span<T> keys, Comparison<T> comparer, int i, int j)
|
||||
{
|
||||
if (i != j)
|
||||
Debug.Assert(i != j);
|
||||
|
||||
if (comparer(keys[i], keys[j]) > 0)
|
||||
{
|
||||
if (comparer(keys[i], keys[j]) > 0)
|
||||
{
|
||||
T key = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = key;
|
||||
}
|
||||
T key = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = key;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Swap(Span<T> a, int i, int j)
|
||||
{
|
||||
if (i != j)
|
||||
{
|
||||
T t = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = t;
|
||||
}
|
||||
Debug.Assert(i != j);
|
||||
|
||||
T t = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = t;
|
||||
}
|
||||
|
||||
internal static void IntrospectiveSort(Span<T> keys, Comparison<T> comparer)
|
||||
|
@ -159,53 +131,51 @@ namespace System.Collections.Generic
|
|||
|
||||
if (keys.Length > 1)
|
||||
{
|
||||
IntroSort(keys, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length), comparer);
|
||||
IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1), comparer);
|
||||
}
|
||||
}
|
||||
|
||||
private static void IntroSort(Span<T> keys, int depthLimit, Comparison<T> comparer)
|
||||
{
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
Debug.Assert(depthLimit >= 0);
|
||||
Debug.Assert(comparer != null);
|
||||
|
||||
while (hi > lo)
|
||||
int hi = keys.Length - 1;
|
||||
while (hi > 0)
|
||||
{
|
||||
int partitionSize = hi - lo + 1;
|
||||
if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
|
||||
int partitionSize = hi + 1;
|
||||
|
||||
if (partitionSize <= Array.IntrosortSizeThreshold)
|
||||
{
|
||||
if (partitionSize == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Debug.Assert(partitionSize >= 2);
|
||||
|
||||
if (partitionSize == 2)
|
||||
{
|
||||
SwapIfGreater(keys, comparer, lo, hi);
|
||||
SwapIfGreater(keys, comparer, 0, hi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (partitionSize == 3)
|
||||
{
|
||||
SwapIfGreater(keys, comparer, lo, hi - 1);
|
||||
SwapIfGreater(keys, comparer, lo, hi);
|
||||
SwapIfGreater(keys, comparer, 0, hi - 1);
|
||||
SwapIfGreater(keys, comparer, 0, hi);
|
||||
SwapIfGreater(keys, comparer, hi - 1, hi);
|
||||
return;
|
||||
}
|
||||
|
||||
InsertionSort(keys[lo..(hi+1)], comparer);
|
||||
InsertionSort(keys.Slice(0, hi+1), comparer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (depthLimit == 0)
|
||||
{
|
||||
HeapSort(keys[lo..(hi+1)], comparer);
|
||||
HeapSort(keys.Slice(0, hi+1), comparer);
|
||||
return;
|
||||
}
|
||||
depthLimit--;
|
||||
|
||||
int p = PickPivotAndPartition(keys[lo..(hi+1)], comparer);
|
||||
int p = PickPivotAndPartition(keys.Slice(0, hi+1), comparer);
|
||||
|
||||
// Note we've already partitioned around the pivot and do not have to move the pivot again.
|
||||
IntroSort(keys[(p+1)..(hi+1)], depthLimit, comparer);
|
||||
|
@ -215,23 +185,22 @@ namespace System.Collections.Generic
|
|||
|
||||
private static int PickPivotAndPartition(Span<T> keys, Comparison<T> comparer)
|
||||
{
|
||||
Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold);
|
||||
Debug.Assert(comparer != null);
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
|
||||
// Compute median-of-three. But also partition them, since we've done the comparison.
|
||||
int middle = lo + ((hi - lo) / 2);
|
||||
int middle = hi >> 1;
|
||||
|
||||
// Sort lo, mid and hi appropriately, then pick mid as the pivot.
|
||||
SwapIfGreater(keys, comparer, lo, middle); // swap the low with the mid point
|
||||
SwapIfGreater(keys, comparer, lo, hi); // swap the low with the high
|
||||
SwapIfGreater(keys, comparer, 0, middle); // swap the low with the mid point
|
||||
SwapIfGreater(keys, comparer, 0, hi); // swap the low with the high
|
||||
SwapIfGreater(keys, comparer, middle, hi); // swap the middle with the high
|
||||
|
||||
T pivot = keys[middle];
|
||||
Swap(keys, middle, hi - 1);
|
||||
int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
|
||||
int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
|
||||
|
||||
while (left < right)
|
||||
{
|
||||
|
@ -245,7 +214,10 @@ namespace System.Collections.Generic
|
|||
}
|
||||
|
||||
// Put pivot in the right location.
|
||||
Swap(keys, left, hi - 1);
|
||||
if (left != hi - 1)
|
||||
{
|
||||
Swap(keys, left, hi - 1);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
|
@ -254,20 +226,16 @@ namespace System.Collections.Generic
|
|||
Debug.Assert(comparer != null);
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
|
||||
int n = hi - lo + 1;
|
||||
|
||||
for (int i = n / 2; i >= 1; i--)
|
||||
int n = keys.Length;
|
||||
for (int i = n >> 1; i >= 1; i--)
|
||||
{
|
||||
DownHeap(keys, i, n, lo, comparer);
|
||||
DownHeap(keys, i, n, 0, comparer);
|
||||
}
|
||||
|
||||
for (int i = n; i > 1; i--)
|
||||
{
|
||||
Swap(keys, lo, lo + i - 1);
|
||||
DownHeap(keys, 1, i - 1, lo, comparer);
|
||||
Swap(keys, 0, i - 1);
|
||||
DownHeap(keys, 1, i - 1, 0, comparer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,7 +246,7 @@ namespace System.Collections.Generic
|
|||
Debug.Assert(lo < keys.Length);
|
||||
|
||||
T d = keys[lo + i - 1];
|
||||
while (i <= n / 2)
|
||||
while (i <= n >> 1)
|
||||
{
|
||||
int child = 2 * i;
|
||||
if (child < n && comparer(keys[lo + child - 1], keys[lo + child]) < 0)
|
||||
|
@ -327,7 +295,10 @@ namespace System.Collections.Generic
|
|||
{
|
||||
if (comparer == null || comparer == Comparer<T>.Default)
|
||||
{
|
||||
IntrospectiveSort(keys);
|
||||
if (keys.Length > 1)
|
||||
{
|
||||
IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -336,11 +307,11 @@ namespace System.Collections.Generic
|
|||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
|
||||
ThrowHelper.ThrowArgumentException_BadComparer(comparer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
|
||||
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -362,7 +333,8 @@ namespace System.Collections.Generic
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
|
||||
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -406,147 +378,140 @@ namespace System.Collections.Generic
|
|||
return ~lo;
|
||||
}
|
||||
|
||||
private static void SwapIfGreater(Span<T> keys, int i, int j)
|
||||
{
|
||||
Debug.Assert(0 <= i && i < keys.Length);
|
||||
Debug.Assert(0 <= j && j < keys.Length);
|
||||
|
||||
if (i != j)
|
||||
{
|
||||
if (keys[i] != null && keys[i].CompareTo(keys[j]) > 0)
|
||||
{
|
||||
T key = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Swaps the values in the two references if the first is greater than the second.</summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Swap(Span<T> a, int i, int j)
|
||||
private static void SwapIfGreater(ref T i, ref T j)
|
||||
{
|
||||
if (i != j)
|
||||
if (i != null && i.CompareTo(j) > 0)
|
||||
{
|
||||
T t = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = t;
|
||||
Swap(ref i, ref j);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void IntrospectiveSort(Span<T> keys)
|
||||
/// <summary>Swaps the values in the two references, regardless of whether the two references are the same.</summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Swap(ref T i, ref T j)
|
||||
{
|
||||
if (keys.Length > 1)
|
||||
{
|
||||
IntroSort(keys, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length));
|
||||
}
|
||||
Debug.Assert(!Unsafe.AreSame(ref i, ref j));
|
||||
|
||||
T t = i;
|
||||
i = j;
|
||||
j = t;
|
||||
}
|
||||
|
||||
private static void IntroSort(Span<T> keys, int depthLimit)
|
||||
{
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
Debug.Assert(depthLimit >= 0);
|
||||
|
||||
while (hi > lo)
|
||||
int hi = keys.Length - 1;
|
||||
while (hi > 0)
|
||||
{
|
||||
int partitionSize = hi - lo + 1;
|
||||
if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
|
||||
int partitionSize = hi + 1;
|
||||
|
||||
if (partitionSize <= Array.IntrosortSizeThreshold)
|
||||
{
|
||||
if (partitionSize == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Debug.Assert(partitionSize >= 2);
|
||||
|
||||
if (partitionSize == 2)
|
||||
{
|
||||
SwapIfGreater(keys, lo, hi);
|
||||
return;
|
||||
}
|
||||
if (partitionSize == 3)
|
||||
{
|
||||
SwapIfGreater(keys, lo, hi - 1);
|
||||
SwapIfGreater(keys, lo, hi);
|
||||
SwapIfGreater(keys, hi - 1, hi);
|
||||
SwapIfGreater(ref keys[0], ref keys[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
InsertionSort(keys[lo..(hi+1)]);
|
||||
if (partitionSize == 3)
|
||||
{
|
||||
ref T hiRef = ref keys[2];
|
||||
ref T him1Ref = ref keys[1];
|
||||
ref T loRef = ref keys[0];
|
||||
|
||||
SwapIfGreater(ref loRef, ref him1Ref);
|
||||
SwapIfGreater(ref loRef, ref hiRef);
|
||||
SwapIfGreater(ref him1Ref, ref hiRef);
|
||||
return;
|
||||
}
|
||||
|
||||
InsertionSort(keys.Slice(0, partitionSize));
|
||||
return;
|
||||
}
|
||||
|
||||
if (depthLimit == 0)
|
||||
{
|
||||
HeapSort(keys[lo..(hi+1)]);
|
||||
HeapSort(keys.Slice(0, partitionSize));
|
||||
return;
|
||||
}
|
||||
depthLimit--;
|
||||
|
||||
int p = PickPivotAndPartition(keys[lo..(hi+1)]);
|
||||
int p = PickPivotAndPartition(keys.Slice(0, partitionSize));
|
||||
|
||||
// Note we've already partitioned around the pivot and do not have to move the pivot again.
|
||||
IntroSort(keys[(p+1)..(hi+1)], depthLimit);
|
||||
IntroSort(keys[(p+1)..partitionSize], depthLimit);
|
||||
hi = p - 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int PickPivotAndPartition(Span<T> keys)
|
||||
{
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold);
|
||||
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
// Use median-of-three to select a pivot. Grab a reference to the 0th, Length-1th, and Length/2th elements, and sort them.
|
||||
ref T zeroRef = ref MemoryMarshal.GetReference(keys);
|
||||
ref T lastRef = ref Unsafe.Add(ref zeroRef, keys.Length - 1);
|
||||
ref T middleRef = ref Unsafe.Add(ref zeroRef, (keys.Length - 1) >> 1);
|
||||
SwapIfGreater(ref zeroRef, ref middleRef);
|
||||
SwapIfGreater(ref zeroRef, ref lastRef);
|
||||
SwapIfGreater(ref middleRef, ref lastRef);
|
||||
|
||||
// Compute median-of-three. But also partition them, since we've done the comparison.
|
||||
int middle = lo + ((hi - lo) / 2);
|
||||
// Select the middle value as the pivot, and move it to be just before the last element.
|
||||
ref T nextToLastRef = ref Unsafe.Add(ref zeroRef, keys.Length - 2);
|
||||
T pivot = middleRef;
|
||||
Swap(ref middleRef, ref nextToLastRef);
|
||||
|
||||
// Sort lo, mid and hi appropriately, then pick mid as the pivot.
|
||||
SwapIfGreater(keys, lo, middle); // swap the low with the mid point
|
||||
SwapIfGreater(keys, lo, hi); // swap the low with the high
|
||||
SwapIfGreater(keys, middle, hi); // swap the middle with the high
|
||||
|
||||
T pivot = keys[middle];
|
||||
Swap(keys, middle, hi - 1);
|
||||
int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
|
||||
|
||||
while (left < right)
|
||||
// Walk the left and right pointers, swapping elements as necessary, until they cross.
|
||||
ref T leftRef = ref zeroRef, rightRef = ref nextToLastRef;
|
||||
while (Unsafe.IsAddressLessThan(ref leftRef, ref rightRef))
|
||||
{
|
||||
if (pivot == null)
|
||||
{
|
||||
while (left < (hi - 1) && keys[++left] == null) ;
|
||||
while (right > lo && keys[--right] != null) ;
|
||||
while (Unsafe.IsAddressLessThan(ref leftRef, ref nextToLastRef) && (leftRef = ref Unsafe.Add(ref leftRef, 1)) == null) ;
|
||||
while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && (rightRef = ref Unsafe.Add(ref rightRef, -1)) == null) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (pivot.CompareTo(keys[++left]) > 0) ;
|
||||
while (pivot.CompareTo(keys[--right]) < 0) ;
|
||||
while (Unsafe.IsAddressLessThan(ref leftRef, ref nextToLastRef) && pivot.CompareTo(leftRef = ref Unsafe.Add(ref leftRef, 1)) > 0) ;
|
||||
while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && pivot.CompareTo(rightRef = ref Unsafe.Add(ref rightRef, -1)) < 0) ;
|
||||
}
|
||||
|
||||
if (left >= right)
|
||||
if (!Unsafe.IsAddressLessThan(ref leftRef, ref rightRef))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Swap(keys, left, right);
|
||||
Swap(ref leftRef, ref rightRef);
|
||||
}
|
||||
|
||||
// Put pivot in the right location.
|
||||
Swap(keys, left, hi - 1);
|
||||
return left;
|
||||
// Put the pivot in the correct location.
|
||||
if (!Unsafe.AreSame(ref leftRef, ref nextToLastRef))
|
||||
{
|
||||
Swap(ref leftRef, ref nextToLastRef);
|
||||
}
|
||||
return (int)((nint)Unsafe.ByteOffset(ref zeroRef, ref leftRef) / Unsafe.SizeOf<T>());
|
||||
}
|
||||
|
||||
private static void HeapSort(Span<T> keys)
|
||||
{
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
|
||||
int n = hi - lo + 1;
|
||||
for (int i = n / 2; i >= 1; i = i - 1)
|
||||
int n = keys.Length;
|
||||
for (int i = n >> 1; i >= 1; i--)
|
||||
{
|
||||
DownHeap(keys, i, n, lo);
|
||||
DownHeap(keys, i, n, 0);
|
||||
}
|
||||
|
||||
for (int i = n; i > 1; i--)
|
||||
{
|
||||
Swap(keys, lo, lo + i - 1);
|
||||
DownHeap(keys, 1, i - 1, lo);
|
||||
Swap(ref keys[0], ref keys[i - 1]);
|
||||
DownHeap(keys, 1, i - 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -556,7 +521,7 @@ namespace System.Collections.Generic
|
|||
Debug.Assert(lo < keys.Length);
|
||||
|
||||
T d = keys[lo + i - 1];
|
||||
while (i <= n / 2)
|
||||
while (i <= n >> 1)
|
||||
{
|
||||
int child = 2 * i;
|
||||
if (child < n && (keys[lo + child - 1] == null || keys[lo + child - 1].CompareTo(keys[lo + child]) < 0))
|
||||
|
@ -578,16 +543,16 @@ namespace System.Collections.Generic
|
|||
{
|
||||
for (int i = 0; i < keys.Length - 1; i++)
|
||||
{
|
||||
T t = keys[i + 1];
|
||||
T t = Unsafe.Add(ref MemoryMarshal.GetReference(keys), i + 1);
|
||||
|
||||
int j = i;
|
||||
while (j >= 0 && (t == null || t.CompareTo(keys[j]) < 0))
|
||||
while (j >= 0 && (t == null || t.CompareTo(Unsafe.Add(ref MemoryMarshal.GetReference(keys), j)) < 0))
|
||||
{
|
||||
keys[j + 1] = keys[j];
|
||||
Unsafe.Add(ref MemoryMarshal.GetReference(keys), j + 1) = Unsafe.Add(ref MemoryMarshal.GetReference(keys), j);
|
||||
j--;
|
||||
}
|
||||
|
||||
keys[j + 1] = t;
|
||||
Unsafe.Add(ref MemoryMarshal.GetReference(keys), j + 1) = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -608,11 +573,11 @@ namespace System.Collections.Generic
|
|||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
|
||||
ThrowHelper.ThrowArgumentException_BadComparer(comparer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
|
||||
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -621,35 +586,32 @@ namespace System.Collections.Generic
|
|||
Debug.Assert(comparer != null);
|
||||
Debug.Assert(0 <= i && i < keys.Length && i < values.Length);
|
||||
Debug.Assert(0 <= j && j < keys.Length && j < values.Length);
|
||||
Debug.Assert(i != j);
|
||||
|
||||
if (i != j)
|
||||
if (comparer.Compare(keys[i], keys[j]) > 0)
|
||||
{
|
||||
if (comparer.Compare(keys[i], keys[j]) > 0)
|
||||
{
|
||||
TKey key = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = key;
|
||||
TKey key = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = key;
|
||||
|
||||
TValue value = values[i];
|
||||
values[i] = values[j];
|
||||
values[j] = value;
|
||||
}
|
||||
TValue value = values[i];
|
||||
values[i] = values[j];
|
||||
values[j] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Swap(Span<TKey> keys, Span<TValue> values, int i, int j)
|
||||
{
|
||||
if (i != j)
|
||||
{
|
||||
TKey k = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = k;
|
||||
Debug.Assert(i != j);
|
||||
|
||||
TValue v = values[i];
|
||||
values[i] = values[j];
|
||||
values[j] = v;
|
||||
}
|
||||
TKey k = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = k;
|
||||
|
||||
TValue v = values[i];
|
||||
values[i] = values[j];
|
||||
values[j] = v;
|
||||
}
|
||||
|
||||
internal static void IntrospectiveSort(Span<TKey> keys, Span<TValue> values, IComparer<TKey> comparer)
|
||||
|
@ -659,79 +621,77 @@ namespace System.Collections.Generic
|
|||
|
||||
if (keys.Length > 1)
|
||||
{
|
||||
IntroSort(keys, values, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length), comparer);
|
||||
IntroSort(keys, values, 2 * (BitOperations.Log2((uint)keys.Length) + 1), comparer);
|
||||
}
|
||||
}
|
||||
|
||||
private static void IntroSort(Span<TKey> keys, Span<TValue> values, int depthLimit, IComparer<TKey> comparer)
|
||||
{
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
Debug.Assert(values.Length == keys.Length);
|
||||
Debug.Assert(depthLimit >= 0);
|
||||
Debug.Assert(comparer != null);
|
||||
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
|
||||
while (hi > lo)
|
||||
while (hi > 0)
|
||||
{
|
||||
int partitionSize = hi - lo + 1;
|
||||
if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
|
||||
int partitionSize = hi + 1;
|
||||
|
||||
if (partitionSize <= Array.IntrosortSizeThreshold)
|
||||
{
|
||||
if (partitionSize == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Debug.Assert(partitionSize >= 2);
|
||||
|
||||
if (partitionSize == 2)
|
||||
{
|
||||
SwapIfGreaterWithValues(keys, values, comparer, lo, hi);
|
||||
SwapIfGreaterWithValues(keys, values, comparer, 0, hi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (partitionSize == 3)
|
||||
{
|
||||
SwapIfGreaterWithValues(keys, values, comparer, lo, hi - 1);
|
||||
SwapIfGreaterWithValues(keys, values, comparer, lo, hi);
|
||||
SwapIfGreaterWithValues(keys, values, comparer, 0, hi - 1);
|
||||
SwapIfGreaterWithValues(keys, values, comparer, 0, hi);
|
||||
SwapIfGreaterWithValues(keys, values, comparer, hi - 1, hi);
|
||||
return;
|
||||
}
|
||||
|
||||
InsertionSort(keys[lo..(hi+1)], values[lo..(hi+1)], comparer);
|
||||
InsertionSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize), comparer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (depthLimit == 0)
|
||||
{
|
||||
HeapSort(keys[lo..(hi+1)], values[lo..(hi+1)], comparer);
|
||||
HeapSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize), comparer);
|
||||
return;
|
||||
}
|
||||
depthLimit--;
|
||||
|
||||
int p = PickPivotAndPartition(keys[lo..(hi+1)], values[lo..(hi+1)], comparer);
|
||||
int p = PickPivotAndPartition(keys.Slice(0, partitionSize), values.Slice(0, partitionSize), comparer);
|
||||
|
||||
// Note we've already partitioned around the pivot and do not have to move the pivot again.
|
||||
IntroSort(keys[(p+1)..(hi+1)], values[(p+1)..(hi+1)], depthLimit, comparer);
|
||||
IntroSort(keys[(p+1)..partitionSize], values[(p+1)..partitionSize], depthLimit, comparer);
|
||||
hi = p - 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int PickPivotAndPartition(Span<TKey> keys, Span<TValue> values, IComparer<TKey> comparer)
|
||||
{
|
||||
Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold);
|
||||
Debug.Assert(comparer != null);
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
|
||||
// Compute median-of-three. But also partition them, since we've done the comparison.
|
||||
int middle = lo + ((hi - lo) / 2);
|
||||
int middle = hi >> 1;
|
||||
|
||||
// Sort lo, mid and hi appropriately, then pick mid as the pivot.
|
||||
SwapIfGreaterWithValues(keys, values, comparer, lo, middle); // swap the low with the mid point
|
||||
SwapIfGreaterWithValues(keys, values, comparer, lo, hi); // swap the low with the high
|
||||
SwapIfGreaterWithValues(keys, values, comparer, 0, middle); // swap the low with the mid point
|
||||
SwapIfGreaterWithValues(keys, values, comparer, 0, hi); // swap the low with the high
|
||||
SwapIfGreaterWithValues(keys, values, comparer, middle, hi); // swap the middle with the high
|
||||
|
||||
TKey pivot = keys[middle];
|
||||
Swap(keys, values, middle, hi - 1);
|
||||
int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
|
||||
int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
|
||||
|
||||
while (left < right)
|
||||
{
|
||||
|
@ -745,7 +705,10 @@ namespace System.Collections.Generic
|
|||
}
|
||||
|
||||
// Put pivot in the right location.
|
||||
Swap(keys, values, left, hi - 1);
|
||||
if (left != hi - 1)
|
||||
{
|
||||
Swap(keys, values, left, hi - 1);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
|
@ -754,19 +717,16 @@ namespace System.Collections.Generic
|
|||
Debug.Assert(comparer != null);
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
|
||||
int n = hi - lo + 1;
|
||||
for (int i = n / 2; i >= 1; i--)
|
||||
int n = keys.Length;
|
||||
for (int i = n >> 1; i >= 1; i--)
|
||||
{
|
||||
DownHeap(keys, values, i, n, lo, comparer);
|
||||
DownHeap(keys, values, i, n, 0, comparer);
|
||||
}
|
||||
|
||||
for (int i = n; i > 1; i--)
|
||||
{
|
||||
Swap(keys, values, lo, lo + i - 1);
|
||||
DownHeap(keys, values, 1, i - 1, lo, comparer);
|
||||
Swap(keys, values, 0, i - 1);
|
||||
DownHeap(keys, values, 1, i - 1, 0, comparer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -779,7 +739,7 @@ namespace System.Collections.Generic
|
|||
TKey d = keys[lo + i - 1];
|
||||
TValue dValue = values[lo + i - 1];
|
||||
|
||||
while (i <= n / 2)
|
||||
while (i <= n >> 1)
|
||||
{
|
||||
int child = 2 * i;
|
||||
if (child < n && comparer.Compare(keys[lo + child - 1], keys[lo + child]) < 0)
|
||||
|
@ -842,44 +802,42 @@ namespace System.Collections.Generic
|
|||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer);
|
||||
ThrowHelper.ThrowArgumentException_BadComparer(comparer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e);
|
||||
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SwapIfGreaterWithValues(Span<TKey> keys, Span<TValue> values, int i, int j)
|
||||
{
|
||||
if (i != j)
|
||||
{
|
||||
if (keys[i] != null && keys[i].CompareTo(keys[j]) > 0)
|
||||
{
|
||||
TKey key = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = key;
|
||||
Debug.Assert(i != j);
|
||||
|
||||
TValue value = values[i];
|
||||
values[i] = values[j];
|
||||
values[j] = value;
|
||||
}
|
||||
if (keys[i] != null && keys[i].CompareTo(keys[j]) > 0)
|
||||
{
|
||||
TKey key = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = key;
|
||||
|
||||
TValue value = values[i];
|
||||
values[i] = values[j];
|
||||
values[j] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Swap(Span<TKey> keys, Span<TValue> values, int i, int j)
|
||||
{
|
||||
if (i != j)
|
||||
{
|
||||
TKey k = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = k;
|
||||
Debug.Assert(i != j);
|
||||
|
||||
TValue v = values[i];
|
||||
values[i] = values[j];
|
||||
values[j] = v;
|
||||
}
|
||||
TKey k = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = k;
|
||||
|
||||
TValue v = values[i];
|
||||
values[i] = values[j];
|
||||
values[j] = v;
|
||||
}
|
||||
|
||||
internal static void IntrospectiveSort(Span<TKey> keys, Span<TValue> values)
|
||||
|
@ -888,83 +846,82 @@ namespace System.Collections.Generic
|
|||
|
||||
if (keys.Length > 1)
|
||||
{
|
||||
IntroSort(keys, values, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length));
|
||||
IntroSort(keys, values, 2 * (BitOperations.Log2((uint)keys.Length) + 1));
|
||||
}
|
||||
}
|
||||
|
||||
private static void IntroSort(Span<TKey> keys, Span<TValue> values, int depthLimit)
|
||||
{
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
Debug.Assert(values.Length == keys.Length);
|
||||
Debug.Assert(depthLimit >= 0);
|
||||
|
||||
while (hi > lo)
|
||||
int hi = keys.Length - 1;
|
||||
while (hi > 0)
|
||||
{
|
||||
int partitionSize = hi - lo + 1;
|
||||
if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold)
|
||||
int partitionSize = hi + 1;
|
||||
|
||||
if (partitionSize <= Array.IntrosortSizeThreshold)
|
||||
{
|
||||
if (partitionSize == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Debug.Assert(partitionSize >= 2);
|
||||
|
||||
if (partitionSize == 2)
|
||||
{
|
||||
SwapIfGreaterWithValues(keys, values, lo, hi);
|
||||
SwapIfGreaterWithValues(keys, values, 0, hi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (partitionSize == 3)
|
||||
{
|
||||
SwapIfGreaterWithValues(keys, values, lo, hi - 1);
|
||||
SwapIfGreaterWithValues(keys, values, lo, hi);
|
||||
SwapIfGreaterWithValues(keys, values, 0, hi - 1);
|
||||
SwapIfGreaterWithValues(keys, values, 0, hi);
|
||||
SwapIfGreaterWithValues(keys, values, hi - 1, hi);
|
||||
return;
|
||||
}
|
||||
|
||||
InsertionSort(keys[lo..(hi+1)], values[lo..(hi+1)]);
|
||||
InsertionSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize));
|
||||
return;
|
||||
}
|
||||
|
||||
if (depthLimit == 0)
|
||||
{
|
||||
HeapSort(keys[lo..(hi+1)], values[lo..(hi+1)]);
|
||||
HeapSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize));
|
||||
return;
|
||||
}
|
||||
depthLimit--;
|
||||
|
||||
int p = PickPivotAndPartition(keys[lo..(hi+1)], values[lo..(hi+1)]);
|
||||
int p = PickPivotAndPartition(keys.Slice(0, partitionSize), values.Slice(0, partitionSize));
|
||||
|
||||
// Note we've already partitioned around the pivot and do not have to move the pivot again.
|
||||
IntroSort(keys[(p+1)..(hi+1)], values[(p+1)..(hi+1)], depthLimit);
|
||||
IntroSort(keys[(p+1)..partitionSize], values[(p+1)..partitionSize], depthLimit);
|
||||
hi = p - 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int PickPivotAndPartition(Span<TKey> keys, Span<TValue> values)
|
||||
{
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold);
|
||||
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
|
||||
// Compute median-of-three. But also partition them, since we've done the comparison.
|
||||
int middle = lo + ((hi - lo) / 2);
|
||||
int middle = hi >> 1;
|
||||
|
||||
// Sort lo, mid and hi appropriately, then pick mid as the pivot.
|
||||
SwapIfGreaterWithValues(keys, values, lo, middle); // swap the low with the mid point
|
||||
SwapIfGreaterWithValues(keys, values, lo, hi); // swap the low with the high
|
||||
SwapIfGreaterWithValues(keys, values, 0, middle); // swap the low with the mid point
|
||||
SwapIfGreaterWithValues(keys, values, 0, hi); // swap the low with the high
|
||||
SwapIfGreaterWithValues(keys, values, middle, hi); // swap the middle with the high
|
||||
|
||||
TKey pivot = keys[middle];
|
||||
Swap(keys, values, middle, hi - 1);
|
||||
int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
|
||||
int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
|
||||
|
||||
while (left < right)
|
||||
{
|
||||
if (pivot == null)
|
||||
{
|
||||
while (left < (hi - 1) && keys[++left] == null) ;
|
||||
while (right > lo && keys[--right] != null) ;
|
||||
while (right > 0 && keys[--right] != null) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -979,7 +936,10 @@ namespace System.Collections.Generic
|
|||
}
|
||||
|
||||
// Put pivot in the right location.
|
||||
Swap(keys, values, left, hi - 1);
|
||||
if (left != hi - 1)
|
||||
{
|
||||
Swap(keys, values, left, hi - 1);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
|
@ -987,19 +947,16 @@ namespace System.Collections.Generic
|
|||
{
|
||||
Debug.Assert(!keys.IsEmpty);
|
||||
|
||||
int lo = 0;
|
||||
int hi = keys.Length - 1;
|
||||
|
||||
int n = hi - lo + 1;
|
||||
for (int i = n / 2; i >= 1; i--)
|
||||
int n = keys.Length;
|
||||
for (int i = n >> 1; i >= 1; i--)
|
||||
{
|
||||
DownHeap(keys, values, i, n, lo);
|
||||
DownHeap(keys, values, i, n, 0);
|
||||
}
|
||||
|
||||
for (int i = n; i > 1; i--)
|
||||
{
|
||||
Swap(keys, values, lo, lo + i - 1);
|
||||
DownHeap(keys, values, 1, i - 1, lo);
|
||||
Swap(keys, values, 0, i - 1);
|
||||
DownHeap(keys, values, 1, i - 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1011,7 +968,7 @@ namespace System.Collections.Generic
|
|||
TKey d = keys[lo + i - 1];
|
||||
TValue dValue = values[lo + i - 1];
|
||||
|
||||
while (i <= n / 2)
|
||||
while (i <= n >> 1)
|
||||
{
|
||||
int child = 2 * i;
|
||||
if (child < n && (keys[lo + child - 1] == null || keys[lo + child - 1].CompareTo(keys[lo + child]) < 0))
|
||||
|
|
|
@ -512,7 +512,6 @@ namespace System.Collections.Generic
|
|||
if (behavior == InsertionBehavior.OverwriteExisting)
|
||||
{
|
||||
entries[i].value = value;
|
||||
_version++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -555,7 +554,6 @@ namespace System.Collections.Generic
|
|||
if (behavior == InsertionBehavior.OverwriteExisting)
|
||||
{
|
||||
entries[i].value = value;
|
||||
_version++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -595,7 +593,6 @@ namespace System.Collections.Generic
|
|||
if (behavior == InsertionBehavior.OverwriteExisting)
|
||||
{
|
||||
entries[i].value = value;
|
||||
_version++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a readonly abstraction of a set.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements in the set.</typeparam>
|
||||
public interface IReadOnlySet<T> : IReadOnlyCollection<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if the set contains a specific item
|
||||
/// </summary>
|
||||
/// <param name="item">The item to check if the set contains.</param>
|
||||
/// <returns><see langword="true" /> if found; otherwise <see langword="false" />.</returns>
|
||||
bool Contains(T item);
|
||||
/// <summary>
|
||||
/// Determines whether the current set is a proper (strict) subset of a specified collection.
|
||||
/// </summary>
|
||||
/// <param name="other">The collection to compare to the current set.</param>
|
||||
/// <returns><see langword="true" /> if the current set is a proper subset of other; otherwise <see langword="false" />.</returns>
|
||||
/// <exception cref="ArgumentNullException">other is <see langword="null" />.</exception>
|
||||
bool IsProperSubsetOf(IEnumerable<T> other);
|
||||
/// <summary>
|
||||
/// Determines whether the current set is a proper (strict) superset of a specified collection.
|
||||
/// </summary>
|
||||
/// <param name="other">The collection to compare to the current set.</param>
|
||||
/// <returns><see langword="true" /> if the collection is a proper superset of other; otherwise <see langword="false" />.</returns>
|
||||
/// <exception cref="ArgumentNullException">other is <see langword="null" />.</exception>
|
||||
bool IsProperSupersetOf(IEnumerable<T> other);
|
||||
/// <summary>
|
||||
/// Determine whether the current set is a subset of a specified collection.
|
||||
/// </summary>
|
||||
/// <param name="other">The collection to compare to the current set.</param>
|
||||
/// <returns><see langword="true" /> if the current set is a subset of other; otherwise <see langword="false" />.</returns>
|
||||
/// <exception cref="ArgumentNullException">other is <see langword="null" />.</exception>
|
||||
bool IsSubsetOf(IEnumerable<T> other);
|
||||
/// <summary>
|
||||
/// Determine whether the current set is a super set of a specified collection.
|
||||
/// </summary>
|
||||
/// <param name="other">The collection to compare to the current set</param>
|
||||
/// <returns><see langword="true" /> if the current set is a subset of other; otherwise <see langword="false" />.</returns>
|
||||
/// <exception cref="ArgumentNullException">other is <see langword="null" />.</exception>
|
||||
bool IsSupersetOf(IEnumerable<T> other);
|
||||
/// <summary>
|
||||
/// Determines whether the current set overlaps with the specified collection.
|
||||
/// </summary>
|
||||
/// <param name="other">The collection to compare to the current set.</param>
|
||||
/// <returns><see langword="true" />if the current set and other share at least one common element; otherwise, <see langword="false" />.</returns>
|
||||
/// <exception cref="ArgumentNullException">other is <see langword="null" />.</exception>
|
||||
bool Overlaps(IEnumerable<T> other);
|
||||
/// <summary>
|
||||
/// Determines whether the current set and the specified collection contain the same elements.
|
||||
/// </summary>
|
||||
/// <param name="other">The collection to compare to the current set.</param>
|
||||
/// <returns><see langword="true" /> if the current set is equal to other; otherwise, <see langword="false" />.</returns>
|
||||
/// <exception cref="ArgumentNullException">other is <see langword="null" />.</exception>
|
||||
bool SetEquals(IEnumerable<T> other);
|
||||
}
|
||||
}
|
|
@ -2,8 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
@ -480,11 +480,9 @@ namespace System.Collections
|
|||
throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key);
|
||||
}
|
||||
|
||||
uint seed;
|
||||
uint incr;
|
||||
// Take a snapshot of buckets, in case another thread resizes table
|
||||
bucket[] lbuckets = _buckets;
|
||||
uint hashcode = InitHash(key, lbuckets.Length, out seed, out incr);
|
||||
uint hashcode = InitHash(key, lbuckets.Length, out uint seed, out uint incr);
|
||||
int ntry = 0;
|
||||
|
||||
bucket b;
|
||||
|
@ -639,12 +637,10 @@ namespace System.Collections
|
|||
throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key);
|
||||
}
|
||||
|
||||
uint seed;
|
||||
uint incr;
|
||||
|
||||
// Take a snapshot of buckets, in case another thread does a resize
|
||||
bucket[] lbuckets = _buckets;
|
||||
uint hashcode = InitHash(key, lbuckets.Length, out seed, out incr);
|
||||
uint hashcode = InitHash(key, lbuckets.Length, out uint seed, out uint incr);
|
||||
int ntry = 0;
|
||||
|
||||
bucket b;
|
||||
|
@ -858,11 +854,9 @@ namespace System.Collections
|
|||
rehash();
|
||||
}
|
||||
|
||||
uint seed;
|
||||
uint incr;
|
||||
// Assume we only have one thread writing concurrently. Modify
|
||||
// buckets to contain new data, as long as we insert in the right order.
|
||||
uint hashcode = InitHash(key, _buckets.Length, out seed, out incr);
|
||||
uint hashcode = InitHash(key, _buckets.Length, out uint seed, out uint incr);
|
||||
int ntry = 0;
|
||||
int emptySlotNumber = -1; // We use the empty slot number to cache the first empty slot. We chose to reuse slots
|
||||
// create by remove that have the collision bit set over using up new slots.
|
||||
|
@ -994,10 +988,8 @@ namespace System.Collections
|
|||
|
||||
Debug.Assert(!_isWriterInProgress, "Race condition detected in usages of Hashtable - multiple threads appear to be writing to a Hashtable instance simultaneously! Don't do that - use Hashtable.Synchronized.");
|
||||
|
||||
uint seed;
|
||||
uint incr;
|
||||
// Assuming only one concurrent writer, write directly into buckets.
|
||||
uint hashcode = InitHash(key, _buckets.Length, out seed, out incr);
|
||||
uint hashcode = InitHash(key, _buckets.Length, out uint seed, out uint incr);
|
||||
int ntry = 0;
|
||||
|
||||
bucket b;
|
||||
|
@ -1116,8 +1108,7 @@ namespace System.Collections
|
|||
return;
|
||||
}
|
||||
|
||||
SerializationInfo? siInfo;
|
||||
HashHelpers.SerializationInfoTable.TryGetValue(this, out siInfo);
|
||||
HashHelpers.SerializationInfoTable.TryGetValue(this, out SerializationInfo? siInfo);
|
||||
|
||||
if (siInfo == null)
|
||||
{
|
||||
|
|
|
@ -528,11 +528,7 @@ namespace System
|
|||
return (char)value;
|
||||
}
|
||||
|
||||
public static char ToChar(int value)
|
||||
{
|
||||
if (value < 0 || value > char.MaxValue) ThrowCharOverflowException();
|
||||
return (char)value;
|
||||
}
|
||||
public static char ToChar(int value) => ToChar((uint)value);
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static char ToChar(uint value)
|
||||
|
@ -541,11 +537,7 @@ namespace System
|
|||
return (char)value;
|
||||
}
|
||||
|
||||
public static char ToChar(long value)
|
||||
{
|
||||
if (value < 0 || value > char.MaxValue) ThrowCharOverflowException();
|
||||
return (char)value;
|
||||
}
|
||||
public static char ToChar(long value) => ToChar((ulong)value);
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static char ToChar(ulong value)
|
||||
|
@ -667,7 +659,7 @@ namespace System
|
|||
[CLSCompliant(false)]
|
||||
public static sbyte ToSByte(uint value)
|
||||
{
|
||||
if (value > sbyte.MaxValue) ThrowSByteOverflowException();
|
||||
if (value > (uint)sbyte.MaxValue) ThrowSByteOverflowException();
|
||||
return (sbyte)value;
|
||||
}
|
||||
|
||||
|
@ -708,13 +700,13 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return sbyte.Parse(value, CultureInfo.CurrentCulture);
|
||||
return sbyte.Parse(value);
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static sbyte ToSByte(string value, IFormatProvider? provider)
|
||||
{
|
||||
return sbyte.Parse(value, NumberStyles.Integer, provider);
|
||||
return sbyte.Parse(value, provider);
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
|
@ -757,13 +749,13 @@ namespace System
|
|||
[CLSCompliant(false)]
|
||||
public static byte ToByte(sbyte value)
|
||||
{
|
||||
if (value < byte.MinValue) ThrowByteOverflowException();
|
||||
if (value < 0) ThrowByteOverflowException();
|
||||
return (byte)value;
|
||||
}
|
||||
|
||||
public static byte ToByte(short value)
|
||||
{
|
||||
if (value < byte.MinValue || value > byte.MaxValue) ThrowByteOverflowException();
|
||||
if ((uint)value > byte.MaxValue) ThrowByteOverflowException();
|
||||
return (byte)value;
|
||||
}
|
||||
|
||||
|
@ -774,11 +766,7 @@ namespace System
|
|||
return (byte)value;
|
||||
}
|
||||
|
||||
public static byte ToByte(int value)
|
||||
{
|
||||
if (value < byte.MinValue || value > byte.MaxValue) ThrowByteOverflowException();
|
||||
return (byte)value;
|
||||
}
|
||||
public static byte ToByte(int value) => ToByte((uint)value);
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static byte ToByte(uint value)
|
||||
|
@ -787,11 +775,7 @@ namespace System
|
|||
return (byte)value;
|
||||
}
|
||||
|
||||
public static byte ToByte(long value)
|
||||
{
|
||||
if (value < byte.MinValue || value > byte.MaxValue) ThrowByteOverflowException();
|
||||
return (byte)value;
|
||||
}
|
||||
public static byte ToByte(long value) => ToByte((ulong)value);
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static byte ToByte(ulong value)
|
||||
|
@ -819,14 +803,14 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return byte.Parse(value, CultureInfo.CurrentCulture);
|
||||
return byte.Parse(value);
|
||||
}
|
||||
|
||||
public static byte ToByte(string? value, IFormatProvider? provider)
|
||||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return byte.Parse(value, NumberStyles.Integer, provider);
|
||||
return byte.Parse(value, provider);
|
||||
}
|
||||
|
||||
public static byte ToByte(DateTime value)
|
||||
|
@ -887,7 +871,7 @@ namespace System
|
|||
[CLSCompliant(false)]
|
||||
public static short ToInt16(uint value)
|
||||
{
|
||||
if (value > short.MaxValue) ThrowInt16OverflowException();
|
||||
if (value > (uint)short.MaxValue) ThrowInt16OverflowException();
|
||||
return (short)value;
|
||||
}
|
||||
|
||||
|
@ -928,14 +912,14 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return short.Parse(value, CultureInfo.CurrentCulture);
|
||||
return short.Parse(value);
|
||||
}
|
||||
|
||||
public static short ToInt16(string? value, IFormatProvider? provider)
|
||||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return short.Parse(value, NumberStyles.Integer, provider);
|
||||
return short.Parse(value, provider);
|
||||
}
|
||||
|
||||
public static short ToInt16(DateTime value)
|
||||
|
@ -993,11 +977,7 @@ namespace System
|
|||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static ushort ToUInt16(int value)
|
||||
{
|
||||
if (value < 0 || value > ushort.MaxValue) ThrowUInt16OverflowException();
|
||||
return (ushort)value;
|
||||
}
|
||||
public static ushort ToUInt16(int value) => ToUInt16((uint)value);
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static ushort ToUInt16(ushort value)
|
||||
|
@ -1013,11 +993,7 @@ namespace System
|
|||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static ushort ToUInt16(long value)
|
||||
{
|
||||
if (value < 0 || value > ushort.MaxValue) ThrowUInt16OverflowException();
|
||||
return (ushort)value;
|
||||
}
|
||||
public static ushort ToUInt16(long value) => ToUInt16((ulong)value);
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static ushort ToUInt16(ulong value)
|
||||
|
@ -1049,7 +1025,7 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return ushort.Parse(value, CultureInfo.CurrentCulture);
|
||||
return ushort.Parse(value);
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
|
@ -1057,7 +1033,7 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return ushort.Parse(value, NumberStyles.Integer, provider);
|
||||
return ushort.Parse(value, provider);
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
|
@ -1116,7 +1092,7 @@ namespace System
|
|||
[CLSCompliant(false)]
|
||||
public static int ToInt32(uint value)
|
||||
{
|
||||
if (value > int.MaxValue) ThrowInt32OverflowException();
|
||||
if ((int)value < 0) ThrowInt32OverflowException();
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
|
@ -1177,14 +1153,14 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return int.Parse(value, CultureInfo.CurrentCulture);
|
||||
return int.Parse(value);
|
||||
}
|
||||
|
||||
public static int ToInt32(string? value, IFormatProvider? provider)
|
||||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return int.Parse(value, NumberStyles.Integer, provider);
|
||||
return int.Parse(value, provider);
|
||||
}
|
||||
|
||||
public static int ToInt32(DateTime value)
|
||||
|
@ -1261,11 +1237,7 @@ namespace System
|
|||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static uint ToUInt32(long value)
|
||||
{
|
||||
if (value < 0 || value > uint.MaxValue) ThrowUInt32OverflowException();
|
||||
return (uint)value;
|
||||
}
|
||||
public static uint ToUInt32(long value) => ToUInt32((ulong)value);
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public static uint ToUInt32(ulong value)
|
||||
|
@ -1304,7 +1276,7 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return uint.Parse(value, CultureInfo.CurrentCulture);
|
||||
return uint.Parse(value);
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
|
@ -1312,7 +1284,7 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return uint.Parse(value, NumberStyles.Integer, provider);
|
||||
return uint.Parse(value, provider);
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
|
@ -1382,7 +1354,7 @@ namespace System
|
|||
[CLSCompliant(false)]
|
||||
public static long ToInt64(ulong value)
|
||||
{
|
||||
if (value > long.MaxValue) ThrowInt64OverflowException();
|
||||
if ((long)value < 0) ThrowInt64OverflowException();
|
||||
return (long)value;
|
||||
}
|
||||
|
||||
|
@ -1410,14 +1382,14 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return long.Parse(value, CultureInfo.CurrentCulture);
|
||||
return long.Parse(value);
|
||||
}
|
||||
|
||||
public static long ToInt64(string? value, IFormatProvider? provider)
|
||||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return long.Parse(value, NumberStyles.Integer, provider);
|
||||
return long.Parse(value, provider);
|
||||
}
|
||||
|
||||
public static long ToInt64(DateTime value)
|
||||
|
@ -1529,7 +1501,7 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return ulong.Parse(value, CultureInfo.CurrentCulture);
|
||||
return ulong.Parse(value);
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
|
@ -1537,7 +1509,7 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return ulong.Parse(value, NumberStyles.Integer, provider);
|
||||
return ulong.Parse(value, provider);
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
|
@ -1629,14 +1601,14 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return float.Parse(value, CultureInfo.CurrentCulture);
|
||||
return float.Parse(value);
|
||||
}
|
||||
|
||||
public static float ToSingle(string? value, IFormatProvider? provider)
|
||||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return float.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider);
|
||||
return float.Parse(value, provider);
|
||||
}
|
||||
|
||||
public static float ToSingle(bool value)
|
||||
|
@ -1732,14 +1704,14 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return double.Parse(value, CultureInfo.CurrentCulture);
|
||||
return double.Parse(value);
|
||||
}
|
||||
|
||||
public static double ToDouble(string? value, IFormatProvider? provider)
|
||||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
return double.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider);
|
||||
return double.Parse(value, provider);
|
||||
}
|
||||
|
||||
public static double ToDouble(bool value)
|
||||
|
@ -1830,14 +1802,14 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return 0m;
|
||||
return decimal.Parse(value, CultureInfo.CurrentCulture);
|
||||
return decimal.Parse(value);
|
||||
}
|
||||
|
||||
public static decimal ToDecimal(string? value, IFormatProvider? provider)
|
||||
{
|
||||
if (value == null)
|
||||
return 0m;
|
||||
return decimal.Parse(value, NumberStyles.Number, provider);
|
||||
return decimal.Parse(value, provider);
|
||||
}
|
||||
|
||||
public static decimal ToDecimal(decimal value)
|
||||
|
@ -1879,7 +1851,7 @@ namespace System
|
|||
{
|
||||
if (value == null)
|
||||
return new DateTime(0);
|
||||
return DateTime.Parse(value, CultureInfo.CurrentCulture);
|
||||
return DateTime.Parse(value);
|
||||
}
|
||||
|
||||
public static DateTime ToDateTime(string? value, IFormatProvider? provider)
|
||||
|
@ -2000,7 +1972,7 @@ namespace System
|
|||
[CLSCompliant(false)]
|
||||
public static string ToString(sbyte value)
|
||||
{
|
||||
return value.ToString(CultureInfo.CurrentCulture);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
|
@ -2011,7 +1983,7 @@ namespace System
|
|||
|
||||
public static string ToString(byte value)
|
||||
{
|
||||
return value.ToString(CultureInfo.CurrentCulture);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public static string ToString(byte value, IFormatProvider? provider)
|
||||
|
@ -2021,7 +1993,7 @@ namespace System
|
|||
|
||||
public static string ToString(short value)
|
||||
{
|
||||
return value.ToString(CultureInfo.CurrentCulture);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public static string ToString(short value, IFormatProvider? provider)
|
||||
|
@ -2032,7 +2004,7 @@ namespace System
|
|||
[CLSCompliant(false)]
|
||||
public static string ToString(ushort value)
|
||||
{
|
||||
return value.ToString(CultureInfo.CurrentCulture);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
|
@ -2043,7 +2015,7 @@ namespace System
|
|||
|
||||
public static string ToString(int value)
|
||||
{
|
||||
return value.ToString(CultureInfo.CurrentCulture);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public static string ToString(int value, IFormatProvider? provider)
|
||||
|
@ -2054,7 +2026,7 @@ namespace System
|
|||
[CLSCompliant(false)]
|
||||
public static string ToString(uint value)
|
||||
{
|
||||
return value.ToString(CultureInfo.CurrentCulture);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
|
@ -2065,7 +2037,7 @@ namespace System
|
|||
|
||||
public static string ToString(long value)
|
||||
{
|
||||
return value.ToString(CultureInfo.CurrentCulture);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public static string ToString(long value, IFormatProvider? provider)
|
||||
|
@ -2076,7 +2048,7 @@ namespace System
|
|||
[CLSCompliant(false)]
|
||||
public static string ToString(ulong value)
|
||||
{
|
||||
return value.ToString(CultureInfo.CurrentCulture);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
[CLSCompliant(false)]
|
||||
|
@ -2087,7 +2059,7 @@ namespace System
|
|||
|
||||
public static string ToString(float value)
|
||||
{
|
||||
return value.ToString(CultureInfo.CurrentCulture);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public static string ToString(float value, IFormatProvider? provider)
|
||||
|
@ -2097,7 +2069,7 @@ namespace System
|
|||
|
||||
public static string ToString(double value)
|
||||
{
|
||||
return value.ToString(CultureInfo.CurrentCulture);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public static string ToString(double value, IFormatProvider? provider)
|
||||
|
@ -2107,7 +2079,7 @@ namespace System
|
|||
|
||||
public static string ToString(decimal value)
|
||||
{
|
||||
return value.ToString(CultureInfo.CurrentCulture);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public static string ToString(decimal value, IFormatProvider? provider)
|
||||
|
@ -2157,7 +2129,7 @@ namespace System
|
|||
}
|
||||
|
||||
int r = ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned);
|
||||
if (r < byte.MinValue || r > byte.MaxValue)
|
||||
if ((uint)r > byte.MaxValue)
|
||||
ThrowByteOverflowException();
|
||||
return (byte)r;
|
||||
}
|
||||
|
@ -2231,7 +2203,7 @@ namespace System
|
|||
}
|
||||
|
||||
int r = ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned);
|
||||
if (r < ushort.MinValue || r > ushort.MaxValue)
|
||||
if ((uint)r > ushort.MaxValue)
|
||||
ThrowUInt16OverflowException();
|
||||
return (ushort)r;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
@ -751,8 +752,7 @@ namespace System
|
|||
// Because the ticks conversion between UTC and local is lossy, we need to capture whether the
|
||||
// time is in a repeated hour so that it can be passed to the DateTime constructor.
|
||||
DateTime utcDt = new DateTime(ticks, DateTimeKind.Utc);
|
||||
bool isDaylightSavings = false;
|
||||
offsetTicks = TimeZoneInfo.GetUtcOffsetFromUtc(utcDt, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst).Ticks;
|
||||
offsetTicks = TimeZoneInfo.GetUtcOffsetFromUtc(utcDt, TimeZoneInfo.Local, out bool isDaylightSavings, out isAmbiguousLocalDst).Ticks;
|
||||
}
|
||||
ticks += offsetTicks;
|
||||
// Another behaviour of parsing is to cause small times to wrap around, so that they can be used
|
||||
|
@ -1079,8 +1079,7 @@ namespace System
|
|||
get
|
||||
{
|
||||
DateTime utc = UtcNow;
|
||||
bool isAmbiguousLocalDst;
|
||||
long offset = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utc, out isAmbiguousLocalDst).Ticks;
|
||||
long offset = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utc, out bool isAmbiguousLocalDst).Ticks;
|
||||
long tick = utc.Ticks + offset;
|
||||
if (tick > DateTime.MaxTicks)
|
||||
{
|
||||
|
@ -1290,9 +1289,7 @@ namespace System
|
|||
{
|
||||
return this;
|
||||
}
|
||||
bool isDaylightSavings = false;
|
||||
bool isAmbiguousLocalDst = false;
|
||||
long offset = TimeZoneInfo.GetUtcOffsetFromUtc(this, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst).Ticks;
|
||||
long offset = TimeZoneInfo.GetUtcOffsetFromUtc(this, TimeZoneInfo.Local, out bool isDaylightSavings, out bool isAmbiguousLocalDst).Ticks;
|
||||
long tick = Ticks + offset;
|
||||
if (tick > DateTime.MaxTicks)
|
||||
{
|
||||
|
@ -1359,7 +1356,7 @@ namespace System
|
|||
return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
|
||||
}
|
||||
|
||||
public static bool TryParse(string? s, out DateTime result)
|
||||
public static bool TryParse([NotNullWhen(true)] string? s, out DateTime result)
|
||||
{
|
||||
if (s == null)
|
||||
{
|
||||
|
@ -1374,7 +1371,7 @@ namespace System
|
|||
return DateTimeParse.TryParse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result);
|
||||
}
|
||||
|
||||
public static bool TryParse(string? s, IFormatProvider? provider, DateTimeStyles styles, out DateTime result)
|
||||
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, DateTimeStyles styles, out DateTime result)
|
||||
{
|
||||
DateTimeFormatInfo.ValidateStyles(styles, nameof(styles));
|
||||
|
||||
|
@ -1393,7 +1390,7 @@ namespace System
|
|||
return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result);
|
||||
}
|
||||
|
||||
public static bool TryParseExact(string? s, string? format, IFormatProvider? provider, DateTimeStyles style, out DateTime result)
|
||||
public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(true)] string? format, IFormatProvider? provider, DateTimeStyles style, out DateTime result)
|
||||
{
|
||||
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
|
||||
|
||||
|
@ -1412,7 +1409,7 @@ namespace System
|
|||
return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result);
|
||||
}
|
||||
|
||||
public static bool TryParseExact(string? s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result)
|
||||
public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(true)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result)
|
||||
{
|
||||
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
|
||||
|
||||
|
@ -1425,7 +1422,7 @@ namespace System
|
|||
return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result);
|
||||
}
|
||||
|
||||
public static bool TryParseExact(ReadOnlySpan<char> s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result)
|
||||
public static bool TryParseExact(ReadOnlySpan<char> s, [NotNullWhen(true)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result)
|
||||
{
|
||||
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
|
||||
return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization;
|
||||
|
@ -479,11 +480,10 @@ namespace System
|
|||
{
|
||||
if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
|
||||
|
||||
TimeSpan offset;
|
||||
DateTime dateResult = DateTimeParse.Parse(input,
|
||||
DateTimeFormatInfo.CurrentInfo,
|
||||
DateTimeStyles.None,
|
||||
out offset);
|
||||
out TimeSpan offset);
|
||||
return new DateTimeOffset(dateResult.Ticks, offset);
|
||||
}
|
||||
|
||||
|
@ -502,11 +502,10 @@ namespace System
|
|||
styles = ValidateStyles(styles, nameof(styles));
|
||||
if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
|
||||
|
||||
TimeSpan offset;
|
||||
DateTime dateResult = DateTimeParse.Parse(input,
|
||||
DateTimeFormatInfo.GetInstance(formatProvider),
|
||||
styles,
|
||||
out offset);
|
||||
out TimeSpan offset);
|
||||
return new DateTimeOffset(dateResult.Ticks, offset);
|
||||
}
|
||||
|
||||
|
@ -538,12 +537,11 @@ namespace System
|
|||
if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
|
||||
if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
|
||||
|
||||
TimeSpan offset;
|
||||
DateTime dateResult = DateTimeParse.ParseExact(input,
|
||||
format,
|
||||
DateTimeFormatInfo.GetInstance(formatProvider),
|
||||
styles,
|
||||
out offset);
|
||||
out TimeSpan offset);
|
||||
return new DateTimeOffset(dateResult.Ticks, offset);
|
||||
}
|
||||
|
||||
|
@ -559,12 +557,11 @@ namespace System
|
|||
styles = ValidateStyles(styles, nameof(styles));
|
||||
if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input);
|
||||
|
||||
TimeSpan offset;
|
||||
DateTime dateResult = DateTimeParse.ParseExactMultiple(input,
|
||||
formats,
|
||||
DateTimeFormatInfo.GetInstance(formatProvider),
|
||||
styles,
|
||||
out offset);
|
||||
out TimeSpan offset);
|
||||
return new DateTimeOffset(dateResult.Ticks, offset);
|
||||
}
|
||||
|
||||
|
@ -652,15 +649,13 @@ namespace System
|
|||
public DateTimeOffset ToUniversalTime() =>
|
||||
new DateTimeOffset(UtcDateTime);
|
||||
|
||||
public static bool TryParse(string? input, out DateTimeOffset result)
|
||||
public static bool TryParse([NotNullWhen(true)] string? input, out DateTimeOffset result)
|
||||
{
|
||||
TimeSpan offset;
|
||||
DateTime dateResult;
|
||||
bool parsed = DateTimeParse.TryParse(input,
|
||||
DateTimeFormatInfo.CurrentInfo,
|
||||
DateTimeStyles.None,
|
||||
out dateResult,
|
||||
out offset);
|
||||
out DateTime dateResult,
|
||||
out TimeSpan offset);
|
||||
result = new DateTimeOffset(dateResult.Ticks, offset);
|
||||
return parsed;
|
||||
}
|
||||
|
@ -672,7 +667,7 @@ namespace System
|
|||
return parsed;
|
||||
}
|
||||
|
||||
public static bool TryParse(string? input, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result)
|
||||
public static bool TryParse([NotNullWhen(true)] string? input, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result)
|
||||
{
|
||||
styles = ValidateStyles(styles, nameof(styles));
|
||||
if (input == null)
|
||||
|
@ -681,13 +676,11 @@ namespace System
|
|||
return false;
|
||||
}
|
||||
|
||||
TimeSpan offset;
|
||||
DateTime dateResult;
|
||||
bool parsed = DateTimeParse.TryParse(input,
|
||||
DateTimeFormatInfo.GetInstance(formatProvider),
|
||||
styles,
|
||||
out dateResult,
|
||||
out offset);
|
||||
out DateTime dateResult,
|
||||
out TimeSpan offset);
|
||||
result = new DateTimeOffset(dateResult.Ticks, offset);
|
||||
return parsed;
|
||||
}
|
||||
|
@ -700,7 +693,7 @@ namespace System
|
|||
return parsed;
|
||||
}
|
||||
|
||||
public static bool TryParseExact(string? input, string? format, IFormatProvider? formatProvider, DateTimeStyles styles,
|
||||
public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string? format, IFormatProvider? formatProvider, DateTimeStyles styles,
|
||||
out DateTimeOffset result)
|
||||
{
|
||||
styles = ValidateStyles(styles, nameof(styles));
|
||||
|
@ -710,14 +703,12 @@ namespace System
|
|||
return false;
|
||||
}
|
||||
|
||||
TimeSpan offset;
|
||||
DateTime dateResult;
|
||||
bool parsed = DateTimeParse.TryParseExact(input,
|
||||
format,
|
||||
DateTimeFormatInfo.GetInstance(formatProvider),
|
||||
styles,
|
||||
out dateResult,
|
||||
out offset);
|
||||
out DateTime dateResult,
|
||||
out TimeSpan offset);
|
||||
result = new DateTimeOffset(dateResult.Ticks, offset);
|
||||
return parsed;
|
||||
}
|
||||
|
@ -731,7 +722,7 @@ namespace System
|
|||
return parsed;
|
||||
}
|
||||
|
||||
public static bool TryParseExact(string? input, string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles,
|
||||
public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles,
|
||||
out DateTimeOffset result)
|
||||
{
|
||||
styles = ValidateStyles(styles, nameof(styles));
|
||||
|
@ -741,20 +732,18 @@ namespace System
|
|||
return false;
|
||||
}
|
||||
|
||||
TimeSpan offset;
|
||||
DateTime dateResult;
|
||||
bool parsed = DateTimeParse.TryParseExactMultiple(input,
|
||||
formats,
|
||||
DateTimeFormatInfo.GetInstance(formatProvider),
|
||||
styles,
|
||||
out dateResult,
|
||||
out offset);
|
||||
out DateTime dateResult,
|
||||
out TimeSpan offset);
|
||||
result = new DateTimeOffset(dateResult.Ticks, offset);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
public static bool TryParseExact(
|
||||
ReadOnlySpan<char> input, string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result)
|
||||
ReadOnlySpan<char> input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result)
|
||||
{
|
||||
styles = ValidateStyles(styles, nameof(styles));
|
||||
bool parsed = DateTimeParse.TryParseExactMultiple(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
using System.Buffers.Binary;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -480,7 +481,7 @@ namespace System
|
|||
return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider));
|
||||
}
|
||||
|
||||
public static bool TryParse(string? s, out decimal result)
|
||||
public static bool TryParse([NotNullWhen(true)] string? s, out decimal result)
|
||||
{
|
||||
if (s == null)
|
||||
{
|
||||
|
@ -496,7 +497,7 @@ namespace System
|
|||
return Number.TryParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK;
|
||||
}
|
||||
|
||||
public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out decimal result)
|
||||
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out decimal result)
|
||||
{
|
||||
NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
|
||||
|
||||
|
@ -936,9 +937,9 @@ namespace System
|
|||
[CLSCompliant(false)]
|
||||
public static explicit operator ulong(decimal value) => ToUInt64(value);
|
||||
|
||||
public static explicit operator float(decimal value) => ToSingle(value);
|
||||
public static explicit operator float(decimal value) => DecCalc.VarR4FromDec(in value);
|
||||
|
||||
public static explicit operator double(decimal value) => ToDouble(value);
|
||||
public static explicit operator double(decimal value) => DecCalc.VarR8FromDec(in value);
|
||||
|
||||
public static decimal operator +(decimal d) => d;
|
||||
|
||||
|
@ -1051,12 +1052,12 @@ namespace System
|
|||
|
||||
float IConvertible.ToSingle(IFormatProvider? provider)
|
||||
{
|
||||
return Convert.ToSingle(this);
|
||||
return DecCalc.VarR4FromDec(in this);
|
||||
}
|
||||
|
||||
double IConvertible.ToDouble(IFormatProvider? provider)
|
||||
{
|
||||
return Convert.ToDouble(this);
|
||||
return DecCalc.VarR8FromDec(in this);
|
||||
}
|
||||
|
||||
decimal IConvertible.ToDecimal(IFormatProvider? provider)
|
||||
|
|
|
@ -600,7 +600,6 @@ namespace System
|
|||
{
|
||||
if (newMin == 2)
|
||||
{
|
||||
currentMin = i;
|
||||
ambig = false;
|
||||
currentMin = i;
|
||||
}
|
||||
|
|
|
@ -125,4 +125,71 @@ namespace System.Diagnostics.CodeAnalysis
|
|||
/// <summary>Gets the condition parameter value.</summary>
|
||||
public bool ParameterValue { get; }
|
||||
}
|
||||
|
||||
/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values.</summary>
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
|
||||
#if INTERNAL_NULLABLE_ATTRIBUTES
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
sealed class MemberNotNullAttribute : Attribute
|
||||
{
|
||||
/// <summary>Initializes the attribute with a field or property member.</summary>
|
||||
/// <param name="member">
|
||||
/// The field or property member that is promised to be not-null.
|
||||
/// </param>
|
||||
public MemberNotNullAttribute(string member) => Members = new[] { member };
|
||||
|
||||
/// <summary>Initializes the attribute with the list of field and property members.</summary>
|
||||
/// <param name="members">
|
||||
/// The list of field and property members that are promised to be not-null.
|
||||
/// </param>
|
||||
public MemberNotNullAttribute(params string[] members) => Members = members;
|
||||
|
||||
/// <summary>Gets field or property member names.</summary>
|
||||
public string[] Members { get; }
|
||||
}
|
||||
|
||||
/// <summary>Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition.</summary>
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
|
||||
#if INTERNAL_NULLABLE_ATTRIBUTES
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
sealed class MemberNotNullWhenAttribute : Attribute
|
||||
{
|
||||
/// <summary>Initializes the attribute with the specified return value condition and a field or property member.</summary>
|
||||
/// <param name="returnValue">
|
||||
/// The return value condition. If the method returns this value, the associated parameter will not be null.
|
||||
/// </param>
|
||||
/// <param name="member">
|
||||
/// The field or property member that is promised to be not-null.
|
||||
/// </param>
|
||||
public MemberNotNullWhenAttribute(bool returnValue, string member)
|
||||
{
|
||||
ReturnValue = returnValue;
|
||||
Members = new[] { member };
|
||||
}
|
||||
|
||||
/// <summary>Initializes the attribute with the specified return value condition and list of field and property members.</summary>
|
||||
/// <param name="returnValue">
|
||||
/// The return value condition. If the method returns this value, the associated parameter will not be null.
|
||||
/// </param>
|
||||
/// <param name="members">
|
||||
/// The list of field and property members that are promised to be not-null.
|
||||
/// </param>
|
||||
public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
|
||||
{
|
||||
ReturnValue = returnValue;
|
||||
Members = members;
|
||||
}
|
||||
|
||||
/// <summary>Gets the return value condition.</summary>
|
||||
public bool ReturnValue { get; }
|
||||
|
||||
/// <summary>Gets field or property member names.</summary>
|
||||
public string[] Members { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace System.Diagnostics
|
||||
{
|
||||
public partial class DebugProvider
|
||||
|
@ -56,7 +54,7 @@ namespace System.Diagnostics
|
|||
}
|
||||
else
|
||||
{
|
||||
Interop.Sys.SysLog(Interop.Sys.SysLogPriority.LOG_USER | Interop.Sys.SysLogPriority.LOG_DEBUG, "%s", message);
|
||||
Interop.Sys.SysLog(Interop.Sys.SysLogPriority.LOG_DEBUG, "%s", message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +87,7 @@ namespace System.Diagnostics
|
|||
int totalBytesWritten = 0;
|
||||
while (bufCount > 0)
|
||||
{
|
||||
int bytesWritten = Interop.Sys.Write(2 /* stderr */, buf + totalBytesWritten, bufCount);
|
||||
int bytesWritten = Interop.Sys.Write((IntPtr)2 /* stderr */, buf + totalBytesWritten, bufCount);
|
||||
if (bytesWritten < 0)
|
||||
{
|
||||
// On error, simply stop writing the debug output. This could commonly happen if stderr
|
||||
|
|
|
@ -102,8 +102,7 @@ namespace System.Diagnostics.Tracing
|
|||
EnsureEventSourceIndexAvailable(eventSourceIndex);
|
||||
Debug.Assert(s_counterGroups != null);
|
||||
WeakReference<CounterGroup> weakRef = CounterGroup.s_counterGroups[eventSourceIndex];
|
||||
CounterGroup? ret = null;
|
||||
if (weakRef == null || !weakRef.TryGetTarget(out ret))
|
||||
if (weakRef == null || !weakRef.TryGetTarget(out CounterGroup? ret))
|
||||
{
|
||||
ret = new CounterGroup(eventSource);
|
||||
CounterGroup.s_counterGroups[eventSourceIndex] = new WeakReference<CounterGroup>(ret);
|
||||
|
|
|
@ -0,0 +1,277 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
#if FEATURE_PERFTRACING
|
||||
|
||||
namespace System.Diagnostics.Tracing
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct EventPipeEventInstanceData
|
||||
{
|
||||
internal IntPtr ProviderID;
|
||||
internal uint EventID;
|
||||
internal uint ThreadID;
|
||||
internal long TimeStamp;
|
||||
internal Guid ActivityId;
|
||||
internal Guid ChildActivityId;
|
||||
internal IntPtr Payload;
|
||||
internal uint PayloadLength;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct EventPipeSessionInfo
|
||||
{
|
||||
internal long StartTimeAsUTCFileTime;
|
||||
internal long StartTimeStamp;
|
||||
internal long TimeStampFrequency;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct EventPipeProviderConfiguration
|
||||
{
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
private readonly string m_providerName;
|
||||
private readonly ulong m_keywords;
|
||||
private readonly uint m_loggingLevel;
|
||||
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
private readonly string? m_filterData;
|
||||
|
||||
internal EventPipeProviderConfiguration(
|
||||
string providerName,
|
||||
ulong keywords,
|
||||
uint loggingLevel,
|
||||
string? filterData)
|
||||
{
|
||||
if (string.IsNullOrEmpty(providerName))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(providerName));
|
||||
}
|
||||
if (loggingLevel > 5) // 5 == Verbose, the highest value in EventPipeLoggingLevel.
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(loggingLevel));
|
||||
}
|
||||
m_providerName = providerName;
|
||||
m_keywords = keywords;
|
||||
m_loggingLevel = loggingLevel;
|
||||
m_filterData = filterData;
|
||||
}
|
||||
|
||||
internal string ProviderName
|
||||
{
|
||||
get { return m_providerName; }
|
||||
}
|
||||
|
||||
internal ulong Keywords
|
||||
{
|
||||
get { return m_keywords; }
|
||||
}
|
||||
|
||||
internal uint LoggingLevel
|
||||
{
|
||||
get { return m_loggingLevel; }
|
||||
}
|
||||
|
||||
internal string? FilterData => m_filterData;
|
||||
}
|
||||
|
||||
internal enum EventPipeSerializationFormat
|
||||
{
|
||||
NetPerf,
|
||||
NetTrace
|
||||
}
|
||||
|
||||
internal sealed class EventPipeWaitHandle : WaitHandle
|
||||
{
|
||||
}
|
||||
|
||||
internal sealed class EventPipeConfiguration
|
||||
{
|
||||
private readonly string m_outputFile;
|
||||
private readonly EventPipeSerializationFormat m_format;
|
||||
private readonly uint m_circularBufferSizeInMB;
|
||||
private readonly List<EventPipeProviderConfiguration> m_providers;
|
||||
private TimeSpan m_minTimeBetweenSamples = TimeSpan.FromMilliseconds(1);
|
||||
|
||||
internal EventPipeConfiguration(
|
||||
string outputFile,
|
||||
EventPipeSerializationFormat format,
|
||||
uint circularBufferSizeInMB)
|
||||
{
|
||||
if (string.IsNullOrEmpty(outputFile))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(outputFile));
|
||||
}
|
||||
if (circularBufferSizeInMB == 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(circularBufferSizeInMB));
|
||||
}
|
||||
m_outputFile = outputFile;
|
||||
m_format = format;
|
||||
m_circularBufferSizeInMB = circularBufferSizeInMB;
|
||||
m_providers = new List<EventPipeProviderConfiguration>();
|
||||
}
|
||||
|
||||
internal string OutputFile
|
||||
{
|
||||
get { return m_outputFile; }
|
||||
}
|
||||
|
||||
internal EventPipeSerializationFormat Format
|
||||
{
|
||||
get { return m_format; }
|
||||
}
|
||||
|
||||
internal uint CircularBufferSizeInMB
|
||||
{
|
||||
get { return m_circularBufferSizeInMB; }
|
||||
}
|
||||
|
||||
internal EventPipeProviderConfiguration[] Providers
|
||||
{
|
||||
get { return m_providers.ToArray(); }
|
||||
}
|
||||
|
||||
internal void EnableProvider(string providerName, ulong keywords, uint loggingLevel)
|
||||
{
|
||||
EnableProviderWithFilter(providerName, keywords, loggingLevel, null);
|
||||
}
|
||||
|
||||
internal void EnableProviderWithFilter(string providerName, ulong keywords, uint loggingLevel, string? filterData)
|
||||
{
|
||||
m_providers.Add(new EventPipeProviderConfiguration(
|
||||
providerName,
|
||||
keywords,
|
||||
loggingLevel,
|
||||
filterData));
|
||||
}
|
||||
|
||||
private void EnableProviderConfiguration(EventPipeProviderConfiguration providerConfig)
|
||||
{
|
||||
m_providers.Add(providerConfig);
|
||||
}
|
||||
|
||||
internal void EnableProviderRange(EventPipeProviderConfiguration[] providerConfigs)
|
||||
{
|
||||
foreach (EventPipeProviderConfiguration config in providerConfigs)
|
||||
{
|
||||
EnableProviderConfiguration(config);
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetProfilerSamplingRate(TimeSpan minTimeBetweenSamples)
|
||||
{
|
||||
if (minTimeBetweenSamples.Ticks <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(minTimeBetweenSamples));
|
||||
}
|
||||
|
||||
m_minTimeBetweenSamples = minTimeBetweenSamples;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class EventPipe
|
||||
{
|
||||
private static ulong s_sessionID = 0;
|
||||
|
||||
internal static void Enable(EventPipeConfiguration configuration)
|
||||
{
|
||||
if (configuration == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configuration));
|
||||
}
|
||||
|
||||
if (configuration.Providers == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configuration.Providers));
|
||||
}
|
||||
|
||||
EventPipeProviderConfiguration[] providers = configuration.Providers;
|
||||
|
||||
s_sessionID = EventPipeInternal.Enable(
|
||||
configuration.OutputFile,
|
||||
configuration.Format,
|
||||
configuration.CircularBufferSizeInMB,
|
||||
providers);
|
||||
}
|
||||
|
||||
internal static void Disable()
|
||||
{
|
||||
EventPipeInternal.Disable(s_sessionID);
|
||||
}
|
||||
}
|
||||
|
||||
internal static partial class EventPipeInternal
|
||||
{
|
||||
private unsafe struct EventPipeProviderConfigurationNative
|
||||
{
|
||||
private char* m_pProviderName;
|
||||
private ulong m_keywords;
|
||||
private uint m_loggingLevel;
|
||||
private char* m_pFilterData;
|
||||
|
||||
internal static void MarshalToNative(EventPipeProviderConfiguration managed, ref EventPipeProviderConfigurationNative native)
|
||||
{
|
||||
native.m_pProviderName = (char*)Marshal.StringToCoTaskMemUni(managed.ProviderName);
|
||||
native.m_keywords = managed.Keywords;
|
||||
native.m_loggingLevel = managed.LoggingLevel;
|
||||
native.m_pFilterData = (char*)Marshal.StringToCoTaskMemUni(managed.FilterData);
|
||||
}
|
||||
|
||||
internal void Release()
|
||||
{
|
||||
if (m_pProviderName != null)
|
||||
{
|
||||
Marshal.FreeCoTaskMem((IntPtr)m_pProviderName);
|
||||
}
|
||||
if (m_pFilterData != null)
|
||||
{
|
||||
Marshal.FreeCoTaskMem((IntPtr)m_pFilterData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe ulong Enable(
|
||||
string? outputFile,
|
||||
EventPipeSerializationFormat format,
|
||||
uint circularBufferSizeInMB,
|
||||
EventPipeProviderConfiguration[] providers)
|
||||
{
|
||||
Span<EventPipeProviderConfigurationNative> providersNative = new Span<EventPipeProviderConfigurationNative>((void*)Marshal.AllocCoTaskMem(sizeof(EventPipeProviderConfigurationNative) * providers.Length), providers.Length);
|
||||
providersNative.Clear();
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < providers.Length; i++)
|
||||
{
|
||||
EventPipeProviderConfigurationNative.MarshalToNative(providers[i], ref providersNative[i]);
|
||||
}
|
||||
|
||||
fixed (char* outputFilePath = outputFile)
|
||||
fixed (EventPipeProviderConfigurationNative* providersNativePointer = providersNative)
|
||||
{
|
||||
return Enable(outputFilePath, format, circularBufferSizeInMB, providersNativePointer, (uint)providersNative.Length);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
for (int i = 0; i < providers.Length; i++)
|
||||
{
|
||||
providersNative[i].Release();
|
||||
}
|
||||
|
||||
fixed (EventPipeProviderConfigurationNative* providersNativePointer = providersNative)
|
||||
{
|
||||
Marshal.FreeCoTaskMem((IntPtr)providersNativePointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FEATURE_PERFTRACING
|
|
@ -0,0 +1,226 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace System.Diagnostics.Tracing
|
||||
{
|
||||
#if FEATURE_PERFTRACING
|
||||
internal sealed class EventPipeEventDispatcher
|
||||
{
|
||||
internal sealed class EventListenerSubscription
|
||||
{
|
||||
internal EventKeywords MatchAnyKeywords { get; private set; }
|
||||
internal EventLevel Level { get; private set; }
|
||||
|
||||
internal EventListenerSubscription(EventKeywords matchAnyKeywords, EventLevel level)
|
||||
{
|
||||
MatchAnyKeywords = matchAnyKeywords;
|
||||
Level = level;
|
||||
}
|
||||
}
|
||||
|
||||
internal static readonly EventPipeEventDispatcher Instance = new EventPipeEventDispatcher();
|
||||
|
||||
private readonly IntPtr m_RuntimeProviderID;
|
||||
|
||||
private ulong m_sessionID = 0;
|
||||
private DateTime m_syncTimeUtc;
|
||||
private long m_syncTimeQPC;
|
||||
private long m_timeQPCFrequency;
|
||||
|
||||
private bool m_stopDispatchTask;
|
||||
private readonly EventPipeWaitHandle m_dispatchTaskWaitHandle = new EventPipeWaitHandle();
|
||||
private Task? m_dispatchTask = null;
|
||||
private readonly object m_dispatchControlLock = new object();
|
||||
private readonly Dictionary<EventListener, EventListenerSubscription> m_subscriptions = new Dictionary<EventListener, EventListenerSubscription>();
|
||||
|
||||
private const uint DefaultEventListenerCircularMBSize = 10;
|
||||
|
||||
private EventPipeEventDispatcher()
|
||||
{
|
||||
// Get the ID of the runtime provider so that it can be used as a filter when processing events.
|
||||
m_RuntimeProviderID = EventPipeInternal.GetProvider(NativeRuntimeEventSource.EventSourceName);
|
||||
m_dispatchTaskWaitHandle.SafeWaitHandle = new SafeWaitHandle(IntPtr.Zero, false);
|
||||
}
|
||||
|
||||
internal void SendCommand(EventListener eventListener, EventCommand command, bool enable, EventLevel level, EventKeywords matchAnyKeywords)
|
||||
{
|
||||
if (command == EventCommand.Update && enable)
|
||||
{
|
||||
lock (m_dispatchControlLock)
|
||||
{
|
||||
// Add the new subscription. This will overwrite an existing subscription for the listener if one exists.
|
||||
m_subscriptions[eventListener] = new EventListenerSubscription(matchAnyKeywords, level);
|
||||
|
||||
// Commit the configuration change.
|
||||
CommitDispatchConfiguration();
|
||||
}
|
||||
}
|
||||
else if (command == EventCommand.Update && !enable)
|
||||
{
|
||||
RemoveEventListener(eventListener);
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveEventListener(EventListener listener)
|
||||
{
|
||||
lock (m_dispatchControlLock)
|
||||
{
|
||||
// Remove the event listener from the list of subscribers.
|
||||
if (m_subscriptions.ContainsKey(listener))
|
||||
{
|
||||
m_subscriptions.Remove(listener);
|
||||
}
|
||||
|
||||
// Commit the configuration change.
|
||||
CommitDispatchConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
private void CommitDispatchConfiguration()
|
||||
{
|
||||
Debug.Assert(Monitor.IsEntered(m_dispatchControlLock));
|
||||
|
||||
// Ensure that the dispatch task is stopped.
|
||||
// This is a no-op if the task is already stopped.
|
||||
StopDispatchTask();
|
||||
|
||||
// Stop tracing.
|
||||
// This is a no-op if it's already disabled.
|
||||
EventPipeInternal.Disable(m_sessionID);
|
||||
|
||||
// Check to see if tracing should be enabled.
|
||||
if (m_subscriptions.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine the keywords and level that should be used based on the set of enabled EventListeners.
|
||||
EventKeywords aggregatedKeywords = EventKeywords.None;
|
||||
EventLevel highestLevel = EventLevel.LogAlways;
|
||||
|
||||
foreach (EventListenerSubscription subscription in m_subscriptions.Values)
|
||||
{
|
||||
aggregatedKeywords |= subscription.MatchAnyKeywords;
|
||||
highestLevel = (subscription.Level > highestLevel) ? subscription.Level : highestLevel;
|
||||
}
|
||||
|
||||
// Enable the EventPipe session.
|
||||
EventPipeProviderConfiguration[] providerConfiguration = new EventPipeProviderConfiguration[]
|
||||
{
|
||||
new EventPipeProviderConfiguration(NativeRuntimeEventSource.EventSourceName, (ulong)aggregatedKeywords, (uint)highestLevel, null)
|
||||
};
|
||||
|
||||
m_sessionID = EventPipeInternal.Enable(null, EventPipeSerializationFormat.NetTrace, DefaultEventListenerCircularMBSize, providerConfiguration);
|
||||
Debug.Assert(m_sessionID != 0);
|
||||
|
||||
// Get the session information that is required to properly dispatch events.
|
||||
EventPipeSessionInfo sessionInfo;
|
||||
unsafe
|
||||
{
|
||||
if (!EventPipeInternal.GetSessionInfo(m_sessionID, &sessionInfo))
|
||||
{
|
||||
Debug.Fail("GetSessionInfo returned false.");
|
||||
}
|
||||
}
|
||||
|
||||
m_syncTimeUtc = DateTime.FromFileTimeUtc(sessionInfo.StartTimeAsUTCFileTime);
|
||||
m_syncTimeQPC = sessionInfo.StartTimeStamp;
|
||||
m_timeQPCFrequency = sessionInfo.TimeStampFrequency;
|
||||
|
||||
// Start the dispatch task.
|
||||
StartDispatchTask();
|
||||
}
|
||||
|
||||
private void StartDispatchTask()
|
||||
{
|
||||
Debug.Assert(Monitor.IsEntered(m_dispatchControlLock));
|
||||
|
||||
if (m_dispatchTask == null)
|
||||
{
|
||||
m_stopDispatchTask = false;
|
||||
// Create a SafeWaitHandle that won't release the handle when done
|
||||
m_dispatchTaskWaitHandle.SafeWaitHandle = new SafeWaitHandle(EventPipeInternal.GetWaitHandle(m_sessionID), false);
|
||||
|
||||
m_dispatchTask = Task.Factory.StartNew(DispatchEventsToEventListeners, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||
}
|
||||
}
|
||||
|
||||
private void StopDispatchTask()
|
||||
{
|
||||
Debug.Assert(Monitor.IsEntered(m_dispatchControlLock));
|
||||
|
||||
if (m_dispatchTask != null)
|
||||
{
|
||||
m_stopDispatchTask = true;
|
||||
Debug.Assert(!m_dispatchTaskWaitHandle.SafeWaitHandle.IsInvalid);
|
||||
EventWaitHandle.Set(m_dispatchTaskWaitHandle.SafeWaitHandle);
|
||||
m_dispatchTask.Wait();
|
||||
m_dispatchTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void DispatchEventsToEventListeners()
|
||||
{
|
||||
// Struct to fill with the call to GetNextEvent.
|
||||
EventPipeEventInstanceData instanceData;
|
||||
|
||||
while (!m_stopDispatchTask)
|
||||
{
|
||||
bool eventsReceived = false;
|
||||
// Get the next event.
|
||||
while (!m_stopDispatchTask && EventPipeInternal.GetNextEvent(m_sessionID, &instanceData))
|
||||
{
|
||||
eventsReceived = true;
|
||||
|
||||
// Filter based on provider.
|
||||
if (instanceData.ProviderID == m_RuntimeProviderID)
|
||||
{
|
||||
// Dispatch the event.
|
||||
ReadOnlySpan<byte> payload = new ReadOnlySpan<byte>((void*)instanceData.Payload, (int)instanceData.PayloadLength);
|
||||
DateTime dateTimeStamp = TimeStampToDateTime(instanceData.TimeStamp);
|
||||
NativeRuntimeEventSource.Log.ProcessEvent(instanceData.EventID, instanceData.ThreadID, dateTimeStamp, instanceData.ActivityId, instanceData.ChildActivityId, payload);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for more events.
|
||||
if (!m_stopDispatchTask)
|
||||
{
|
||||
if (!eventsReceived)
|
||||
{
|
||||
// Future TODO: this would make more sense to handle in EventPipeSession/EventPipe native code.
|
||||
Debug.Assert(!m_dispatchTaskWaitHandle.SafeWaitHandle.IsInvalid);
|
||||
m_dispatchTaskWaitHandle.WaitOne();
|
||||
}
|
||||
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a QueryPerformanceCounter (QPC) timestamp to a UTC DateTime.
|
||||
/// </summary>
|
||||
private DateTime TimeStampToDateTime(long timeStamp)
|
||||
{
|
||||
if (timeStamp == long.MaxValue)
|
||||
{
|
||||
return DateTime.MaxValue;
|
||||
}
|
||||
|
||||
Debug.Assert((m_syncTimeUtc.Ticks != 0) && (m_syncTimeQPC != 0) && (m_timeQPCFrequency != 0));
|
||||
long inTicks = (long)((timeStamp - m_syncTimeQPC) * 10000000.0 / m_timeQPCFrequency) + m_syncTimeUtc.Ticks;
|
||||
if ((inTicks < 0) || (DateTime.MaxTicks < inTicks))
|
||||
{
|
||||
inTicks = DateTime.MaxTicks;
|
||||
}
|
||||
|
||||
return new DateTime(inTicks, DateTimeKind.Utc);
|
||||
}
|
||||
}
|
||||
#endif // FEATURE_PERFTRACING
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace System.Diagnostics.Tracing
|
||||
{
|
||||
internal sealed class EventPipeEventProvider : IEventProvider
|
||||
{
|
||||
// The EventPipeProvider handle.
|
||||
private IntPtr m_provHandle = IntPtr.Zero;
|
||||
|
||||
// Register an event provider.
|
||||
unsafe uint IEventProvider.EventRegister(
|
||||
EventSource eventSource,
|
||||
Interop.Advapi32.EtwEnableCallback enableCallback,
|
||||
void* callbackContext,
|
||||
ref long registrationHandle)
|
||||
{
|
||||
uint returnStatus = 0;
|
||||
m_provHandle = EventPipeInternal.CreateProvider(eventSource.Name, enableCallback);
|
||||
if (m_provHandle != IntPtr.Zero)
|
||||
{
|
||||
// Fixed registration handle because a new EventPipeEventProvider
|
||||
// will be created for each new EventSource.
|
||||
registrationHandle = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unable to create the provider.
|
||||
returnStatus = 1;
|
||||
}
|
||||
|
||||
return returnStatus;
|
||||
}
|
||||
|
||||
// Unregister an event provider.
|
||||
uint IEventProvider.EventUnregister(long registrationHandle)
|
||||
{
|
||||
EventPipeInternal.DeleteProvider(m_provHandle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write an event.
|
||||
unsafe EventProvider.WriteEventErrorCode IEventProvider.EventWriteTransfer(
|
||||
long registrationHandle,
|
||||
in EventDescriptor eventDescriptor,
|
||||
IntPtr eventHandle,
|
||||
Guid* activityId,
|
||||
Guid* relatedActivityId,
|
||||
int userDataCount,
|
||||
EventProvider.EventData* userData)
|
||||
{
|
||||
if (eventHandle != IntPtr.Zero)
|
||||
{
|
||||
if (userDataCount == 0)
|
||||
{
|
||||
EventPipeInternal.WriteEventData(eventHandle, null, 0, activityId, relatedActivityId);
|
||||
return EventProvider.WriteEventErrorCode.NoError;
|
||||
}
|
||||
|
||||
// If Channel == 11, this is a TraceLogging event.
|
||||
// The first 3 descriptors contain event metadata that is emitted for ETW and should be discarded on EventPipe.
|
||||
// EventPipe metadata is provided via the EventPipeEventProvider.DefineEventHandle.
|
||||
if (eventDescriptor.Channel == 11)
|
||||
{
|
||||
userData += 3;
|
||||
userDataCount -= 3;
|
||||
Debug.Assert(userDataCount >= 0);
|
||||
}
|
||||
EventPipeInternal.WriteEventData(eventHandle, userData, (uint)userDataCount, activityId, relatedActivityId);
|
||||
}
|
||||
|
||||
return EventProvider.WriteEventErrorCode.NoError;
|
||||
}
|
||||
|
||||
// Get or set the per-thread activity ID.
|
||||
int IEventProvider.EventActivityIdControl(Interop.Advapi32.ActivityControl ControlCode, ref Guid ActivityId)
|
||||
{
|
||||
return EventPipeInternal.EventActivityIdControl((uint)ControlCode, ref ActivityId);
|
||||
}
|
||||
|
||||
// Define an EventPipeEvent handle.
|
||||
unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, uint level, byte* pMetadata, uint metadataLength)
|
||||
{
|
||||
IntPtr eventHandlePtr = EventPipeInternal.DefineEvent(m_provHandle, eventID, keywords, eventVersion, level, pMetadata, metadataLength);
|
||||
return eventHandlePtr;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,412 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
using System.Reflection;
|
||||
using EventMetadata = System.Diagnostics.Tracing.EventSource.EventMetadata;
|
||||
|
||||
namespace System.Diagnostics.Tracing
|
||||
{
|
||||
#if FEATURE_PERFTRACING
|
||||
internal sealed class EventPipeMetadataGenerator
|
||||
{
|
||||
public static EventPipeMetadataGenerator Instance = new EventPipeMetadataGenerator();
|
||||
|
||||
private EventPipeMetadataGenerator() { }
|
||||
|
||||
public byte[]? GenerateEventMetadata(EventMetadata eventMetadata)
|
||||
{
|
||||
ParameterInfo[] parameters = eventMetadata.Parameters;
|
||||
EventParameterInfo[] eventParams = new EventParameterInfo[parameters.Length];
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
eventParams[i].SetInfo(parameters[i].Name!, parameters[i].ParameterType);
|
||||
}
|
||||
|
||||
return GenerateMetadata(
|
||||
eventMetadata.Descriptor.EventId,
|
||||
eventMetadata.Name,
|
||||
eventMetadata.Descriptor.Keywords,
|
||||
eventMetadata.Descriptor.Level,
|
||||
eventMetadata.Descriptor.Version,
|
||||
eventParams);
|
||||
}
|
||||
|
||||
public byte[]? GenerateEventMetadata(
|
||||
int eventId,
|
||||
string eventName,
|
||||
EventKeywords keywords,
|
||||
EventLevel level,
|
||||
uint version,
|
||||
TraceLoggingEventTypes eventTypes)
|
||||
{
|
||||
TraceLoggingTypeInfo[] typeInfos = eventTypes.typeInfos;
|
||||
string[]? paramNames = eventTypes.paramNames;
|
||||
EventParameterInfo[] eventParams = new EventParameterInfo[typeInfos.Length];
|
||||
for (int i = 0; i < typeInfos.Length; i++)
|
||||
{
|
||||
string paramName = string.Empty;
|
||||
if (paramNames != null)
|
||||
{
|
||||
paramName = paramNames[i];
|
||||
}
|
||||
eventParams[i].SetInfo(paramName, typeInfos[i].DataType, typeInfos[i]);
|
||||
}
|
||||
|
||||
return GenerateMetadata(eventId, eventName, (long)keywords, (uint)level, version, eventParams);
|
||||
}
|
||||
|
||||
internal unsafe byte[]? GenerateMetadata(
|
||||
int eventId,
|
||||
string eventName,
|
||||
long keywords,
|
||||
uint level,
|
||||
uint version,
|
||||
EventParameterInfo[] parameters)
|
||||
{
|
||||
byte[]? metadata = null;
|
||||
try
|
||||
{
|
||||
// eventID : 4 bytes
|
||||
// eventName : (eventName.Length + 1) * 2 bytes
|
||||
// keywords : 8 bytes
|
||||
// eventVersion : 4 bytes
|
||||
// level : 4 bytes
|
||||
// parameterCount : 4 bytes
|
||||
uint metadataLength = 24 + ((uint)eventName.Length + 1) * 2;
|
||||
uint defaultMetadataLength = metadataLength;
|
||||
|
||||
// Check for an empty payload.
|
||||
// Write<T> calls with no arguments by convention have a parameter of
|
||||
// type NullTypeInfo which is serialized as nothing.
|
||||
if ((parameters.Length == 1) && (parameters[0].ParameterType == typeof(EmptyStruct)))
|
||||
{
|
||||
parameters = Array.Empty<EventParameterInfo>();
|
||||
}
|
||||
|
||||
// Increase the metadataLength for parameters.
|
||||
foreach (EventParameterInfo parameter in parameters)
|
||||
{
|
||||
int pMetadataLength = parameter.GetMetadataLength();
|
||||
// The call above may return -1 which means we failed to get the metadata length.
|
||||
// We then return a default metadata blob (with parameterCount of 0) to prevent it from generating malformed metadata.
|
||||
if (pMetadataLength < 0)
|
||||
{
|
||||
parameters = Array.Empty<EventParameterInfo>();
|
||||
metadataLength = defaultMetadataLength;
|
||||
break;
|
||||
}
|
||||
metadataLength += (uint)pMetadataLength;
|
||||
}
|
||||
|
||||
metadata = new byte[metadataLength];
|
||||
|
||||
// Write metadata: eventID, eventName, keywords, eventVersion, level, parameterCount, param1 type, param1 name...
|
||||
fixed (byte* pMetadata = metadata)
|
||||
{
|
||||
uint offset = 0;
|
||||
WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)eventId);
|
||||
fixed (char* pEventName = eventName)
|
||||
{
|
||||
WriteToBuffer(pMetadata, metadataLength, ref offset, (byte*)pEventName, ((uint)eventName.Length + 1) * 2);
|
||||
}
|
||||
WriteToBuffer(pMetadata, metadataLength, ref offset, keywords);
|
||||
WriteToBuffer(pMetadata, metadataLength, ref offset, version);
|
||||
WriteToBuffer(pMetadata, metadataLength, ref offset, level);
|
||||
WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)parameters.Length);
|
||||
foreach (EventParameterInfo parameter in parameters)
|
||||
{
|
||||
if (!parameter.GenerateMetadata(pMetadata, ref offset, metadataLength))
|
||||
{
|
||||
// If we fail to generate metadata for any parameter, we should return the "default" metadata without any parameters
|
||||
return GenerateMetadata(eventId, eventName, keywords, level, version, Array.Empty<EventParameterInfo>());
|
||||
}
|
||||
}
|
||||
Debug.Assert(metadataLength == offset);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If a failure occurs during metadata generation, make sure that we don't return
|
||||
// malformed metadata. Instead, return a null metadata blob.
|
||||
// Consumers can either build in knowledge of the event or skip it entirely.
|
||||
metadata = null;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
// Copy src to buffer and modify the offset.
|
||||
// Note: We know the buffer size ahead of time to make sure no buffer overflow.
|
||||
internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, byte* src, uint srcLength)
|
||||
{
|
||||
Debug.Assert(bufferLength >= (offset + srcLength));
|
||||
for (int i = 0; i < srcLength; i++)
|
||||
{
|
||||
*(byte*)(buffer + offset + i) = *(byte*)(src + i);
|
||||
}
|
||||
offset += srcLength;
|
||||
}
|
||||
|
||||
// Copy uint value to buffer.
|
||||
internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, uint value)
|
||||
{
|
||||
Debug.Assert(bufferLength >= (offset + 4));
|
||||
*(uint*)(buffer + offset) = value;
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
// Copy long value to buffer.
|
||||
internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, long value)
|
||||
{
|
||||
Debug.Assert(bufferLength >= (offset + 8));
|
||||
*(long*)(buffer + offset) = value;
|
||||
offset += 8;
|
||||
}
|
||||
|
||||
// Copy char value to buffer.
|
||||
internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, char value)
|
||||
{
|
||||
Debug.Assert(bufferLength >= (offset + 2));
|
||||
*(char*)(buffer + offset) = value;
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
|
||||
internal struct EventParameterInfo
|
||||
{
|
||||
internal string ParameterName;
|
||||
internal Type ParameterType;
|
||||
internal TraceLoggingTypeInfo? TypeInfo;
|
||||
|
||||
internal void SetInfo(string name, Type type, TraceLoggingTypeInfo? typeInfo = null)
|
||||
{
|
||||
ParameterName = name;
|
||||
ParameterType = type;
|
||||
TypeInfo = typeInfo;
|
||||
}
|
||||
|
||||
internal unsafe bool GenerateMetadata(byte* pMetadataBlob, ref uint offset, uint blobSize)
|
||||
{
|
||||
TypeCode typeCode = GetTypeCodeExtended(ParameterType);
|
||||
if (typeCode == TypeCode.Object)
|
||||
{
|
||||
// Each nested struct is serialized as:
|
||||
// TypeCode.Object : 4 bytes
|
||||
// Number of properties : 4 bytes
|
||||
// Property description 0...N
|
||||
// Nested struct property name : NULL-terminated string.
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)TypeCode.Object);
|
||||
|
||||
if (!(TypeInfo is InvokeTypeInfo invokeTypeInfo))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the set of properties to be serialized.
|
||||
PropertyAnalysis[]? properties = invokeTypeInfo.properties;
|
||||
if (properties != null)
|
||||
{
|
||||
// Write the count of serializable properties.
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)properties.Length);
|
||||
|
||||
foreach (PropertyAnalysis prop in properties)
|
||||
{
|
||||
if (!GenerateMetadataForProperty(prop, pMetadataBlob, ref offset, blobSize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This struct has zero serializable properties so we just write the property count.
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)0);
|
||||
}
|
||||
|
||||
// Top-level structs don't have a property name, but for simplicity we write a NULL-char to represent the name.
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, '\0');
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write parameter type.
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)typeCode);
|
||||
|
||||
// Write parameter name.
|
||||
fixed (char* pParameterName = ParameterName)
|
||||
{
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (byte*)pParameterName, ((uint)ParameterName.Length + 1) * 2);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static unsafe bool GenerateMetadataForProperty(PropertyAnalysis property, byte* pMetadataBlob, ref uint offset, uint blobSize)
|
||||
{
|
||||
Debug.Assert(property != null);
|
||||
Debug.Assert(pMetadataBlob != null);
|
||||
|
||||
// Check if this property is a nested struct.
|
||||
if (property.typeInfo is InvokeTypeInfo invokeTypeInfo)
|
||||
{
|
||||
// Each nested struct is serialized as:
|
||||
// TypeCode.Object : 4 bytes
|
||||
// Number of properties : 4 bytes
|
||||
// Property description 0...N
|
||||
// Nested struct property name : NULL-terminated string.
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)TypeCode.Object);
|
||||
|
||||
// Get the set of properties to be serialized.
|
||||
PropertyAnalysis[]? properties = invokeTypeInfo.properties;
|
||||
if (properties != null)
|
||||
{
|
||||
// Write the count of serializable properties.
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)properties.Length);
|
||||
|
||||
foreach (PropertyAnalysis prop in properties)
|
||||
{
|
||||
if (!GenerateMetadataForProperty(prop, pMetadataBlob, ref offset, blobSize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This struct has zero serializable properties so we just write the property count.
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)0);
|
||||
}
|
||||
|
||||
// Write the property name.
|
||||
fixed (char* pPropertyName = property.name)
|
||||
{
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (byte*)pPropertyName, ((uint)property.name.Length + 1) * 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Each primitive type is serialized as:
|
||||
// TypeCode : 4 bytes
|
||||
// PropertyName : NULL-terminated string
|
||||
TypeCode typeCode = GetTypeCodeExtended(property.typeInfo.DataType);
|
||||
|
||||
// EventPipe does not support this type. Throw, which will cause no metadata to be registered for this event.
|
||||
if (typeCode == TypeCode.Object)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the type code.
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)typeCode);
|
||||
|
||||
// Write the property name.
|
||||
fixed (char* pPropertyName = property.name)
|
||||
{
|
||||
EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (byte*)pPropertyName, ((uint)property.name.Length + 1) * 2);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal int GetMetadataLength()
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
TypeCode typeCode = GetTypeCodeExtended(ParameterType);
|
||||
if (typeCode == TypeCode.Object)
|
||||
{
|
||||
if (!(TypeInfo is InvokeTypeInfo typeInfo))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Each nested struct is serialized as:
|
||||
// TypeCode.Object : 4 bytes
|
||||
// Number of properties : 4 bytes
|
||||
// Property description 0...N
|
||||
// Nested struct property name : NULL-terminated string.
|
||||
ret += sizeof(uint) // TypeCode
|
||||
+ sizeof(uint); // Property count
|
||||
|
||||
// Get the set of properties to be serialized.
|
||||
PropertyAnalysis[]? properties = typeInfo.properties;
|
||||
if (properties != null)
|
||||
{
|
||||
foreach (PropertyAnalysis prop in properties)
|
||||
{
|
||||
ret += (int)GetMetadataLengthForProperty(prop);
|
||||
}
|
||||
}
|
||||
|
||||
// For simplicity when writing a reader, we write a NULL char
|
||||
// after the metadata for a top-level struct (for its name) so that
|
||||
// readers don't have do special case the outer-most struct.
|
||||
ret += sizeof(char);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += (int)(sizeof(uint) + ((ParameterName.Length + 1) * 2));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static uint GetMetadataLengthForProperty(PropertyAnalysis property)
|
||||
{
|
||||
Debug.Assert(property != null);
|
||||
|
||||
uint ret = 0;
|
||||
|
||||
// Check if this property is a nested struct.
|
||||
if (property.typeInfo is InvokeTypeInfo invokeTypeInfo)
|
||||
{
|
||||
// Each nested struct is serialized as:
|
||||
// TypeCode.Object : 4 bytes
|
||||
// Number of properties : 4 bytes
|
||||
// Property description 0...N
|
||||
// Nested struct property name : NULL-terminated string.
|
||||
ret += sizeof(uint) // TypeCode
|
||||
+ sizeof(uint); // Property count
|
||||
|
||||
// Get the set of properties to be serialized.
|
||||
PropertyAnalysis[]? properties = invokeTypeInfo.properties;
|
||||
if (properties != null)
|
||||
{
|
||||
foreach (PropertyAnalysis prop in properties)
|
||||
{
|
||||
ret += GetMetadataLengthForProperty(prop);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the size of the property name.
|
||||
ret += (uint)((property.name.Length + 1) * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += (uint)(sizeof(uint) + ((property.name.Length + 1) * 2));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static TypeCode GetTypeCodeExtended(Type parameterType)
|
||||
{
|
||||
// Guid is not part of TypeCode, we decided to use 17 to represent it, as it's the "free slot"
|
||||
// see https://github.com/dotnet/coreclr/issues/16105#issuecomment-361749750 for more
|
||||
const TypeCode GuidTypeCode = (TypeCode)17;
|
||||
|
||||
if (parameterType == typeof(Guid)) // Guid is not a part of TypeCode enum
|
||||
return GuidTypeCode;
|
||||
|
||||
// IntPtr and UIntPtr are converted to their non-pointer types.
|
||||
if (parameterType == typeof(IntPtr))
|
||||
return IntPtr.Size == 4 ? TypeCode.Int32 : TypeCode.Int64;
|
||||
|
||||
if (parameterType == typeof(UIntPtr))
|
||||
return UIntPtr.Size == 4 ? TypeCode.UInt32 : TypeCode.UInt64;
|
||||
|
||||
return Type.GetTypeCode(parameterType);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FEATURE_PERFTRACING
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
using System.Buffers.Binary;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Diagnostics.Tracing
|
||||
{
|
||||
#if FEATURE_PERFTRACING
|
||||
internal static class EventPipePayloadDecoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Given the metadata for an event and an event payload, decode and deserialize the event payload.
|
||||
/// </summary>
|
||||
internal static object[] DecodePayload(ref EventSource.EventMetadata metadata, ReadOnlySpan<byte> payload)
|
||||
{
|
||||
ParameterInfo[] parameters = metadata.Parameters;
|
||||
object[] decodedFields = new object[parameters.Length];
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
// It is possible that an older version of the event was emitted.
|
||||
// If this happens, the payload might be missing arguments at the end.
|
||||
// We can just leave these unset.
|
||||
if (payload.Length <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Type parameterType = parameters[i].ParameterType;
|
||||
if (parameterType == typeof(IntPtr))
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
{
|
||||
decodedFields[i] = (IntPtr)BinaryPrimitives.ReadInt64LittleEndian(payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
decodedFields[i] = (IntPtr)BinaryPrimitives.ReadInt32LittleEndian(payload);
|
||||
}
|
||||
payload = payload.Slice(IntPtr.Size);
|
||||
}
|
||||
else if (parameterType == typeof(int))
|
||||
{
|
||||
decodedFields[i] = BinaryPrimitives.ReadInt32LittleEndian(payload);
|
||||
payload = payload.Slice(sizeof(int));
|
||||
}
|
||||
else if (parameterType == typeof(uint))
|
||||
{
|
||||
decodedFields[i] = BinaryPrimitives.ReadUInt32LittleEndian(payload);
|
||||
payload = payload.Slice(sizeof(uint));
|
||||
}
|
||||
else if (parameterType == typeof(long))
|
||||
{
|
||||
decodedFields[i] = BinaryPrimitives.ReadInt64LittleEndian(payload);
|
||||
payload = payload.Slice(sizeof(long));
|
||||
}
|
||||
else if (parameterType == typeof(ulong))
|
||||
{
|
||||
decodedFields[i] = BinaryPrimitives.ReadUInt64LittleEndian(payload);
|
||||
payload = payload.Slice(sizeof(ulong));
|
||||
}
|
||||
else if (parameterType == typeof(byte))
|
||||
{
|
||||
decodedFields[i] = MemoryMarshal.Read<byte>(payload);
|
||||
payload = payload.Slice(sizeof(byte));
|
||||
}
|
||||
else if (parameterType == typeof(sbyte))
|
||||
{
|
||||
decodedFields[i] = MemoryMarshal.Read<sbyte>(payload);
|
||||
payload = payload.Slice(sizeof(sbyte));
|
||||
}
|
||||
else if (parameterType == typeof(short))
|
||||
{
|
||||
decodedFields[i] = BinaryPrimitives.ReadInt16LittleEndian(payload);
|
||||
payload = payload.Slice(sizeof(short));
|
||||
}
|
||||
else if (parameterType == typeof(ushort))
|
||||
{
|
||||
decodedFields[i] = BinaryPrimitives.ReadUInt16LittleEndian(payload);
|
||||
payload = payload.Slice(sizeof(ushort));
|
||||
}
|
||||
else if (parameterType == typeof(float))
|
||||
{
|
||||
decodedFields[i] = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(payload));
|
||||
payload = payload.Slice(sizeof(float));
|
||||
}
|
||||
else if (parameterType == typeof(double))
|
||||
{
|
||||
decodedFields[i] = BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64LittleEndian(payload));
|
||||
payload = payload.Slice(sizeof(double));
|
||||
}
|
||||
else if (parameterType == typeof(bool))
|
||||
{
|
||||
// The manifest defines a bool as a 32bit type (WIN32 BOOL), not 1 bit as CLR Does.
|
||||
decodedFields[i] = (BinaryPrimitives.ReadInt32LittleEndian(payload) == 1);
|
||||
payload = payload.Slice(sizeof(int));
|
||||
}
|
||||
else if (parameterType == typeof(Guid))
|
||||
{
|
||||
const int sizeOfGuid = 16;
|
||||
decodedFields[i] = new Guid(payload.Slice(0, sizeOfGuid));
|
||||
payload = payload.Slice(sizeOfGuid);
|
||||
}
|
||||
else if (parameterType == typeof(char))
|
||||
{
|
||||
decodedFields[i] = (char)BinaryPrimitives.ReadUInt16LittleEndian(payload);
|
||||
payload = payload.Slice(sizeof(char));
|
||||
}
|
||||
else if (parameterType == typeof(string))
|
||||
{
|
||||
// Try to find null terminator (0x00) from the byte span
|
||||
// NOTE: we do this by hand instead of using IndexOf because payload may be unaligned due to
|
||||
// mixture of different types being stored in the same buffer. (see eventpipe.cpp:CopyData)
|
||||
int byteCount = -1;
|
||||
for (int j = 1; j < payload.Length; j += 2)
|
||||
{
|
||||
if (payload[j - 1] == (byte)(0) && payload[j] == (byte)(0))
|
||||
{
|
||||
byteCount = j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ReadOnlySpan<char> charPayload;
|
||||
if (byteCount < 0)
|
||||
{
|
||||
charPayload = MemoryMarshal.Cast<byte, char>(payload);
|
||||
payload = default;
|
||||
}
|
||||
else
|
||||
{
|
||||
charPayload = MemoryMarshal.Cast<byte, char>(payload.Slice(0, byteCount - 2));
|
||||
payload = payload.Slice(byteCount);
|
||||
}
|
||||
decodedFields[i] = BitConverter.IsLittleEndian ? new string(charPayload) : Encoding.Unicode.GetString(MemoryMarshal.Cast<char, byte>(charPayload));
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Fail("Unsupported type encountered.");
|
||||
}
|
||||
}
|
||||
|
||||
return decodedFields;
|
||||
}
|
||||
}
|
||||
#endif // FEATURE_PERFTRACING
|
||||
}
|
|
@ -13,7 +13,7 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
#if CORECLR && TARGET_WINDOWS
|
||||
#if (CORECLR || MONO) && TARGET_WINDOWS
|
||||
using Internal.Win32;
|
||||
#endif
|
||||
#if ES_BUILD_AGAINST_DOTNET_V35
|
||||
|
@ -288,10 +288,8 @@ namespace System.Diagnostics.Tracing
|
|||
filterData = null;
|
||||
|
||||
// read filter data only when a session is being *added*
|
||||
byte[]? data;
|
||||
int keyIndex;
|
||||
if (bEnabling &&
|
||||
GetDataFromController(etwSessionId, filterData, out command, out data, out keyIndex))
|
||||
GetDataFromController(etwSessionId, filterData, out command, out byte[]? data, out int keyIndex))
|
||||
{
|
||||
args = new Dictionary<string, string?>(4);
|
||||
// data can be null if the filterArgs had a very large size which failed our sanity check
|
||||
|
@ -469,42 +467,59 @@ namespace System.Diagnostics.Tracing
|
|||
// does not have this issue.
|
||||
#if (TARGET_WINDOWS && (ES_SESSION_INFO || !ES_BUILD_STANDALONE))
|
||||
int buffSize = 256; // An initial guess that probably works most of the time.
|
||||
byte* buffer;
|
||||
while (true)
|
||||
byte* stackSpace = stackalloc byte[buffSize];
|
||||
byte* buffer = stackSpace;
|
||||
try
|
||||
{
|
||||
byte* space = stackalloc byte[buffSize];
|
||||
buffer = space;
|
||||
int hr = 0;
|
||||
|
||||
fixed (Guid* provider = &m_providerId)
|
||||
while (true)
|
||||
{
|
||||
hr = Interop.Advapi32.EnumerateTraceGuidsEx(Interop.Advapi32.TRACE_QUERY_INFO_CLASS.TraceGuidQueryInfo,
|
||||
provider, sizeof(Guid), buffer, buffSize, out buffSize);
|
||||
int hr = 0;
|
||||
|
||||
fixed (Guid* provider = &m_providerId)
|
||||
{
|
||||
hr = Interop.Advapi32.EnumerateTraceGuidsEx(Interop.Advapi32.TRACE_QUERY_INFO_CLASS.TraceGuidQueryInfo,
|
||||
provider, sizeof(Guid), buffer, buffSize, out buffSize);
|
||||
}
|
||||
if (hr == 0)
|
||||
break;
|
||||
if (hr != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
|
||||
return;
|
||||
|
||||
if (buffer != stackSpace)
|
||||
{
|
||||
byte* toFree = buffer;
|
||||
buffer = null;
|
||||
Marshal.FreeHGlobal((IntPtr)toFree);
|
||||
}
|
||||
buffer = (byte*)Marshal.AllocHGlobal(buffSize);
|
||||
}
|
||||
|
||||
var providerInfos = (Interop.Advapi32.TRACE_GUID_INFO*)buffer;
|
||||
var providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&providerInfos[1];
|
||||
int processId = unchecked((int)Interop.Kernel32.GetCurrentProcessId());
|
||||
// iterate over the instances of the EventProvider in all processes
|
||||
for (int i = 0; i < providerInfos->InstanceCount; i++)
|
||||
{
|
||||
if (providerInstance->Pid == processId)
|
||||
{
|
||||
var enabledInfos = (Interop.Advapi32.TRACE_ENABLE_INFO*)&providerInstance[1];
|
||||
// iterate over the list of active ETW sessions "listening" to the current provider
|
||||
for (int j = 0; j < providerInstance->EnableCount; j++)
|
||||
action(enabledInfos[j].LoggerId, enabledInfos[j].MatchAllKeyword, ref sessionList);
|
||||
}
|
||||
if (providerInstance->NextOffset == 0)
|
||||
break;
|
||||
Debug.Assert(0 <= providerInstance->NextOffset && providerInstance->NextOffset < buffSize);
|
||||
byte* structBase = (byte*)providerInstance;
|
||||
providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&structBase[providerInstance->NextOffset];
|
||||
}
|
||||
if (hr == 0)
|
||||
break;
|
||||
if (hr != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
|
||||
return;
|
||||
}
|
||||
|
||||
var providerInfos = (Interop.Advapi32.TRACE_GUID_INFO*)buffer;
|
||||
var providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&providerInfos[1];
|
||||
int processId = unchecked((int)Interop.Kernel32.GetCurrentProcessId());
|
||||
// iterate over the instances of the EventProvider in all processes
|
||||
for (int i = 0; i < providerInfos->InstanceCount; i++)
|
||||
finally
|
||||
{
|
||||
if (providerInstance->Pid == processId)
|
||||
if (buffer != null && buffer != stackSpace)
|
||||
{
|
||||
var enabledInfos = (Interop.Advapi32.TRACE_ENABLE_INFO*)&providerInstance[1];
|
||||
// iterate over the list of active ETW sessions "listening" to the current provider
|
||||
for (int j = 0; j < providerInstance->EnableCount; j++)
|
||||
action(enabledInfos[j].LoggerId, enabledInfos[j].MatchAllKeyword, ref sessionList);
|
||||
Marshal.FreeHGlobal((IntPtr)buffer);
|
||||
}
|
||||
if (providerInstance->NextOffset == 0)
|
||||
break;
|
||||
Debug.Assert(0 <= providerInstance->NextOffset && providerInstance->NextOffset < buffSize);
|
||||
byte* structBase = (byte*)providerInstance;
|
||||
providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&structBase[providerInstance->NextOffset];
|
||||
}
|
||||
#else
|
||||
#if !ES_BUILD_PCL && TARGET_WINDOWS // TODO command arguments don't work on PCL builds...
|
||||
|
|
|
@ -649,10 +649,8 @@ namespace System.Diagnostics.Tracing
|
|||
{
|
||||
m_config = ValidateSettings(settings);
|
||||
|
||||
Guid eventSourceGuid;
|
||||
string? eventSourceName;
|
||||
|
||||
GetMetadata(out eventSourceGuid, out eventSourceName, out _, out _);
|
||||
GetMetadata(out Guid eventSourceGuid, out string? eventSourceName, out _, out _);
|
||||
|
||||
if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null)
|
||||
{
|
||||
|
@ -1373,28 +1371,29 @@ namespace System.Diagnostics.Tracing
|
|||
int dataCount,
|
||||
IntPtr data)
|
||||
{
|
||||
#if FEATURE_MANAGED_ETW || FEATURE_PERFTRACING
|
||||
bool allAreNull = true;
|
||||
#if FEATURE_MANAGED_ETW
|
||||
if (m_etwProvider == null)
|
||||
allAreNull &= (m_etwProvider == null);
|
||||
if (m_etwProvider != null
|
||||
&& !m_etwProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data))
|
||||
{
|
||||
ThrowEventSourceException(eventName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_etwProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data))
|
||||
ThrowEventSourceException(eventName);
|
||||
}
|
||||
#endif // FEATURE_MANAGED_ETW
|
||||
#if FEATURE_PERFTRACING
|
||||
if (m_eventPipeProvider == null)
|
||||
allAreNull &= (m_eventPipeProvider == null);
|
||||
if (m_eventPipeProvider != null
|
||||
&& !m_eventPipeProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data))
|
||||
{
|
||||
ThrowEventSourceException(eventName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_eventPipeProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data))
|
||||
ThrowEventSourceException(eventName);
|
||||
}
|
||||
#endif // FEATURE_PERFTRACING
|
||||
if (allAreNull)
|
||||
{
|
||||
ThrowEventSourceException(eventName);
|
||||
}
|
||||
#endif // FEATURE_MANAGED_ETW || FEATURE_PERFTRACING
|
||||
}
|
||||
|
||||
// FrameworkEventSource is on the startup path for the framework, so we have this internal overload that it can use
|
||||
|
@ -2150,49 +2149,95 @@ namespace System.Diagnostics.Tracing
|
|||
}
|
||||
}
|
||||
|
||||
private unsafe void WriteEventString(EventLevel level, long keywords, string msgString)
|
||||
// WriteEventString is used for logging an error message (or similar) to
|
||||
// ETW and EventPipe providers. It is not a general purpose API, it will
|
||||
// log the message with Level=LogAlways and Keywords=All to make sure whoever
|
||||
// is listening gets the message.
|
||||
private unsafe void WriteEventString(string msgString)
|
||||
{
|
||||
#if FEATURE_MANAGED_ETW || FEATURE_PERFTRACING
|
||||
bool allAreNull = true;
|
||||
#if FEATURE_MANAGED_ETW
|
||||
if (m_etwProvider != null)
|
||||
allAreNull &= (m_etwProvider == null);
|
||||
#endif // FEATURE_MANAGED_ETW
|
||||
#if FEATURE_PERFTRACING
|
||||
allAreNull &= (m_eventPipeProvider == null);
|
||||
#endif // FEATURE_PERFTRACING
|
||||
if (allAreNull)
|
||||
{
|
||||
const string EventName = "EventSourceMessage";
|
||||
if (SelfDescribingEvents)
|
||||
{
|
||||
EventSourceOptions opt = new EventSourceOptions
|
||||
{
|
||||
Keywords = (EventKeywords)unchecked(keywords),
|
||||
Level = level
|
||||
};
|
||||
var msg = new { message = msgString };
|
||||
var tlet = new TraceLoggingEventTypes(EventName, EventTags.None, new Type[] { msg.GetType() });
|
||||
WriteMultiMergeInner(EventName, ref opt, tlet, null, null, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We want the name of the provider to show up so if we don't have a manifest we create
|
||||
// on that at least has the provider name (I don't define any events).
|
||||
if (m_rawManifest == null && m_outOfBandMessageCount == 1)
|
||||
{
|
||||
ManifestBuilder manifestBuilder = new ManifestBuilder(Name, Guid, Name, null, EventManifestOptions.None);
|
||||
manifestBuilder.StartEvent(EventName, new EventAttribute(0) { Level = EventLevel.LogAlways, Task = (EventTask)0xFFFE });
|
||||
manifestBuilder.AddEventParameter(typeof(string), "message");
|
||||
manifestBuilder.EndEvent();
|
||||
SendManifest(manifestBuilder.CreateManifest());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// We use this low level routine to bypass the enabled checking, since the eventSource itself is only partially inited.
|
||||
fixed (char* msgStringPtr = msgString)
|
||||
EventLevel level = EventLevel.LogAlways;
|
||||
long keywords = -1;
|
||||
const string EventName = "EventSourceMessage";
|
||||
if (SelfDescribingEvents)
|
||||
{
|
||||
EventSourceOptions opt = new EventSourceOptions
|
||||
{
|
||||
Keywords = (EventKeywords)unchecked(keywords),
|
||||
Level = level
|
||||
};
|
||||
var msg = new { message = msgString };
|
||||
var tlet = new TraceLoggingEventTypes(EventName, EventTags.None, new Type[] { msg.GetType() });
|
||||
WriteMultiMergeInner(EventName, ref opt, tlet, null, null, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We want the name of the provider to show up so if we don't have a manifest we create
|
||||
// on that at least has the provider name (I don't define any events).
|
||||
if (m_rawManifest == null && m_outOfBandMessageCount == 1)
|
||||
{
|
||||
ManifestBuilder manifestBuilder = new ManifestBuilder(Name, Guid, Name, null, EventManifestOptions.None);
|
||||
manifestBuilder.StartEvent(EventName, new EventAttribute(0) { Level = level, Task = (EventTask)0xFFFE });
|
||||
manifestBuilder.AddEventParameter(typeof(string), "message");
|
||||
manifestBuilder.EndEvent();
|
||||
SendManifest(manifestBuilder.CreateManifest());
|
||||
}
|
||||
|
||||
// We use this low level routine to bypass the enabled checking, since the eventSource itself is only partially inited.
|
||||
fixed (char* msgStringPtr = msgString)
|
||||
{
|
||||
EventDescriptor descr = new EventDescriptor(0, 0, 0, (byte)level, 0, 0, keywords);
|
||||
EventProvider.EventData data = default;
|
||||
data.Ptr = (ulong)msgStringPtr;
|
||||
data.Size = (uint)(2 * (msgString.Length + 1));
|
||||
data.Reserved = 0;
|
||||
#if FEATURE_MANAGED_ETW
|
||||
if (m_etwProvider != null)
|
||||
{
|
||||
EventDescriptor descr = new EventDescriptor(0, 0, 0, (byte)level, 0, 0, keywords);
|
||||
EventProvider.EventData data = default;
|
||||
data.Ptr = (ulong)msgStringPtr;
|
||||
data.Size = (uint)(2 * (msgString.Length + 1));
|
||||
data.Reserved = 0;
|
||||
m_etwProvider.WriteEvent(ref descr, IntPtr.Zero, null, null, 1, (IntPtr)((void*)&data));
|
||||
}
|
||||
#endif // FEATURE_MANAGED_ETW
|
||||
#if FEATURE_PERFTRACING
|
||||
if (m_eventPipeProvider != null)
|
||||
{
|
||||
if (m_writeEventStringEventHandle == IntPtr.Zero)
|
||||
{
|
||||
lock (m_createEventLock)
|
||||
{
|
||||
if (m_writeEventStringEventHandle == IntPtr.Zero)
|
||||
{
|
||||
string eventName = "EventSourceMessage";
|
||||
EventParameterInfo paramInfo = default(EventParameterInfo);
|
||||
paramInfo.SetInfo("message", typeof(string));
|
||||
byte[]? metadata = EventPipeMetadataGenerator.Instance.GenerateMetadata(0, eventName, keywords, (uint)level, 0, new EventParameterInfo[] { paramInfo });
|
||||
uint metadataLength = (metadata != null) ? (uint)metadata.Length : 0;
|
||||
|
||||
fixed (byte* pMetadata = metadata)
|
||||
{
|
||||
m_writeEventStringEventHandle = m_eventPipeProvider.m_eventProvider.DefineEventHandle(0, eventName, keywords, 0, (uint)level, pMetadata, metadataLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_eventPipeProvider.WriteEvent(ref descr, m_writeEventStringEventHandle, null, null, 1, (IntPtr)((void*)&data));
|
||||
}
|
||||
#endif // FEATURE_PERFTRACING
|
||||
}
|
||||
}
|
||||
#endif // FEATURE_MANAGED_ETW
|
||||
#endif // FEATURE_MANAGED_ETW || FEATURE_PERFTRACING
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -2871,13 +2916,10 @@ namespace System.Diagnostics.Tracing
|
|||
if (m_eventData == null)
|
||||
{
|
||||
Guid eventSourceGuid = Guid.Empty;
|
||||
string? eventSourceName = null;
|
||||
EventMetadata[]? eventData = null;
|
||||
byte[]? manifest = null;
|
||||
|
||||
// Try the GetMetadata provided by the ILTransform in ProjectN. The default sets all to null, and in that case we fall back
|
||||
// to the reflection approach.
|
||||
GetMetadata(out eventSourceGuid, out eventSourceName, out eventData, out manifest);
|
||||
GetMetadata(out eventSourceGuid, out string? eventSourceName, out EventMetadata[]? eventData, out byte[]? manifest);
|
||||
|
||||
if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null || eventData == null || manifest == null)
|
||||
{
|
||||
|
@ -3808,7 +3850,7 @@ namespace System.Diagnostics.Tracing
|
|||
msg = "Reached message limit. End of EventSource error messages.";
|
||||
}
|
||||
|
||||
WriteEventString(EventLevel.LogAlways, -1, msg);
|
||||
WriteEventString(msg);
|
||||
WriteStringToAllListeners("EventSourceMessage", msg);
|
||||
}
|
||||
catch { } // If we fail during last chance logging, well, we have to give up....
|
||||
|
@ -3865,6 +3907,8 @@ namespace System.Diagnostics.Tracing
|
|||
private volatile OverideEventProvider m_etwProvider = null!; // This hooks up ETW commands to our 'OnEventCommand' callback
|
||||
#endif
|
||||
#if FEATURE_PERFTRACING
|
||||
private object m_createEventLock = new object();
|
||||
private IntPtr m_writeEventStringEventHandle = IntPtr.Zero;
|
||||
private volatile OverideEventProvider m_eventPipeProvider = null!;
|
||||
#endif
|
||||
private bool m_completelyInited; // The EventSource constructor has returned without exception.
|
||||
|
@ -5551,8 +5595,7 @@ namespace System.Diagnostics.Tracing
|
|||
if (channelTab.Count == MaxCountChannels)
|
||||
ManifestError(SR.EventSource_MaxChannelExceeded);
|
||||
|
||||
ChannelInfo? info;
|
||||
if (!channelTab.TryGetValue((int)channel, out info))
|
||||
if (!channelTab.TryGetValue((int)channel, out ChannelInfo? info))
|
||||
{
|
||||
// If we were not given an explicit channel, allocate one.
|
||||
if (channelKeyword != 0)
|
||||
|
@ -5876,8 +5919,7 @@ namespace System.Diagnostics.Tracing
|
|||
#if FEATURE_MANAGED_ETW_CHANNELS
|
||||
private string? GetChannelName(EventChannel channel, string eventName, string? eventMessage)
|
||||
{
|
||||
ChannelInfo? info = null;
|
||||
if (channelTab == null || !channelTab.TryGetValue((int)channel, out info))
|
||||
if (channelTab == null || !channelTab.TryGetValue((int)channel, out ChannelInfo? info))
|
||||
{
|
||||
if (channel < EventChannel.Admin) // || channel > EventChannel.Debug)
|
||||
ManifestError(SR.Format(SR.EventSource_UndefinedChannel, channel, eventName));
|
||||
|
@ -5909,9 +5951,8 @@ namespace System.Diagnostics.Tracing
|
|||
if (task == EventTask.None)
|
||||
return "";
|
||||
|
||||
string? ret;
|
||||
taskTab ??= new Dictionary<int, string>();
|
||||
if (!taskTab.TryGetValue((int)task, out ret))
|
||||
if (!taskTab.TryGetValue((int)task, out string? ret))
|
||||
ret = taskTab[(int)task] = eventName;
|
||||
return ret;
|
||||
}
|
||||
|
@ -5944,8 +5985,7 @@ namespace System.Diagnostics.Tracing
|
|||
return "win:Receive";
|
||||
}
|
||||
|
||||
string? ret;
|
||||
if (opcodeTab == null || !opcodeTab.TryGetValue((int)opcode, out ret))
|
||||
if (opcodeTab == null || !opcodeTab.TryGetValue((int)opcode, out string? ret))
|
||||
{
|
||||
ManifestError(SR.Format(SR.EventSource_UndefinedOpcode, opcode, eventName), true);
|
||||
ret = null;
|
||||
|
@ -6052,7 +6092,6 @@ namespace System.Diagnostics.Tracing
|
|||
{
|
||||
StringBuilder? stringBuilder = null; // We lazily create this
|
||||
int writtenSoFar = 0;
|
||||
int chIdx = -1;
|
||||
for (int i = 0; ;)
|
||||
{
|
||||
if (i >= eventMessage.Length)
|
||||
|
@ -6063,6 +6102,7 @@ namespace System.Diagnostics.Tracing
|
|||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
int chIdx;
|
||||
if (eventMessage[i] == '%')
|
||||
{
|
||||
// handle format message escaping character '%' by escaping it
|
||||
|
@ -6125,8 +6165,7 @@ namespace System.Diagnostics.Tracing
|
|||
|
||||
private int TranslateIndexToManifestConvention(int idx, string evtName)
|
||||
{
|
||||
List<int>? byteArrArgIndices;
|
||||
if (perEventByteArrayArgIndices.TryGetValue(evtName, out byteArrArgIndices))
|
||||
if (perEventByteArrayArgIndices.TryGetValue(evtName, out List<int>? byteArrArgIndices))
|
||||
{
|
||||
foreach (int byArrIdx in byteArrArgIndices)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace System.Diagnostics.Tracing
|
||||
{
|
||||
/// <summary>
|
||||
/// NativeRuntimeEventSource is an EventSource that represents the ETW/EventPipe events emitted by the native runtime.
|
||||
/// Most of NativeRuntimeEventSource is auto-generated by scripts/genRuntimeEventSources.py based on the contents of the Microsoft-Windows-DotNETRuntime provider.
|
||||
/// </summary>
|
||||
[EventSource(Guid = "5E5BB766-BBFC-5662-0548-1D44FAD9BB56", Name = "Microsoft-Windows-DotNETRuntime")]
|
||||
internal sealed partial class NativeRuntimeEventSource : EventSource
|
||||
{
|
||||
internal const string EventSourceName = "Microsoft-Windows-DotNETRuntime";
|
||||
internal static NativeRuntimeEventSource Log = new NativeRuntimeEventSource();
|
||||
|
||||
// The NativeRuntimeEventSource GUID is {5e5bb766-bbfc-5662-0548-1d44fad9bb56}
|
||||
private NativeRuntimeEventSource() : base(new Guid(0x5e5bb766, 0xbbfc, 0x5662, 0x05, 0x48, 0x1d, 0x44, 0xfa, 0xd9, 0xbb, 0x56), EventSourceName) { }
|
||||
|
||||
/// <summary>
|
||||
/// Dispatch a single event with the specified event ID and payload.
|
||||
/// </summary>
|
||||
/// <param name="eventID">The eventID corresponding to the event as defined in the auto-generated portion of the NativeRuntimeEventSource class.</param>
|
||||
/// <param name="osThreadID">The thread ID of the operating system thread.</param>
|
||||
/// <param name="timeStamp">The current timestamp.</param>
|
||||
/// <param name="activityId">The ID of the current activity.</param>
|
||||
/// <param name="childActivityId">The ID of the current child activity.</param>
|
||||
/// <param name="payload">A span pointing to the data payload for the event.</param>
|
||||
[NonEvent]
|
||||
internal unsafe void ProcessEvent(uint eventID, uint osThreadID, DateTime timeStamp, Guid activityId, Guid childActivityId, ReadOnlySpan<byte> payload)
|
||||
{
|
||||
// Make sure the eventID is valid.
|
||||
if (eventID >= m_eventData!.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Decode the payload.
|
||||
object[] decodedPayloadFields = EventPipePayloadDecoder.DecodePayload(ref m_eventData[eventID], payload);
|
||||
WriteToAllListeners(
|
||||
eventId: (int)eventID,
|
||||
osThreadId: &osThreadID,
|
||||
timeStamp: &timeStamp,
|
||||
activityID: &activityId,
|
||||
childActivityID: &childActivityId,
|
||||
args: decodedPayloadFields);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Diagnostics.Tracing
|
||||
{
|
||||
/// <summary>
|
||||
/// RuntimeEventSource is an EventSource that represents events emitted by the managed runtime.
|
||||
/// </summary>
|
||||
[EventSource(Guid = "49592C0F-5A05-516D-AA4B-A64E02026C89", Name = "System.Runtime")]
|
||||
internal sealed class RuntimeEventSource : EventSource
|
||||
{
|
||||
internal const string EventSourceName = "System.Runtime";
|
||||
|
||||
private static RuntimeEventSource? s_RuntimeEventSource;
|
||||
private PollingCounter? _gcHeapSizeCounter;
|
||||
private IncrementingPollingCounter? _gen0GCCounter;
|
||||
private IncrementingPollingCounter? _gen1GCCounter;
|
||||
private IncrementingPollingCounter? _gen2GCCounter;
|
||||
private PollingCounter? _cpuTimeCounter;
|
||||
private PollingCounter? _workingSetCounter;
|
||||
private PollingCounter? _threadPoolThreadCounter;
|
||||
private IncrementingPollingCounter? _monitorContentionCounter;
|
||||
private PollingCounter? _threadPoolQueueCounter;
|
||||
private IncrementingPollingCounter? _completedItemsCounter;
|
||||
private IncrementingPollingCounter? _allocRateCounter;
|
||||
private PollingCounter? _timerCounter;
|
||||
|
||||
#if !MONO
|
||||
private IncrementingPollingCounter? _exceptionCounter;
|
||||
private PollingCounter? _gcTimeCounter;
|
||||
private PollingCounter? _gen0SizeCounter;
|
||||
private PollingCounter? _gen1SizeCounter;
|
||||
private PollingCounter? _gen2SizeCounter;
|
||||
private PollingCounter? _lohSizeCounter;
|
||||
private PollingCounter? _assemblyCounter;
|
||||
#endif
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
s_RuntimeEventSource = new RuntimeEventSource();
|
||||
}
|
||||
|
||||
private RuntimeEventSource() : base(new Guid(0x49592C0F, 0x5A05, 0x516D, 0xAA, 0x4B, 0xA6, 0x4E, 0x02, 0x02, 0x6C, 0x89), EventSourceName, EventSourceSettings.EtwSelfDescribingEventFormat)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnEventCommand(EventCommandEventArgs command)
|
||||
{
|
||||
if (command.Command == EventCommand.Enable)
|
||||
{
|
||||
// NOTE: These counters will NOT be disposed on disable command because we may be introducing
|
||||
// a race condition by doing that. We still want to create these lazily so that we aren't adding
|
||||
// overhead by at all times even when counters aren't enabled.
|
||||
|
||||
// On disable, PollingCounters will stop polling for values so it should be fine to leave them around.
|
||||
_cpuTimeCounter ??= new PollingCounter("cpu-usage", this, () => RuntimeEventSourceHelper.GetCpuUsage()) { DisplayName = "CPU Usage", DisplayUnits = "%" };
|
||||
_workingSetCounter ??= new PollingCounter("working-set", this, () => (double)(Environment.WorkingSet / 1000000)) { DisplayName = "Working Set", DisplayUnits = "MB" };
|
||||
_gcHeapSizeCounter ??= new PollingCounter("gc-heap-size", this, () => (double)(GC.GetTotalMemory(false) / 1000000)) { DisplayName = "GC Heap Size", DisplayUnits = "MB" };
|
||||
_gen0GCCounter ??= new IncrementingPollingCounter("gen-0-gc-count", this, () => GC.CollectionCount(0)) { DisplayName = "Gen 0 GC Count", DisplayRateTimeScale = new TimeSpan(0, 1, 0) };
|
||||
_gen1GCCounter ??= new IncrementingPollingCounter("gen-1-gc-count", this, () => GC.CollectionCount(1)) { DisplayName = "Gen 1 GC Count", DisplayRateTimeScale = new TimeSpan(0, 1, 0) };
|
||||
_gen2GCCounter ??= new IncrementingPollingCounter("gen-2-gc-count", this, () => GC.CollectionCount(2)) { DisplayName = "Gen 2 GC Count", DisplayRateTimeScale = new TimeSpan(0, 1, 0) };
|
||||
_threadPoolThreadCounter ??= new PollingCounter("threadpool-thread-count", this, () => ThreadPool.ThreadCount) { DisplayName = "ThreadPool Thread Count" };
|
||||
_monitorContentionCounter ??= new IncrementingPollingCounter("monitor-lock-contention-count", this, () => Monitor.LockContentionCount) { DisplayName = "Monitor Lock Contention Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) };
|
||||
_threadPoolQueueCounter ??= new PollingCounter("threadpool-queue-length", this, () => ThreadPool.PendingWorkItemCount) { DisplayName = "ThreadPool Queue Length" };
|
||||
_completedItemsCounter ??= new IncrementingPollingCounter("threadpool-completed-items-count", this, () => ThreadPool.CompletedWorkItemCount) { DisplayName = "ThreadPool Completed Work Item Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) };
|
||||
_allocRateCounter ??= new IncrementingPollingCounter("alloc-rate", this, () => GC.GetTotalAllocatedBytes()) { DisplayName = "Allocation Rate", DisplayUnits = "B", DisplayRateTimeScale = new TimeSpan(0, 0, 1) };
|
||||
_timerCounter ??= new PollingCounter("active-timer-count", this, () => Timer.ActiveCount) { DisplayName = "Number of Active Timers" };
|
||||
|
||||
#if !MONO
|
||||
_exceptionCounter ??= new IncrementingPollingCounter("exception-count", this, () => Exception.GetExceptionCount()) { DisplayName = "Exception Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) };
|
||||
_gcTimeCounter ??= new PollingCounter("time-in-gc", this, () => GC.GetLastGCPercentTimeInGC()) { DisplayName = "% Time in GC since last GC", DisplayUnits = "%" };
|
||||
_gen0SizeCounter ??= new PollingCounter("gen-0-size", this, () => GC.GetGenerationSize(0)) { DisplayName = "Gen 0 Size", DisplayUnits = "B" };
|
||||
_gen1SizeCounter ??= new PollingCounter("gen-1-size", this, () => GC.GetGenerationSize(1)) { DisplayName = "Gen 1 Size", DisplayUnits = "B" };
|
||||
_gen2SizeCounter ??= new PollingCounter("gen-2-size", this, () => GC.GetGenerationSize(2)) { DisplayName = "Gen 2 Size", DisplayUnits = "B" };
|
||||
_lohSizeCounter ??= new PollingCounter("loh-size", this, () => GC.GetGenerationSize(3)) { DisplayName = "LOH Size", DisplayUnits = "B" };
|
||||
_assemblyCounter ??= new PollingCounter("assembly-count", this, () => System.Reflection.Assembly.GetAssemblyCount()) { DisplayName = "Number of Assemblies Loaded" };
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace System.Diagnostics.Tracing
|
||||
{
|
||||
internal static class RuntimeEventSourceHelper
|
||||
{
|
||||
private static Interop.Sys.ProcessCpuInformation s_cpuInfo;
|
||||
|
||||
internal static int GetCpuUsage() =>
|
||||
Interop.Sys.GetCpuUtilization(ref s_cpuInfo) / Environment.ProcessorCount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace System.Diagnostics.Tracing
|
||||
{
|
||||
internal static class RuntimeEventSourceHelper
|
||||
{
|
||||
private static long s_prevProcUserTime = 0;
|
||||
private static long s_prevProcKernelTime = 0;
|
||||
private static long s_prevSystemUserTime = 0;
|
||||
private static long s_prevSystemKernelTime = 0;
|
||||
|
||||
internal static int GetCpuUsage()
|
||||
{
|
||||
// Returns the current process' CPU usage as a percentage
|
||||
|
||||
int cpuUsage;
|
||||
|
||||
if (!Interop.Kernel32.GetProcessTimes(Interop.Kernel32.GetCurrentProcess(), out _, out _, out long procKernelTime, out long procUserTime))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!Interop.Kernel32.GetSystemTimes(out _, out long systemUserTime, out long systemKernelTime))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s_prevSystemUserTime == 0 && s_prevSystemKernelTime == 0) // These may be 0 when we report CPU usage for the first time, in which case we should just return 0.
|
||||
{
|
||||
cpuUsage = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
long totalProcTime = (procUserTime - s_prevProcUserTime) + (procKernelTime - s_prevProcKernelTime);
|
||||
long totalSystemTime = (systemUserTime - s_prevSystemUserTime) + (systemKernelTime - s_prevSystemKernelTime);
|
||||
cpuUsage = (int)(totalProcTime * 100 / totalSystemTime);
|
||||
}
|
||||
|
||||
s_prevProcUserTime = procUserTime;
|
||||
s_prevProcKernelTime = procKernelTime;
|
||||
s_prevSystemUserTime = systemUserTime;
|
||||
s_prevSystemKernelTime = systemKernelTime;
|
||||
|
||||
return cpuUsage;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Diagnostics.Tracing
|
||||
{
|
||||
#if FEATURE_PERFTRACING
|
||||
/// <summary>
|
||||
/// Per-EventSource data structure for caching EventPipe EventHandles associated with TraceLogging events.
|
||||
/// </summary>
|
||||
internal sealed class TraceLoggingEventHandleTable
|
||||
{
|
||||
private const int DefaultLength = 10;
|
||||
private IntPtr[] m_innerTable;
|
||||
|
||||
internal TraceLoggingEventHandleTable()
|
||||
{
|
||||
m_innerTable = new IntPtr[DefaultLength];
|
||||
}
|
||||
|
||||
internal IntPtr this[int eventID]
|
||||
{
|
||||
get
|
||||
{
|
||||
IntPtr ret = IntPtr.Zero;
|
||||
IntPtr[] innerTable = Volatile.Read(ref m_innerTable);
|
||||
|
||||
if (eventID >= 0 && eventID < innerTable.Length)
|
||||
{
|
||||
ret = innerTable[eventID];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetEventHandle(int eventID, IntPtr eventHandle)
|
||||
{
|
||||
// Set operations must be serialized to ensure that re-size operations don't lose concurrent writes.
|
||||
Debug.Assert(Monitor.IsEntered(this));
|
||||
|
||||
if (eventID >= m_innerTable.Length)
|
||||
{
|
||||
int newSize = m_innerTable.Length * 2;
|
||||
if (newSize <= eventID)
|
||||
{
|
||||
newSize = eventID + 1;
|
||||
}
|
||||
|
||||
IntPtr[] newTable = new IntPtr[newSize];
|
||||
Array.Copy(m_innerTable, newTable, m_innerTable.Length);
|
||||
Volatile.Write(ref m_innerTable, newTable);
|
||||
}
|
||||
|
||||
m_innerTable[eventID] = eventHandle;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -523,8 +523,7 @@ namespace System.Diagnostics.Tracing
|
|||
|
||||
fixed (EventSourceOptions* pOptions = &options)
|
||||
{
|
||||
EventDescriptor descriptor;
|
||||
NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor);
|
||||
NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out EventDescriptor descriptor);
|
||||
if (nameInfo == null)
|
||||
{
|
||||
return;
|
||||
|
@ -591,9 +590,8 @@ namespace System.Diagnostics.Tracing
|
|||
{
|
||||
fixed (EventSourceOptions* pOptions = &options)
|
||||
{
|
||||
EventDescriptor descriptor;
|
||||
options.Opcode = options.IsOpcodeSet ? options.Opcode : GetOpcodeWithDefault(options.Opcode, eventName);
|
||||
NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor);
|
||||
NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out EventDescriptor descriptor);
|
||||
if (nameInfo == null)
|
||||
{
|
||||
return;
|
||||
|
@ -764,8 +762,7 @@ namespace System.Diagnostics.Tracing
|
|||
if (m_traits[i].StartsWith("ETW_", StringComparison.Ordinal))
|
||||
{
|
||||
string etwTrait = m_traits[i].Substring(4);
|
||||
byte traitNum;
|
||||
if (!byte.TryParse(etwTrait, out traitNum))
|
||||
if (!byte.TryParse(etwTrait, out byte traitNum))
|
||||
{
|
||||
if (etwTrait == "GROUP")
|
||||
{
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче