From a642ac36ec6efb2c8efeadde54b6f8ad235ab929 Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Sat, 15 Apr 2023 11:06:24 -0700 Subject: [PATCH 01/32] Update test run scripts (#84876) 1. Introduce "run.cmd parallel" and "run.py -parallel" arguments for running in anything except the default "collections" mode or the previously allowed sequential ("parallel none") mode. 2. Delete a lot of unused code in the run.cmd script (Fixes #55628) Running "parallel all" versus "parallel collections" (the default) runs the full set of tests twice as fast on my machine. --- src/tests/run.cmd | 218 +++------------------------------------------- src/tests/run.py | 20 +++++ 2 files changed, 34 insertions(+), 204 deletions(-) diff --git a/src/tests/run.cmd b/src/tests/run.cmd index 113deb87cbef1..0c79426b6c437 100644 --- a/src/tests/run.cmd +++ b/src/tests/run.cmd @@ -24,6 +24,7 @@ set __ToolsDir=%__ProjectDir%\..\Tools set "DotNetCli=%__RepoRootDir%\dotnet.cmd" set __Sequential= +set __ParallelType= set __msbuildExtraArgs= set __LongGCTests= set __GCSimulatorTests= @@ -53,13 +54,11 @@ if /i "%1" == "checked" (set __BuildType=Checked if /i "%1" == "TestEnv" (set __TestEnv=%2&shift&shift&goto Arg_Loop) if /i "%1" == "sequential" (set __Sequential=1&shift&goto Arg_Loop) -if /i "%1" == "longgc" (set __LongGCTests=1&shift&goto Arg_Loop) -if /i "%1" == "gcsimulator" (set __GCSimulatorTests=1&shift&goto Arg_Loop) +if /i "%1" == "parallel" (set __ParallelType=%2&shift&shift&goto Arg_Loop) if /i "%1" == "jitstress" (set DOTNET_JitStress=%2&shift&shift&goto Arg_Loop) if /i "%1" == "jitstressregs" (set DOTNET_JitStressRegs=%2&shift&shift&goto Arg_Loop) if /i "%1" == "jitminopts" (set DOTNET_JITMinOpts=1&shift&goto Arg_Loop) if /i "%1" == "jitforcerelocs" (set DOTNET_ForceRelocs=1&shift&goto Arg_Loop) -if /i "%1" == "ilasmroundtrip" (set __IlasmRoundTrip=1&shift&goto Arg_Loop) if /i "%1" == "printlastresultsonly" (set __PrintLastResultsOnly=1&shift&goto Arg_Loop) if /i "%1" == "runcrossgen2tests" (set RunCrossGen2=1&shift&goto Arg_Loop) @@ -68,11 +67,11 @@ if /i "%1" == "runlargeversionbubblecrossgen2tests" (set RunCrossGen2=1&set if /i "%1" == "synthesizepgo" (set CrossGen2SynthesizePgo=1&shift&goto Arg_Loop) if /i "%1" == "link" (set DoLink=true&set ILLINK=%2&shift&shift&goto Arg_Loop) if /i "%1" == "gcname" (set DOTNET_GCName=%2&shift&shift&goto Arg_Loop) -if /i "%1" == "timeout" (set __TestTimeout=%2&shift&shift&goto Arg_Loop) - -REM change it to DOTNET_GCStress when we stop using xunit harness if /i "%1" == "gcstresslevel" (set DOTNET_GCStress=%2&set __TestTimeout=1800000&shift&shift&goto Arg_Loop) - +if /i "%1" == "gcsimulator" (set __GCSimulatorTests=1&shift&goto Arg_Loop) +if /i "%1" == "longgc" (set __LongGCTests=1&shift&goto Arg_Loop) +if /i "%1" == "ilasmroundtrip" (set __IlasmRoundTrip=1&shift&goto Arg_Loop) +if /i "%1" == "timeout" (set __TestTimeout=%2&shift&shift&goto Arg_Loop) if /i "%1" == "runincontext" (set RunInUnloadableContext=1&shift&goto Arg_Loop) if /i "%1" == "tieringtest" (set TieringTest=1&shift&goto Arg_Loop) if /i "%1" == "runnativeaottests" (set RunNativeAot=1&shift&goto Arg_Loop) @@ -107,7 +106,7 @@ set "__TestWorkingDir=%__RootBinDir%\tests\coreclr\%__TargetOS%.%__BuildArch%.%_ if not defined XunitTestBinBase set XunitTestBinBase=%__TestWorkingDir%\ if not defined XunitTestReportDirBase set XunitTestReportDirBase=%XunitTestBinBase%\Reports\ -REM We are not running in the official build scenario, call run.py +REM Set up arguments to call run.py set __RuntestPyArgs=-arch %__BuildArch% -build_type %__BuildType% @@ -135,6 +134,10 @@ if defined __Sequential ( set __RuntestPyArgs=%__RuntestPyArgs% --sequential ) +if defined __ParallelType ( + set __RuntestPyArgs=%__RuntestPyArgs% -parallel %__ParallelType% +) + if defined RunCrossGen2 ( set __RuntestPyArgs=%__RuntestPyArgs% --run_crossgen2_tests ) @@ -180,201 +183,6 @@ echo %NEXTCMD% exit /b %ERRORLEVEL% -:SetupMSBuildAndCallRuntestProj - -:: Note: We've disabled node reuse because it causes file locking issues. -:: The issue is that we extend the build with our own targets which -:: means that rebuilding cannot successfully delete the task -:: assembly. -set __msbuildCommonArgs=/nologo /nodeReuse:false %__msbuildExtraArgs% /p:Platform=%__MSBuildBuildArch% - -if not defined __Sequential ( - set __msbuildCommonArgs=%__msbuildCommonArgs% /maxcpucount -) else ( - set __msbuildCommonArgs=%__msbuildCommonArgs% /p:ParallelRun=false -) - -if defined DoLink ( - set __msbuildCommonArgs=%__msbuildCommonArgs% /p:RunTestsViaIllink=true -) - -if not exist "%__LogsDir%" md "%__LogsDir%" -if not exist "%__MsbuildDebugLogsDir%" md "%__MsbuildDebugLogsDir%" - -REM Set up the directory for MSBuild debug logs. -set MSBUILDDEBUGPATH=%__MsbuildDebugLogsDir% - -REM These log files are created automatically by the test run process. Q: what do they depend on being set? -set __TestRunHtmlLog=%__LogsDir%\TestRun_%__TargetOS%__%__BuildArch%__%__BuildType%.html -set __TestRunXmlLog=%__LogsDir%\TestRun_%__TargetOS%__%__BuildArch%__%__BuildType%.xml - -REM Prepare the Test Drop - -echo %__MsgPrefix%Removing 'ni' files and 'lock' folders from %__TestWorkingDir% -REM Cleans any NI from the last run -powershell -NoProfile "Get-ChildItem -path %__TestWorkingDir% -Include '*.ni.*' -Recurse -Force | Remove-Item -force" -REM Cleans up any lock folder used for synchronization from last run -powershell -NoProfile "Get-ChildItem -path %__TestWorkingDir% -Include 'lock' -Recurse -Force | where {$_.Attributes -eq 'Directory'}| Remove-Item -force -Recurse" - -if defined CORE_ROOT goto SkipCoreRootSetup - -set "CORE_ROOT=%XunitTestBinBase%\Tests\Core_Root" -echo %__MsgPrefix%Using Default CORE_ROOT as %CORE_ROOT% -echo %__MsgPrefix%Copying Built binaries from %__BinDir% to %CORE_ROOT% -if exist "%CORE_ROOT%" rd /s /q "%CORE_ROOT%" -md "%CORE_ROOT%" -xcopy "%__BinDir%" "%CORE_ROOT%" - -:SkipCoreRootSetup - -if not exist %CORE_ROOT%\coreclr.dll ( - echo %__MsgPrefix%Error: Ensure you have done a successful build of the Product and %CORE_ROOT% contains runtime binaries. - exit /b 1 -) - -REM ========================================================================================= -REM === -REM === Run normal (non-perf) tests -REM === -REM ========================================================================================= - -call :SetTestEnvironment - -call :ResolveDependencies -if errorlevel 1 exit /b 1 - -::Check if the test Binaries are built -if not exist %XunitTestBinBase% ( - echo %__MsgPrefix%Error: Ensure the Test Binaries are built and are present at %XunitTestBinBase%. - echo %__MsgPrefix%Run "buildtest.cmd %__BuildArch% %__BuildType%" to build the tests first. - exit /b 1 -) - -echo %__MsgPrefix%CORE_ROOT that will be used is: %CORE_ROOT% -echo %__MsgPrefix%Starting test run at %TIME% - -set __BuildLogRootName=TestRunResults -call :msbuild "%__ProjectFilesDir%\src\runtest.proj" /p:Runtests=true /clp:showcommandline -set __errorlevel=%errorlevel% - - -if %__errorlevel% GEQ 1 ( - echo %__MsgPrefix%Test Run failed. Refer to the following: - echo Html report: %__TestRunHtmlLog% - exit /b 1 -) - -goto TestsDone - -REM ========================================================================================= -REM === -REM === All tests complete! -REM === -REM ========================================================================================= - -:TestsDone - -echo %__MsgPrefix%Test run successful. Finished at %TIME%. Refer to the log files for details: -echo %__TestRunHtmlLog% -echo %__TestRunXmlLog% -exit /b 0 - -REM ========================================================================================= -REM === -REM === Subroutine to invoke msbuild. -REM === -REM === All arguments are passed to msbuild. The first argument should be the .proj file to invoke. -REM === -REM === On entry, environment variable __BuildLogRootName must be set to a file name prefix for the generated log files. -REM === All the "standard" environment variables that aren't expected to change per invocation must also be set, -REM === like __msbuildCommonArgs. -REM === -REM === The build log files will be overwritten, not appended to. -REM === -REM ========================================================================================= - -:msbuild - -echo %__MsgPrefix%Invoking msbuild - -set "__BuildLog=%__LogsDir%\%__BuildLogRootName%_%__TargetOS%__%__BuildArch%__%__BuildType%.log" -set "__BuildWrn=%__LogsDir%\%__BuildLogRootName%_%__TargetOS%__%__BuildArch%__%__BuildType%.wrn" -set "__BuildErr=%__LogsDir%\%__BuildLogRootName%_%__TargetOS%__%__BuildArch%__%__BuildType%.err" - -set __msbuildLogArgs=^ -/fileloggerparameters:Verbosity=normal;LogFile="%__BuildLog%";Append ^ -/fileloggerparameters1:WarningsOnly;LogFile="%__BuildWrn%" ^ -/fileloggerparameters2:ErrorsOnly;LogFile="%__BuildErr%" ^ -/consoleloggerparameters:Summary ^ -/verbosity:minimal - -set __msbuildArgs=%* %__msbuildCommonArgs% %__msbuildLogArgs% - -@REM The next line will overwrite the existing log file, if any. -echo %__MsgPrefix%"%DotNetCli%" msbuild %__msbuildArgs% -echo Invoking: "%DotNetCli%" msbuild %__msbuildArgs% > "%__BuildLog%" - -call "%DotNetCli%" msbuild %__msbuildArgs% -if errorlevel 1 ( - echo %__MsgPrefix%Error: msbuild failed. Refer to the log files for details: - echo %__BuildLog% - echo %__BuildWrn% - echo %__BuildErr% - exit /b 1 -) - -exit /b 0 - -REM ========================================================================================= -REM === -REM === Set various environment variables, based on arguments to this script, before invoking the tests. -REM === -REM ========================================================================================= - -:SetTestEnvironment - -:: Long GC tests take about 10 minutes per test on average, so -:: they often bump up against the default 10 minute timeout. -:: 20 minutes is more than enough time for a test to complete successfully. -if defined __LongGCTests ( - echo %__MsgPrefix%Running Long GC tests, extending timeout to 20 minutes - set __TestTimeout=1200000 - set RunningLongGCTests=1 -) - -:: GCSimulator tests can take up to an hour to complete. They are run twice a week in the -:: CI, so it's fine if they take a long time. -if defined __GCSimulatorTests ( - echo %__MsgPrefix%Running GCSimulator tests, extending timeout to one hour - set __TestTimeout=3600000 - set RunningGCSimulatorTests=1 -) - -if defined __IlasmRoundTrip ( - echo %__MsgPrefix%Running Ilasm round trip - set RunningIlasmRoundTrip=1 -) - -exit /b 0 - -REM ========================================================================================= -REM === -REM === Generate the "layout" directory in CORE_ROOT; download dependencies. -REM === -REM ========================================================================================= - -:ResolveDependencies - -set __BuildLogRootName=Tests_GenerateRuntimeLayout -call :msbuild "%__ProjectFilesDir%\src\runtest.proj" /p:GenerateRuntimeLayout=true -if errorlevel 1 ( - echo %__MsgPrefix%Test Dependency Resolution Failed - exit /b 1 -) -echo %__MsgPrefix%Created the runtime layout with all dependencies in %CORE_ROOT% - -exit /b 0 - REM ========================================================================================= REM === REM === Display a help message describing how to use this script. @@ -395,7 +203,8 @@ echo./? -? /h -h /help -help - View this message. echo ^ - Specifies build architecture: x64, x86, arm, or arm64 ^(default: x64^). echo ^ - Specifies build type: Debug, Release, or Checked ^(default: Debug^). echo TestEnv ^ - Run a custom script before every test to set custom test environment settings. -echo sequential - Run tests sequentially (no parallelism). +echo sequential - Run tests sequentially ^(no parallelism^). +echo parallel ^ - Run tests with given level of parallelism: none, collections, assemblies, all. Default: collections. echo RunCrossgen2Tests - Runs ReadytoRun tests compiled with Crossgen2 echo synthesizepgo - Enabled synthesizing PGO data in CrossGen2 echo jitstress ^ - Runs the tests with DOTNET_JitStress=n @@ -409,6 +218,7 @@ echo 2: GC on transitions to preemptive GC echo 4: GC on every allowable JITed instruction echo 8: GC on every allowable NGEN instruction echo 16: GC only on a unique stack trace +echo (Note that the value must be expresed in hex.) echo gcsimulator - Run the GC Simulator tests echo longgc - Run the long-running GC tests echo ilasmroundtrip - Runs ilasm round trip on the tests diff --git a/src/tests/run.py b/src/tests/run.py index 0680248f63b12..5e9f94a160459 100755 --- a/src/tests/run.py +++ b/src/tests/run.py @@ -75,6 +75,11 @@ prone to failure; however, copying into the Core_Root directory may create naming conflicts.""") +parallel_help = """ +Specify the level of parallelism: none, collections, assemblies, all. Default: collections. +`-parallel none` is a synonym for `--sequential`. +""" + parser = argparse.ArgumentParser(description=description) parser.add_argument("-os", dest="host_os", nargs='?', default=None) @@ -84,6 +89,7 @@ parser.add_argument("-core_root", dest="core_root", nargs='?', default=None) parser.add_argument("-runtime_repo_location", dest="runtime_repo_location", default=os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))) parser.add_argument("-test_env", dest="test_env", default=None) +parser.add_argument("-parallel", dest="parallel", default=None, help=parallel_help) # Optional arguments which change execution. @@ -567,6 +573,9 @@ def call_msbuild(args): common_msbuild_arguments = [] + if args.parallel: + common_msbuild_arguments += ["/p:ParallelRun={}".format(args.parallel)] + if args.sequential: common_msbuild_arguments += ["/p:ParallelRun=none"] @@ -956,11 +965,19 @@ def setup_args(args): print("Error, msbuild currently expects tests in {} (got test_location {})".format(normal_location, coreclr_setup_args.test_location)) raise Exception("Error, msbuild currently expects tests in artifacts/tests/...") + # valid_parallel_args is the same list as that allowed by the xunit.console.dll "-parallel" argument. + valid_parallel_args = ["none", "collections", "assemblies", "all"] + coreclr_setup_args.verify(args, "test_env", lambda arg: True, "Error setting test_env") + coreclr_setup_args.verify(args, + "parallel", + lambda arg: arg is None or arg in valid_parallel_args, + "Parallel argument '{}' unknown".format) + coreclr_setup_args.verify(args, "analyze_results_only", lambda arg: True, @@ -1041,6 +1058,9 @@ def setup_args(args): lambda arg: True, "Error setting run_nativeaot_tests") + if coreclr_setup_args.sequential and coreclr_setup_args.parallel: + print("Error: don't specify both --sequential and -parallel") + sys.exit(1) print("host_os : %s" % coreclr_setup_args.host_os) print("arch : %s" % coreclr_setup_args.arch) From ba777a8ba43dde51bda84a13e0b251492fb9770a Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sat, 15 Apr 2023 16:59:41 -0400 Subject: [PATCH 02/32] Update CodeAnalysis.src.globalconfig (#84059) - Update the names of rules to match the current ones defined in NetAnalyzers - Add a few more IDE rules, including enabling `IDE0280 Use nameof` --- eng/CodeAnalysis.src.globalconfig | 17 +++++++++++++---- eng/CodeAnalysis.test.globalconfig | 15 ++++++++++++--- .../src/Microsoft.Win32.Registry.csproj | 1 + .../src/System/Threading/Timer.cs | 2 +- .../Runtime/Serialization/SchemaImporter.cs | 2 +- .../Cryptography/Xml/SignedXmlDebugLog.cs | 2 +- .../gen/Reflection/RoslynExtensions.cs | 2 +- .../Linker.Steps/UnreachableBlocksOptimizer.cs | 8 ++++---- src/tools/illink/src/linker/Linker/Tracer.cs | 2 +- 9 files changed, 35 insertions(+), 16 deletions(-) diff --git a/eng/CodeAnalysis.src.globalconfig b/eng/CodeAnalysis.src.globalconfig index be4caadbb0dc9..d83299c431cce 100644 --- a/eng/CodeAnalysis.src.globalconfig +++ b/eng/CodeAnalysis.src.globalconfig @@ -348,7 +348,7 @@ dotnet_diagnostic.CA1816.severity = none dotnet_diagnostic.CA1819.severity = none # CA1820: Test for empty strings using string length -dotnet_diagnostic.CA1820.severity = none +dotnet_diagnostic.CA1820.severity = suggestion # CA1821: Remove empty Finalizers dotnet_diagnostic.CA1821.severity = warning @@ -468,7 +468,7 @@ dotnet_diagnostic.CA1858.severity = warning # CA1859: Use concrete types when possible for improved performance dotnet_diagnostic.CA1859.severity = warning -# CA1860: Prefer Length/Count/IsEmpty property check over Any() +# CA1860: Avoid using 'Enumerable.Any()' extension method dotnet_diagnostic.CA1860.severity = warning # CA2000: Dispose objects before losing scope @@ -513,7 +513,7 @@ dotnet_diagnostic.CA2018.severity = warning # CA2019: Improper 'ThreadStatic' field initialization dotnet_diagnostic.CA2019.severity = warning -# CA2020: Prevent behavioral changes +# CA2020: Prevent behavioral change dotnet_diagnostic.CA2020.severity = warning # CA2021: Do not call Enumerable.Cast or Enumerable.OfType with incompatible types @@ -769,7 +769,7 @@ dotnet_diagnostic.CA3061.severity = warning # CA3075: Insecure DTD processing in XML dotnet_diagnostic.CA3075.severity = warning -# CA3076: Insecure XSLT script processing. +# CA3076: Insecure XSLT script processing dotnet_diagnostic.CA3076.severity = warning # CA3077: Insecure Processing in API Design, XmlDocument and XmlTextReader @@ -1659,6 +1659,15 @@ dotnet_diagnostic.IDE0241.severity = suggestion # IDE0250: Make struct readonly dotnet_diagnostic.IDE0250.severity = suggestion +# IDE0260: Use pattern matching +dotnet_diagnostic.IDE0260.severity = suggestion + +# IDE0270: Use coalesce expression +dotnet_diagnostic.IDE0270.severity = suggestion + +# IDE0280: Use 'nameof' +dotnet_diagnostic.IDE0280.severity = warning + # IDE1005: Delegate invocation can be simplified. dotnet_diagnostic.IDE1005.severity = warning diff --git a/eng/CodeAnalysis.test.globalconfig b/eng/CodeAnalysis.test.globalconfig index b64207eeaf669..84c7837a7e536 100644 --- a/eng/CodeAnalysis.test.globalconfig +++ b/eng/CodeAnalysis.test.globalconfig @@ -465,7 +465,7 @@ dotnet_diagnostic.CA1858.severity = none # CA1859: Use concrete types when possible for improved performance dotnet_diagnostic.CA1859.severity = none -# CA1860: Prefer Length/Count/IsEmpty property check over Any() +# CA1860: Avoid using 'Enumerable.Any()' extension method dotnet_diagnostic.CA1860.severity = none # CA2000: Dispose objects before losing scope @@ -510,7 +510,7 @@ dotnet_diagnostic.CA2018.severity = none # CA2019: Improper 'ThreadStatic' field initialization dotnet_diagnostic.CA2019.severity = none -# CA2020: Prevent behavioral changes +# CA2020: Prevent behavioral change dotnet_diagnostic.CA2020.severity = none # CA2021: Do not call Enumerable.Cast or Enumerable.OfType with incompatible types @@ -765,7 +765,7 @@ dotnet_diagnostic.CA3061.severity = none # CA3075: Insecure DTD processing in XML dotnet_diagnostic.CA3075.severity = none -# CA3076: Insecure XSLT script processing. +# CA3076: Insecure XSLT script processing dotnet_diagnostic.CA3076.severity = none # CA3077: Insecure Processing in API Design, XmlDocument and XmlTextReader @@ -1653,6 +1653,15 @@ dotnet_diagnostic.IDE0241.severity = silent # IDE0250: Make struct readonly dotnet_diagnostic.IDE0250.severity = silent +# IDE0260: Use pattern matching +dotnet_diagnostic.IDE0260.severity = silent + +# IDE0270: Use coalesce expression +dotnet_diagnostic.IDE0270.severity = silent + +# IDE0280: Use 'nameof' +dotnet_diagnostic.IDE0280.severity = silent + # IDE1005: Delegate invocation can be simplified. dotnet_diagnostic.IDE1005.severity = silent diff --git a/src/libraries/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj b/src/libraries/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj index 5920905308d2f..987e8547b27f0 100644 --- a/src/libraries/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj +++ b/src/libraries/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj @@ -9,6 +9,7 @@ $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) SR.PlatformNotSupported_Registry + $(NoWarn);IDE0280 ? typ [RequiresDynamicCode(DataContract.SerializerAOTWarning)] [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal void Import([NotNullIfNotNull("_elements")] out List? elementTypeNames) + internal void Import([NotNullIfNotNull(nameof(_elements))] out List? elementTypeNames) { elementTypeNames = null!; diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs index ae73934b34358..64268c03726a8 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs @@ -572,7 +572,7 @@ internal static void LogNamespacePropagation(SignedXml signedXml, XmlNodeList? n /// The reference being processed /// Stream containing the output of the reference /// Stream containing the output of the reference - [return: NotNullIfNotNull("data")] + [return: NotNullIfNotNull(nameof(data))] internal static Stream? LogReferenceData(Reference reference, Stream? data) { if (VerboseLoggingEnabled) diff --git a/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs b/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs index 7add066f09380..3964d53ab4f48 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs @@ -10,7 +10,7 @@ namespace System.Text.Json.Reflection { internal static class RoslynExtensions { - [return: NotNullIfNotNull("typeSymbol")] + [return: NotNullIfNotNull(nameof(typeSymbol))] public static Type? AsType(this ITypeSymbol? typeSymbol, MetadataLoadContextInternal metadataLoadContext) { if (typeSymbol == null) diff --git a/src/tools/illink/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs b/src/tools/illink/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs index 2d9097f975df4..3612aaa3d3cb8 100644 --- a/src/tools/illink/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs +++ b/src/tools/illink/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs @@ -571,8 +571,8 @@ public BodyReducer (MethodBody body, LinkContext context) Collection? FoldedInstructions { get; set; } - [MemberNotNull ("FoldedInstructions")] - [MemberNotNull ("mapping")] + [MemberNotNull (nameof(FoldedInstructions))] + [MemberNotNull (nameof(mapping))] void InitializeFoldedInstruction () { FoldedInstructions = new Collection (Instructions); @@ -1475,7 +1475,7 @@ public ConstantExpressionMethodAnalyzer (UnreachableBlocksOptimizer optimizer) // public bool SideEffectFreeResult { get; private set; } - [MemberNotNullWhen (true, "Result")] + [MemberNotNullWhen (true, nameof(Result))] public bool Analyze (in CalleePayload callee, Stack callStack) { MethodDefinition method = callee.Method; @@ -1852,7 +1852,7 @@ bool EvaluateConditionalJump (Instruction instr, out Instruction? target) return false; } - [MemberNotNullWhen (true, "Result")] + [MemberNotNullWhen (true, nameof(Result))] bool ConvertStackToResult () { if (stack_instr == null) diff --git a/src/tools/illink/src/linker/Linker/Tracer.cs b/src/tools/illink/src/linker/Linker/Tracer.cs index 15bd8a4b342e1..854f2ecdced04 100644 --- a/src/tools/illink/src/linker/Linker/Tracer.cs +++ b/src/tools/illink/src/linker/Linker/Tracer.cs @@ -66,7 +66,7 @@ public void AddRecorder (IDependencyRecorder recorder) recorders.Add (recorder); } - [MemberNotNullWhen (true, "recorders")] + [MemberNotNullWhen (true, nameof(recorders))] bool IsRecordingEnabled () { return recorders != null; From 90f8078bd3c4979c17596e30578a79fdef449f7c Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Sat, 15 Apr 2023 14:43:07 -0700 Subject: [PATCH 03/32] JIT: enable one particular flow opt when we have PGO (#84875) This particular optimization seems to be a good idea, so not sure why the code was unwilling to do it if we had profile data. This optimization removes a "branch around": `` BlockA: jtrue (p) BlockC BlockB: {empty} jmp BlockD BlockC: ... ... BlockD: ... ``` becomes ``` BlockA: jtrue (!p) BlockD BlockC: ... ... BlockD: ... ``` If later during code layout we decide we'd rather have ``` BlockA: jtrue (p) BlockC BlockD: ... ... BlockC: ... ``` we can still make that happen. --- src/coreclr/jit/fgopt.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp index eb0605667a0ee..526cea6443d4b 100644 --- a/src/coreclr/jit/fgopt.cpp +++ b/src/coreclr/jit/fgopt.cpp @@ -2776,15 +2776,6 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc optimizeJump = true; } - // If we are optimizing using real profile weights - // then don't optimize a conditional jump to an unconditional jump - // until after we have computed the edge weights - // - if (fgIsUsingProfileWeights() && !fgEdgeWeightsComputed) - { - optimizeJump = false; - } - if (optimizeJump) { #ifdef DEBUG @@ -3156,15 +3147,6 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block) optimizeJump = false; } - // If we are optimize using real profile weights - // then don't optimize a switch jump to an unconditional jump - // until after we have computed the edge weights - // - if (fgIsUsingProfileWeights() && !fgEdgeWeightsComputed) - { - optimizeJump = false; - } - if (optimizeJump) { bNewDest = bDest->bbJumpDest; From d3fc489b89d3e8dfce91cb75c42812a0a95352b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Sun, 16 Apr 2023 10:36:16 +0900 Subject: [PATCH 04/32] Make `MethodTable` base size access more "typed" (#84823) * Make `MethodTable` base size access more "typed" We reuse the base size field for other purposes for `MethodTable`s that cannot actually exist on heap (otherwise GC needs this to be legit). I almost reused it for similar reasons for function pointers, but looks like we don't need it for those, so just submitting these asserts that we don't read the wrong meaning of the field. * FB * Optimize MethodTable.CorElementType property --------- Co-authored-by: Jan Kotas --- .../src/Internal/Runtime/MethodTable.cs | 38 ++++----- .../src/System/Runtime/EETypePtr.cs | 8 -- .../src/System/Array.NativeAot.cs | 12 +-- .../src/System/EETypePtr.cs | 77 ++++++++++--------- .../MemoryMarshal.NativeAot.cs | 2 +- .../Runtime/TypeLoader/EETypeCreator.cs | 4 +- .../Runtime/TypeLoader/TypeBuilder.cs | 2 +- 7 files changed, 67 insertions(+), 76 deletions(-) diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs index 74cf978e2dedb..ccf4cd6399b36 100644 --- a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs +++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs @@ -357,10 +357,25 @@ internal ushort ExtendedFlags #endif } + internal uint RawBaseSize + { + get + { + return _uBaseSize; + } +#if TYPE_LOADER_IMPLEMENTATION + set + { + _uBaseSize = value; + } +#endif + } + internal uint BaseSize { get { + Debug.Assert(IsCanonical || IsArray); return _uBaseSize; } #if TYPE_LOADER_IMPLEMENTATION @@ -503,7 +518,8 @@ internal bool IsSzArray { get { - return ElementType == EETypeElementType.SzArray; + Debug.Assert(IsArray); + return BaseSize == SZARRAY_BASE_SIZE; } } @@ -713,6 +729,7 @@ internal uint ParameterizedTypeShape { get { + Debug.Assert(IsParameterizedType); return _uBaseSize; } #if TYPE_LOADER_IMPLEMENTATION @@ -833,22 +850,6 @@ internal uint ValueTypeSize } } - internal uint FieldByteCountNonGCAligned - { - get - { - // This api is designed to return correct results for EETypes which can be derived from - // And results indistinguishable from correct for DefTypes which cannot be derived from (sealed classes) - // (For sealed classes, this should always return BaseSize-((uint)sizeof(ObjHeader)); - Debug.Assert(!IsInterface && !IsParameterizedType); - - // get_BaseSize returns the GC size including space for the sync block index field, the MethodTable* and - // padding for GC heap alignment. Must subtract all of these to get the size used for the fields of - // the type (where the fields of the type includes the MethodTable*) - return BaseSize - ((uint)sizeof(ObjHeader) + ValueTypeFieldPadding); - } - } - internal EEInterfaceInfo* InterfaceMap { get @@ -1337,7 +1338,8 @@ internal EETypeElementType ElementType { get { - return (EETypeElementType)((_uFlags & (uint)EETypeFlags.ElementTypeMask) >> (byte)EETypeFlags.ElementTypeShift); + return (EETypeElementType)((_uFlags >> (byte)EETypeFlags.ElementTypeShift) & + ((uint)EETypeFlags.ElementTypeMask >> (byte)EETypeFlags.ElementTypeShift)); } #if TYPE_LOADER_IMPLEMENTATION set diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/EETypePtr.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/EETypePtr.cs index 4252397ed0811..8dc8889325743 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/EETypePtr.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/EETypePtr.cs @@ -44,13 +44,5 @@ internal static EETypePtr EETypePtrOf() { throw new NotImplementedException(); } - - internal unsafe uint BaseSize - { - get - { - return ToPointer()->BaseSize; - } - } } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs index 5db1d3e9134a7..1c594aa928132 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs @@ -32,14 +32,6 @@ public abstract partial class Array : ICollection, IEnumerable, IList, IStructur private int _numComponents; #pragma warning restore -#if TARGET_64BIT - private const int POINTER_SIZE = 8; -#else - private const int POINTER_SIZE = 4; -#endif - // Header + m_pEEType + _numComponents (with an optional padding) - private const int SZARRAY_BASE_SIZE = POINTER_SIZE + POINTER_SIZE + POINTER_SIZE; - public int Length => checked((int)Unsafe.As(this).Length); // This could return a length greater than int.MaxValue @@ -47,11 +39,11 @@ public abstract partial class Array : ICollection, IEnumerable, IList, IStructur public long LongLength => (long)NativeLength; - internal bool IsSzArray + internal unsafe bool IsSzArray { get { - return this.GetEETypePtr().BaseSize == SZARRAY_BASE_SIZE; + return this.GetMethodTable()->IsSzArray; } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs index 70b85c6a0416c..8771fd0a30e71 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/EETypePtr.cs @@ -310,14 +310,6 @@ internal EETypePtr BaseType } } - internal uint BaseSize - { - get - { - return _value->BaseSize; - } - } - internal IntPtr DispatchMap { get @@ -347,34 +339,47 @@ internal CorElementType CorElementType { get { - Debug.Assert((int)CorElementType.ELEMENT_TYPE_BOOLEAN == (int)EETypeElementType.Boolean); - Debug.Assert((int)CorElementType.ELEMENT_TYPE_I1 == (int)EETypeElementType.SByte); - Debug.Assert((int)CorElementType.ELEMENT_TYPE_I8 == (int)EETypeElementType.Int64); - EETypeElementType elementType = ElementType; - - if (elementType <= EETypeElementType.UInt64) - return (CorElementType)elementType; - else if (elementType == EETypeElementType.Single) - return CorElementType.ELEMENT_TYPE_R4; - else if (elementType == EETypeElementType.Double) - return CorElementType.ELEMENT_TYPE_R8; - else if (elementType == EETypeElementType.IntPtr) - return CorElementType.ELEMENT_TYPE_I; - else if (elementType == EETypeElementType.UIntPtr) - return CorElementType.ELEMENT_TYPE_U; - else if (IsValueType) - return CorElementType.ELEMENT_TYPE_VALUETYPE; - else if (IsByRef) - return CorElementType.ELEMENT_TYPE_BYREF; - else if (IsPointer) - return CorElementType.ELEMENT_TYPE_PTR; - else if (IsSzArray) - return CorElementType.ELEMENT_TYPE_SZARRAY; - else if (IsArray) - return CorElementType.ELEMENT_TYPE_ARRAY; - else - return CorElementType.ELEMENT_TYPE_CLASS; - + ReadOnlySpan map = new byte[] + { + default, + (byte)CorElementType.ELEMENT_TYPE_VOID, // EETypeElementType.Void + (byte)CorElementType.ELEMENT_TYPE_BOOLEAN, // EETypeElementType.Boolean + (byte)CorElementType.ELEMENT_TYPE_CHAR, // EETypeElementType.Char + (byte)CorElementType.ELEMENT_TYPE_I1, // EETypeElementType.SByte + (byte)CorElementType.ELEMENT_TYPE_U1, // EETypeElementType.Byte + (byte)CorElementType.ELEMENT_TYPE_I2, // EETypeElementType.Int16 + (byte)CorElementType.ELEMENT_TYPE_U2, // EETypeElementType.UInt16 + (byte)CorElementType.ELEMENT_TYPE_I4, // EETypeElementType.Int32 + (byte)CorElementType.ELEMENT_TYPE_U4, // EETypeElementType.UInt32 + (byte)CorElementType.ELEMENT_TYPE_I8, // EETypeElementType.Int64 + (byte)CorElementType.ELEMENT_TYPE_U8, // EETypeElementType.UInt64 + (byte)CorElementType.ELEMENT_TYPE_I, // EETypeElementType.IntPtr + (byte)CorElementType.ELEMENT_TYPE_U, // EETypeElementType.UIntPtr + (byte)CorElementType.ELEMENT_TYPE_R4, // EETypeElementType.Single + (byte)CorElementType.ELEMENT_TYPE_R8, // EETypeElementType.Double + + (byte)CorElementType.ELEMENT_TYPE_VALUETYPE, // EETypeElementType.ValueType + (byte)CorElementType.ELEMENT_TYPE_VALUETYPE, + (byte)CorElementType.ELEMENT_TYPE_VALUETYPE, // EETypeElementType.Nullable + (byte)CorElementType.ELEMENT_TYPE_VALUETYPE, + (byte)CorElementType.ELEMENT_TYPE_CLASS, // EETypeElementType.Class + (byte)CorElementType.ELEMENT_TYPE_CLASS, // EETypeElementType.Interface + (byte)CorElementType.ELEMENT_TYPE_CLASS, // EETypeElementType.SystemArray + (byte)CorElementType.ELEMENT_TYPE_ARRAY, // EETypeElementType.Array + (byte)CorElementType.ELEMENT_TYPE_SZARRAY, // EETypeElementType.SzArray + (byte)CorElementType.ELEMENT_TYPE_BYREF, // EETypeElementType.ByRef + (byte)CorElementType.ELEMENT_TYPE_PTR, // EETypeElementType.Pointer + default, // Pad the map to 32 elements to enable range check elimination + default, + default, + default, + default + }; + + // Verify last element of the map + Debug.Assert((byte)CorElementType.ELEMENT_TYPE_PTR == map[(int)EETypeElementType.Pointer]); + + return (CorElementType)map[(int)ElementType]; } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.NativeAot.cs index 5d97217a13c8b..19e4a2a663619 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.NativeAot.cs @@ -41,7 +41,7 @@ public static ref byte GetArrayDataReference(Array array) // to special-case arrays of known type and dimension. // See comment on RawArrayData (in RuntimeHelpers.CoreCLR.cs) for details - return ref Unsafe.AddByteOffset(ref Unsafe.As(array).Data, (nuint)array.GetEETypePtr().BaseSize - (nuint)(2 * sizeof(IntPtr))); + return ref Unsafe.AddByteOffset(ref Unsafe.As(array).Data, (nuint)array.GetMethodTable()->BaseSize - (nuint)(2 * sizeof(IntPtr))); } } } diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs index 73aac9a149817..0f7ec21048475 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/EETypeCreator.cs @@ -177,7 +177,7 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo runtimeInterfacesLength = checked((ushort)state.RuntimeInterfaces.Length); } - baseSize = (int)pTemplateEEType->BaseSize; + baseSize = (int)pTemplateEEType->RawBaseSize; isValueType = pTemplateEEType->IsValueType; hasFinalizer = pTemplateEEType->IsFinalizable; isNullable = pTemplateEEType->IsNullable; @@ -269,7 +269,7 @@ private static void CreateEETypeWorker(MethodTable* pTemplateEEType, uint hashCo // Set basic MethodTable fields pEEType->Flags = flags; - pEEType->BaseSize = (uint)baseSize; + pEEType->RawBaseSize = (uint)baseSize; pEEType->NumVtableSlots = numVtableSlots; pEEType->NumInterfaces = runtimeInterfacesLength; pEEType->HashCode = hashCodeOfNewType; diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs index f6674fb35624e..627f9f95b1038 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeBuilder.cs @@ -597,7 +597,7 @@ private unsafe void AllocateRuntimeType(TypeDesc type) if (state.ThreadDataSize != 0) TypeLoaderEnvironment.Instance.RegisterDynamicThreadStaticsInfo(state.HalfBakedRuntimeTypeHandle, state.ThreadStaticOffset, state.ThreadStaticDesc); - TypeLoaderLogger.WriteLine("Allocated new type " + type.ToString() + " with hashcode value = 0x" + type.GetHashCode().LowLevelToString() + " with MethodTable = " + rtt.ToIntPtr().LowLevelToString() + " of size " + rtt.ToEETypePtr()->BaseSize.LowLevelToString()); + TypeLoaderLogger.WriteLine("Allocated new type " + type.ToString() + " with hashcode value = 0x" + type.GetHashCode().LowLevelToString() + " with MethodTable = " + rtt.ToIntPtr().LowLevelToString() + " of size " + rtt.ToEETypePtr()->RawBaseSize.LowLevelToString()); } private static void AllocateRuntimeMethodDictionary(InstantiatedMethod method) From 8cb3bf89e4b28b66bf3b4e2957fd015bf925a787 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Sat, 15 Apr 2023 18:56:43 -0700 Subject: [PATCH 05/32] Fix stepping by removing the unnecessary logic in VirtualCallStubManagerManager (#84869) --- src/coreclr/vm/virtualcallstub.cpp | 56 +++--------------------------- 1 file changed, 4 insertions(+), 52 deletions(-) diff --git a/src/coreclr/vm/virtualcallstub.cpp b/src/coreclr/vm/virtualcallstub.cpp index 26d55c4c07d6d..32a963787e02e 100644 --- a/src/coreclr/vm/virtualcallstub.cpp +++ b/src/coreclr/vm/virtualcallstub.cpp @@ -863,6 +863,7 @@ VirtualCallStubManager *VirtualCallStubManager::FindStubManager(PCODE stubAddres NOTHROW; GC_NOTRIGGER; FORBID_FAULT; + SUPPORTS_DAC; } CONTRACTL_END StubCodeBlockKind unusedStubKind; @@ -3696,56 +3697,7 @@ VirtualCallStubManager *VirtualCallStubManagerManager::FindVirtualCallStubManage SUPPORTS_DAC; -#ifndef DACCESS_COMPILE - // Check the cached element - { - VirtualCallStubManager *pMgr = m_pCacheElem; - if (pMgr != NULL && pMgr->CheckIsStub_Internal(stubAddress)) - { - return pMgr; - } - } - - // Check the current and shared domains. - { - Thread *pThread = GetThreadNULLOk(); - if (pThread != NULL) - { - // Check the current domain - { - BaseDomain *pDom = pThread->GetDomain(); - VirtualCallStubManager *pMgr = pDom->GetLoaderAllocator()->GetVirtualCallStubManager(); - if (pMgr->CheckIsStub_Internal(stubAddress)) - { - m_pCacheElem = pMgr; - return pMgr; - } - } - } - } -#endif - - // If both previous attempts fail, run through the list. This is likely - // because the thread is a debugger thread running outside of the domain - // that owns the target stub. - { - VirtualCallStubManagerIterator it = - VirtualCallStubManagerManager::GlobalManager()->IterateVirtualCallStubManagers(); - - while (it.Next()) - { - if (it.Current()->CheckIsStub_Internal(stubAddress)) - { -#ifndef DACCESS_COMPILE - m_pCacheElem = it.Current(); -#endif - return it.Current(); - } - } - } - - // No VirtualCallStubManager owns this address. - return NULL; + return VirtualCallStubManager::FindStubManager(stubAddress); } static VirtualCallStubManager * const IT_START = (VirtualCallStubManager *)(-1); @@ -3818,8 +3770,8 @@ BOOL VirtualCallStubManagerManager::CheckIsStub_Internal( WRAPPER_NO_CONTRACT; SUPPORTS_DAC; - VirtualCallStubManager *pMgr = FindVirtualCallStubManager(stubStartAddress); - return (pMgr != NULL); + // Forwarded to from RangeSectionStubManager + return FALSE; } ///////////////////////////////////////////////////////////////////////////////////////////// From eafd523bc82cf739b2d04bae55b3a3ceaad6a0f3 Mon Sep 17 00:00:00 2001 From: Meri Khamoyan <96171496+mkhamoyan@users.noreply.github.com> Date: Sun, 16 Apr 2023 17:54:35 +0400 Subject: [PATCH 06/32] [OSX] HybridGlobalization implement locale native functions (#84417) Implementations for native functions local int, grouping size and timeformat --- .../Common/src/Interop/Interop.Locale.OSX.cs | 16 +- .../tests/Hybrid/Hybrid.IOS.Tests.csproj | 28 +- .../System/Globalization/CultureData.OSX.cs | 110 ++++- .../System/Globalization/CultureData.Unix.cs | 11 +- .../src/System/Globalization/CultureData.cs | 22 +- .../System.Globalization.Native/entrypoints.c | 4 + .../System.Globalization.Native/pal_locale.c | 22 + .../System.Globalization.Native/pal_locale.h | 14 +- .../System.Globalization.Native/pal_locale.m | 429 +++++++++++++++++- .../pal_localeNumberData.h | 11 + .../pal_localeStringData.c | 21 - .../pal_localeStringData.h | 6 +- .../pal_locale_internal.h | 18 - 13 files changed, 648 insertions(+), 64 deletions(-) diff --git a/src/libraries/Common/src/Interop/Interop.Locale.OSX.cs b/src/libraries/Common/src/Interop/Interop.Locale.OSX.cs index 52882346b6322..0f7b1763d5850 100644 --- a/src/libraries/Common/src/Interop/Interop.Locale.OSX.cs +++ b/src/libraries/Common/src/Interop/Interop.Locale.OSX.cs @@ -8,9 +8,21 @@ internal static partial class Interop internal static partial class Globalization { [LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetLocaleNameNative", StringMarshalling = StringMarshalling.Utf8)] - internal static unsafe partial string GetLocaleNameNative(string localeName); + internal static partial string GetLocaleNameNative(string localeName); [LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetLocaleInfoStringNative", StringMarshalling = StringMarshalling.Utf8)] - internal static unsafe partial string GetLocaleInfoStringNative(string localeName, uint localeStringData); + internal static partial string GetLocaleInfoStringNative(string localeName, uint localeStringData); + + [LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetLocaleInfoIntNative", StringMarshalling = StringMarshalling.Utf8)] + internal static partial int GetLocaleInfoIntNative(string localeName, uint localeNumberData); + + [LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetLocaleInfoPrimaryGroupingSizeNative", StringMarshalling = StringMarshalling.Utf8)] + internal static partial int GetLocaleInfoPrimaryGroupingSizeNative(string localeName, uint localeGroupingData); + + [LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetLocaleInfoSecondaryGroupingSizeNative", StringMarshalling = StringMarshalling.Utf8)] + internal static partial int GetLocaleInfoSecondaryGroupingSizeNative(string localeName, uint localeGroupingData); + + [LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetLocaleTimeFormatNative", StringMarshalling = StringMarshalling.Utf8)] + internal static partial string GetLocaleTimeFormatNative(string localeName, [MarshalAs(UnmanagedType.Bool)] bool shortFormat); } } diff --git a/src/libraries/System.Globalization/tests/Hybrid/Hybrid.IOS.Tests.csproj b/src/libraries/System.Globalization/tests/Hybrid/Hybrid.IOS.Tests.csproj index b2622d1a6afb9..b9887c1021aaf 100644 --- a/src/libraries/System.Globalization/tests/Hybrid/Hybrid.IOS.Tests.csproj +++ b/src/libraries/System.Globalization/tests/Hybrid/Hybrid.IOS.Tests.csproj @@ -1,10 +1,36 @@ - $(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-osx + $(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-maccatalyst true true + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.OSX.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.OSX.cs index 870d8504fb967..cdbdd65a81426 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.OSX.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.OSX.cs @@ -7,21 +7,23 @@ namespace System.Globalization { internal sealed partial class CultureData { + private const int LOC_FULLNAME_CAPACITY = 157; // max size of locale name + /// /// This method uses the sRealName field (which is initialized by the constructor before this is called) to /// initialize the rest of the state of CultureData based on the underlying OS globalization library. /// - private bool InitNativeCultureDataCore() + private bool InitAppleCultureDataCore() { Debug.Assert(_sRealName != null); Debug.Assert(!GlobalizationMode.Invariant); string realNameBuffer = _sRealName; - _sWindowsName = GetLocaleNameNative(realNameBuffer); + _sWindowsName = _sName = _sRealName = GetLocaleNameNative(realNameBuffer); return true; } - internal static unsafe string GetLocaleNameNative(string localeName) + internal static string GetLocaleNameNative(string localeName) { return Interop.Globalization.GetLocaleNameNative(localeName); } @@ -36,11 +38,111 @@ private string GetLocaleInfoNative(LocaleStringData type) // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the // "windows" name, which can be specific for downlevel (< windows 7) os's. - private static unsafe string GetLocaleInfoNative(string localeName, LocaleStringData type) + private static string GetLocaleInfoNative(string localeName, LocaleStringData type) { Debug.Assert(localeName != null, "[CultureData.GetLocaleInfoNative] Expected localeName to be not be null"); return Interop.Globalization.GetLocaleInfoStringNative(localeName, (uint)type); } + + private int GetLocaleInfoNative(LocaleNumberData type) + { + Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfoNative(LocaleNumberData)] Expected _sWindowsName to be populated already"); + + // returning 0 will cause the first supported calendar to be returned, which is the preferred calendar + if (type == LocaleNumberData.CalendarType) + return 0; + + int value = Interop.Globalization.GetLocaleInfoIntNative(_sWindowsName, (uint)type); + const int DEFAULT_VALUE = 0; + if (value < 0) + { + Debug.Fail("[CultureData.GetLocaleInfoNative(LocaleNumberData)] failed"); + return DEFAULT_VALUE; + } + + return value; + } + + private int[] GetLocaleInfoNative(LocaleGroupingData type) + { + Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfoNative(LocaleGroupingData)] Expected _sWindowsName to be populated already"); + + int primaryGroupingSize = Interop.Globalization.GetLocaleInfoPrimaryGroupingSizeNative(_sWindowsName, (uint)type); + int secondaryGroupingSize = Interop.Globalization.GetLocaleInfoSecondaryGroupingSizeNative(_sWindowsName, (uint)type); + + if (secondaryGroupingSize == 0) + { + return new int[] { primaryGroupingSize }; + } + + return new int[] { primaryGroupingSize, secondaryGroupingSize }; + } + + private string GetTimeFormatStringNative() => GetTimeFormatStringNative(shortFormat: false); + + private string GetTimeFormatStringNative(bool shortFormat) + { + Debug.Assert(_sWindowsName != null, "[CultureData.GetTimeFormatStringNative(bool shortFormat)] Expected _sWindowsName to be populated already"); + + string result = Interop.Globalization.GetLocaleTimeFormatNative(_sWindowsName, shortFormat); + + return ConvertNativeTimeFormatString(result); + } + + private static string ConvertNativeTimeFormatString(string nativeFormatString) + { + Span result = stackalloc char[LOC_FULLNAME_CAPACITY]; + + bool amPmAdded = false; + int resultPos = 0; + + for (int i = 0; i < nativeFormatString.Length; i++) + { + switch (nativeFormatString[i]) + { + case '\'': + result[resultPos++] = nativeFormatString[i++]; + while (i < nativeFormatString.Length) + { + char current = nativeFormatString[i]; + result[resultPos++] = current; + if (current == '\'') + { + break; + } + i++; + } + break; + + case ':': + case '.': + case 'H': + case 'h': + case 'm': + case 's': + result[resultPos++] = nativeFormatString[i]; + break; + + case ' ': + case '\u00A0': + // Convert nonbreaking spaces into regular spaces + result[resultPos++] = ' '; + break; + + case 'a': // AM/PM + if (!amPmAdded) + { + amPmAdded = true; + result[resultPos++] = 't'; + result[resultPos++] = 't'; + } + break; + + } + } + + return result.Slice(0, resultPos).ToString(); + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs index 2a253d5367be3..76c009beb6466 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs @@ -7,7 +7,12 @@ namespace System.Globalization { internal sealed partial class CultureData { - private bool InitCultureDataCore() => InitIcuCultureDataCore(); + private bool InitCultureDataCore() => +#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS + GlobalizationMode.Hybrid ? InitAppleCultureDataCore() : InitIcuCultureDataCore(); +#else + InitIcuCultureDataCore(); +#endif // Unix doesn't support user overrides partial void InitUserOverride(bool useUserOverride); @@ -20,7 +25,11 @@ internal sealed partial class CultureData private string[]? GetTimeFormatsCore(bool shortFormat) { +#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS + string format = GlobalizationMode.Hybrid ? GetTimeFormatStringNative(shortFormat) : IcuGetTimeFormatString(shortFormat); +#else string format = IcuGetTimeFormatString(shortFormat); +#endif return new string[] { format }; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs index 92037366b6389..12ea4ded8beed 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs @@ -1541,7 +1541,11 @@ internal int FirstDayOfWeek { if (_iFirstDayOfWeek == undef && !GlobalizationMode.Invariant) { +#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS + _iFirstDayOfWeek = GlobalizationMode.Hybrid ? GetLocaleInfoNative(LocaleNumberData.FirstDayOfWeek) : IcuGetLocaleInfo(LocaleNumberData.FirstDayOfWeek); +#else _iFirstDayOfWeek = ShouldUseUserOverrideNlsData ? NlsGetFirstDayOfWeek() : IcuGetLocaleInfo(LocaleNumberData.FirstDayOfWeek); +#endif } return _iFirstDayOfWeek; } @@ -1949,7 +1953,11 @@ internal string TimeSeparator } else { +#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS + string? longTimeFormat = GlobalizationMode.Hybrid ? GetTimeFormatStringNative() : IcuGetTimeFormatString(); +#else string? longTimeFormat = ShouldUseUserOverrideNlsData ? NlsGetTimeFormatString() : IcuGetTimeFormatString(); +#endif if (string.IsNullOrEmpty(longTimeFormat)) { longTimeFormat = LongTimes[0]; @@ -2285,8 +2293,11 @@ private int GetLocaleInfoCore(LocaleNumberData type) // This is never reached but helps illinker statically remove dependencies if (GlobalizationMode.Invariant) return 0; - +#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS + return GlobalizationMode.Hybrid ? GetLocaleInfoNative(type) : IcuGetLocaleInfo(type); +#else return GlobalizationMode.UseNls ? NlsGetLocaleInfo(type) : IcuGetLocaleInfo(type); +#endif } private int GetLocaleInfoCoreUserOverride(LocaleNumberData type) @@ -2294,8 +2305,11 @@ private int GetLocaleInfoCoreUserOverride(LocaleNumberData type) // This is never reached but helps illinker statically remove dependencies if (GlobalizationMode.Invariant) return 0; - +#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS + return GlobalizationMode.Hybrid ? GetLocaleInfoNative(type) : IcuGetLocaleInfo(type); +#else return ShouldUseUserOverrideNlsData ? NlsGetLocaleInfo(type) : IcuGetLocaleInfo(type); +#endif } private string GetLocaleInfoCoreUserOverride(LocaleStringData type) @@ -2343,7 +2357,11 @@ private int[] GetLocaleInfoCoreUserOverride(LocaleGroupingData type) if (GlobalizationMode.Invariant) return null!; +#if TARGET_OSX || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS + return GlobalizationMode.Hybrid ? GetLocaleInfoNative(type) : IcuGetLocaleInfo(type); +#else return ShouldUseUserOverrideNlsData ? NlsGetLocaleInfo(type) : IcuGetLocaleInfo(type); +#endif } /// diff --git a/src/native/libs/System.Globalization.Native/entrypoints.c b/src/native/libs/System.Globalization.Native/entrypoints.c index 10254d6256db4..c3c65b2196cde 100644 --- a/src/native/libs/System.Globalization.Native/entrypoints.c +++ b/src/native/libs/System.Globalization.Native/entrypoints.c @@ -61,6 +61,10 @@ static const Entry s_globalizationNative[] = #ifdef __APPLE__ DllImportEntry(GlobalizationNative_GetLocaleNameNative) DllImportEntry(GlobalizationNative_GetLocaleInfoStringNative) + DllImportEntry(GlobalizationNative_GetLocaleInfoIntNative) + DllImportEntry(GlobalizationNative_GetLocaleInfoPrimaryGroupingSizeNative) + DllImportEntry(GlobalizationNative_GetLocaleInfoSecondaryGroupingSizeNative) + DllImportEntry(GlobalizationNative_GetLocaleTimeFormatNative) #endif }; diff --git a/src/native/libs/System.Globalization.Native/pal_locale.c b/src/native/libs/System.Globalization.Native/pal_locale.c index eada9f12ddd39..ccae3e0c6d989 100644 --- a/src/native/libs/System.Globalization.Native/pal_locale.c +++ b/src/native/libs/System.Globalization.Native/pal_locale.c @@ -277,3 +277,25 @@ int32_t GlobalizationNative_IsPredefinedLocale(const UChar* localeName) return err == U_ZERO_ERROR; } + +/* +PAL Function: +GetLocaleTimeFormat + +Obtains time format information (in ICU format, it needs to be converted to .NET's format). +Returns 1 for success, 0 otherwise +*/ +int32_t GlobalizationNative_GetLocaleTimeFormat(const UChar* localeName, + int shortFormat, + UChar* value, + int32_t valueLength) +{ + UErrorCode err = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); + UDateFormatStyle style = (shortFormat != 0) ? UDAT_SHORT : UDAT_MEDIUM; + UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale, NULL, 0, NULL, 0, &err); + udat_toPattern(pFormat, false, value, valueLength, &err); + udat_close(pFormat); + return UErrorCodeToBool(err); +} diff --git a/src/native/libs/System.Globalization.Native/pal_locale.h b/src/native/libs/System.Globalization.Native/pal_locale.h index 7ee6d1e7ee56e..7fe89f667f213 100644 --- a/src/native/libs/System.Globalization.Native/pal_locale.h +++ b/src/native/libs/System.Globalization.Native/pal_locale.h @@ -9,10 +9,16 @@ PALEXPORT int32_t GlobalizationNative_GetLocales(UChar *value, int32_t valueLeng PALEXPORT int32_t GlobalizationNative_GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength); -#ifdef __APPLE__ -PALEXPORT const char* GlobalizationNative_GetLocaleNameNative(const char* localeName); -#endif - PALEXPORT int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_t valueLength); PALEXPORT int32_t GlobalizationNative_IsPredefinedLocale(const UChar* localeName); + +PALEXPORT int32_t GlobalizationNative_GetLocaleTimeFormat(const UChar* localeName, + int shortFormat, UChar* value, + int32_t valueLength); + +#ifdef __APPLE__ +PALEXPORT const char* GlobalizationNative_GetLocaleNameNative(const char* localeName); + +PALEXPORT const char* GlobalizationNative_GetLocaleTimeFormatNative(const char* localeName, int shortFormat); +#endif diff --git a/src/native/libs/System.Globalization.Native/pal_locale.m b/src/native/libs/System.Globalization.Native/pal_locale.m index 7400c48b1c9ba..66b951db76125 100644 --- a/src/native/libs/System.Globalization.Native/pal_locale.m +++ b/src/native/libs/System.Globalization.Native/pal_locale.m @@ -4,6 +4,7 @@ #include #include "pal_locale_internal.h" #include "pal_localeStringData.h" +#include "pal_localeNumberData.h" #import #import @@ -34,10 +35,10 @@ const char* GlobalizationNative_GetLocaleNameNative(const char* localeName) { - NSString *locName = [NSString stringWithFormat:@"%s", localeName]; - NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; - const char* value = [currentLocale.localeIdentifier UTF8String]; - return strdup(value); + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + const char* value = [currentLocale.localeIdentifier UTF8String]; + return strdup(value); } const char* GlobalizationNative_GetLocaleInfoStringNative(const char* localeName, LocaleStringData localeStringData) @@ -51,7 +52,6 @@ [dateFormatter setLocale:currentLocale]; NSLocale *gbLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"]; - switch (localeStringData) { ///// localized name of locale, eg "German (Germany)" in UI language (corresponds to LOCALE_SLOCALIZEDDISPLAYNAME) @@ -148,9 +148,426 @@ value = ""; break; } - return strdup(value); } + +// invariant character definitions +#define CHAR_CURRENCY ((char)0x00A4) // international currency +#define CHAR_SPACE ((char)0x0020) // space +#define CHAR_NBSPACE ((char)0x00A0) // no-break space +#define CHAR_DIGIT ((char)0x0023) // '#' +#define CHAR_MINUS ((char)0x002D) // '-' +#define CHAR_PERCENT ((char)0x0025) // '%' +#define CHAR_OPENPAREN ((char)0x0028) // '(' +#define CHAR_CLOSEPAREN ((char)0x0029) // ')' +#define CHAR_ZERO ((char)0x0030) // '0' + +/* +Function: +NormalizeNumericPattern + +Returns a numeric string pattern in a format that we can match against the +appropriate managed pattern. Examples: +For PositiveMonetaryNumberFormat "¤#,##0.00" becomes "Cn" +For NegativeNumberFormat "#,##0.00;(#,##0.00)" becomes "(n)" +*/ +static char* NormalizeNumericPattern(const char* srcPattern, int isNegative) +{ + int iStart = 0; + int iEnd = strlen(srcPattern); + + // ';' separates positive and negative subpatterns. + // When there is no explicit negative subpattern, + // an implicit negative subpattern is formed from the positive pattern with a prefixed '-'. + char * ptrNegativePattern = strrchr(srcPattern,';'); + if (ptrNegativePattern) + { + int32_t iNegativePatternStart = ptrNegativePattern - srcPattern; + if (isNegative) + { + iStart = iNegativePatternStart + 1; + } + else + { + iEnd = iNegativePatternStart - 1; + } + } + + int minusAdded = false; + + for (int i = iStart; i <= iEnd; i++) + { + switch (srcPattern[i]) + { + case CHAR_MINUS: + case CHAR_OPENPAREN: + case CHAR_CLOSEPAREN: + minusAdded = true; + break; + } + + if (minusAdded) + break; + } + + // international currency symbol (CHAR_CURRENCY) + // The positive pattern comes first, then an optional negative pattern + // separated by a semicolon + // A destPattern example: "(C n)" where C represents the currency symbol, and + // n is the number + char* destPattern; + int index = 0; + + // if there is no negative subpattern, prefix the minus sign + if (isNegative && !minusAdded) + { + int length = (iEnd - iStart) + 2; + destPattern = (char*)calloc((size_t)length, sizeof(char)); + if (!destPattern) + { + return NULL; + } + destPattern[index++] = '-'; + } + else + { + int length = (iEnd - iStart) + 1; + destPattern = (char*)calloc((size_t)length, sizeof(char)); + if (!destPattern) + { + return NULL; + } + } + + int digitAdded = false; + int currencyAdded = false; + int spaceAdded = false; + + for (int i = iStart; i <= iEnd; i++) + { + char ch = srcPattern[i]; + switch (ch) + { + case CHAR_DIGIT: + case CHAR_ZERO: + if (!digitAdded) + { + digitAdded = true; + destPattern[index++] = 'n'; + } + break; + + case CHAR_CURRENCY: + if (!currencyAdded) + { + currencyAdded = true; + destPattern[index++] = 'C'; + } + break; + + case CHAR_SPACE: + case CHAR_NBSPACE: + if (!spaceAdded) + { + spaceAdded = true; + destPattern[index++] = ' '; + } + break; + + case CHAR_MINUS: + case CHAR_OPENPAREN: + case CHAR_CLOSEPAREN: + case CHAR_PERCENT: + destPattern[index++] = ch; + break; + } + } + + const int MAX_DOTNET_NUMERIC_PATTERN_LENGTH = 6; // example: "(C n)" plus terminator + + if (destPattern[0] == '\0' || strlen (destPattern) >= MAX_DOTNET_NUMERIC_PATTERN_LENGTH) + { + free (destPattern); + return NULL; + } + + return destPattern; +} + +/* +Function: +GetNumericPattern + +Determines the pattern from the decimalFormat and returns the matching pattern's +index from patterns[]. +Returns index -1 if no pattern is found. +*/ +static int GetPatternIndex(char* normalizedPattern,const char* patterns[], int patternsCount) +{ + const int INVALID_FORMAT = -1; + + if (!normalizedPattern) + { + return INVALID_FORMAT; + } + + for (int i = 0; i < patternsCount; i++) + { + if (strcmp(normalizedPattern, patterns[i]) == 0) + { + free(normalizedPattern); + return i; + } + } + + assert(false); // should have found a valid pattern + + free(normalizedPattern); + return INVALID_FORMAT; +} + +static int32_t GetValueForNumberFormat(NSLocale *currentLocale, LocaleNumberData localeNumberData) +{ + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + numberFormatter.locale = currentLocale; + const char *pFormat; + int32_t value; + + switch(localeNumberData) + { + case LocaleNumber_PositiveMonetaryNumberFormat: + { + numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + static const char* Patterns[] = {"Cn", "nC", "C n", "n C"}; + pFormat = [[numberFormatter positiveFormat] UTF8String]; + char* normalizedPattern = NormalizeNumericPattern(pFormat, false); + value = GetPatternIndex(normalizedPattern, Patterns, sizeof(Patterns)/sizeof(Patterns[0])); + break; + } + case LocaleNumber_NegativeMonetaryNumberFormat: + { + numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + static const char* Patterns[] = {"(Cn)", "-Cn", "C-n", "Cn-", "(nC)", "-nC", "n-C", "nC-", "-n C", + "-C n", "n C-", "C n-", "C -n", "n- C", "(C n)", "(n C)", "C- n" }; + pFormat = [[numberFormatter negativeFormat] UTF8String]; + char* normalizedPattern = NormalizeNumericPattern(pFormat, true); + value = GetPatternIndex(normalizedPattern, Patterns, sizeof(Patterns)/sizeof(Patterns[0])); + break; + } + case LocaleNumber_NegativeNumberFormat: + { + numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; + static const char* Patterns[] = {"(n)", "-n", "- n", "n-", "n -"}; + pFormat = [[numberFormatter negativeFormat] UTF8String]; + char* normalizedPattern = NormalizeNumericPattern(pFormat, true); + value = GetPatternIndex(normalizedPattern, Patterns, sizeof(Patterns)/sizeof(Patterns[0])); + break; + } + case LocaleNumber_NegativePercentFormat: + { + numberFormatter.numberStyle = NSNumberFormatterPercentStyle; + static const char* Patterns[] = {"-n %", "-n%", "-%n", "%-n", "%n-", "n-%", "n%-", "-% n", "n %-", "% n-", "% -n", "n- %"}; + pFormat = [[numberFormatter negativeFormat] UTF8String]; + char* normalizedPattern = NormalizeNumericPattern(pFormat, true); + value = GetPatternIndex(normalizedPattern, Patterns, sizeof(Patterns)/sizeof(Patterns[0])); + break; + } + case LocaleNumber_PositivePercentFormat: + { + numberFormatter.numberStyle = NSNumberFormatterPercentStyle; + static const char* Patterns[] = {"n %", "n%", "%n", "% n"}; + pFormat = [[numberFormatter positiveFormat] UTF8String]; + char* normalizedPattern = NormalizeNumericPattern(pFormat, false); + value = GetPatternIndex(normalizedPattern, Patterns, sizeof(Patterns)/sizeof(Patterns[0])); + break; + } + default: + return -1; + } + + return value; +} + +int32_t GlobalizationNative_GetLocaleInfoIntNative(const char* localeName, LocaleNumberData localeNumberData) +{ + bool isSuccess = true; + int32_t value; + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + + switch (localeNumberData) + { + case LocaleNumber_MeasurementSystem: + { + const char *measurementSystem = [[currentLocale objectForKey:NSLocaleMeasurementSystem] UTF8String]; + NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; + const char *us_measurementSystem = [[usLocale objectForKey:NSLocaleMeasurementSystem] UTF8String]; + value = (measurementSystem == us_measurementSystem) ? 1 : 0; + break; + } + case LocaleNumber_FractionalDigitsCount: + { + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + numberFormatter.locale = currentLocale; + numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; + value = (int32_t)numberFormatter.maximumFractionDigits; + break; + } + case LocaleNumber_MonetaryFractionalDigitsCount: + { + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + numberFormatter.locale = currentLocale; + numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + value = (int32_t)numberFormatter.maximumFractionDigits; + break; + } + case LocaleNumber_PositiveMonetaryNumberFormat: + case LocaleNumber_NegativeMonetaryNumberFormat: + case LocaleNumber_NegativeNumberFormat: + case LocaleNumber_NegativePercentFormat: + case LocaleNumber_PositivePercentFormat: + { + value = GetValueForNumberFormat(currentLocale, localeNumberData); + if (value < 0) + { + isSuccess = false; + } + break; + } + case LocaleNumber_FirstWeekOfYear: + { + NSCalendar *calendar = [currentLocale objectForKey:NSLocaleCalendar]; + int minDaysInWeek = (int32_t)[calendar minimumDaysInFirstWeek]; + if (minDaysInWeek == 1) + { + value = WeekRule_FirstDay; + } + else if (minDaysInWeek == 7) + { + value = WeekRule_FirstFullWeek; + } + else if (minDaysInWeek >= 4) + { + value = WeekRule_FirstFourDayWeek; + } + else + { + value = -1; + isSuccess = false; + } + break; + } + case LocaleNumber_ReadingLayout: + { + NSLocaleLanguageDirection langDir = [NSLocale characterDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]]; + // 0 - Left to right (such as en-US) + // 1 - Right to left (such as arabic locales) + value = NSLocaleLanguageDirectionRightToLeft == langDir ? 1 : 0; + break; + } + case LocaleNumber_FirstDayofWeek: + { + NSCalendar *calendar = [currentLocale objectForKey:NSLocaleCalendar]; + value = [calendar firstWeekday] - 1; // .NET is 0-based and in Apple is 1-based; + break; + } + default: + value = -1; + isSuccess = false; + break; + } + + assert(isSuccess); + + return value; +} + +/* +PAL Function: +GlobalizationNative_GetLocaleInfoPrimaryGroupingSizeNative + +Returns primary grouping size for decimal and currency +*/ +int32_t GlobalizationNative_GetLocaleInfoPrimaryGroupingSizeNative(const char* localeName, LocaleNumberData localeGroupingData) +{ + bool isSuccess = true; + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + numberFormatter.locale = currentLocale; + + switch (localeGroupingData) + { + case LocaleNumber_Digit: + numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; + break; + case LocaleNumber_Monetary: + numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + break; + default: + isSuccess = false; + assert(isSuccess); + break; + } + return [numberFormatter groupingSize]; +} + +/* +PAL Function: +GlobalizationNative_GetLocaleInfoSecondaryGroupingSizeNative + +Returns secondary grouping size for decimal and currency +*/ +int32_t GlobalizationNative_GetLocaleInfoSecondaryGroupingSizeNative(const char* localeName, LocaleNumberData localeGroupingData) +{ + bool isSuccess = true; + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + numberFormatter.locale = currentLocale; + + switch (localeGroupingData) + { + case LocaleNumber_Digit: + numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; + break; + case LocaleNumber_Monetary: + numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + break; + default: + isSuccess = false; + assert(isSuccess); + break; + } + + return [numberFormatter secondaryGroupingSize]; +} + +/* +PAL Function: +GlobalizationNative_GetLocaleTimeFormatNative + +Returns time format information (in native format, it needs to be converted to .NET's format). +*/ +const char* GlobalizationNative_GetLocaleTimeFormatNative(const char* localeName, int shortFormat) +{ + NSString *locName = [NSString stringWithFormat:@"%s", localeName]; + NSLocale *currentLocale = [[NSLocale alloc] initWithLocaleIdentifier:locName]; + NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setLocale:currentLocale]; + + if (shortFormat != 0) + { + [dateFormatter setTimeStyle:NSDateFormatterShortStyle]; + } + else + { + [dateFormatter setTimeStyle:NSDateFormatterMediumStyle]; + } + + return strdup([[dateFormatter dateFormat] UTF8String]); +} + #endif #if defined(TARGET_MACCATALYST) || defined(TARGET_IOS) || defined(TARGET_TVOS) diff --git a/src/native/libs/System.Globalization.Native/pal_localeNumberData.h b/src/native/libs/System.Globalization.Native/pal_localeNumberData.h index db5c401b8b7b6..a68f1e32e334a 100644 --- a/src/native/libs/System.Globalization.Native/pal_localeNumberData.h +++ b/src/native/libs/System.Globalization.Native/pal_localeNumberData.h @@ -43,3 +43,14 @@ PALEXPORT int32_t GlobalizationNative_GetLocaleInfoGroupingSizes(const UChar* lo LocaleNumberData localeGroupingData, int32_t* primaryGroupSize, int32_t* secondaryGroupSize); + +#ifdef __APPLE__ +PALEXPORT int32_t GlobalizationNative_GetLocaleInfoIntNative(const char* localeName, + LocaleNumberData localeNumberData); + +PALEXPORT int32_t GlobalizationNative_GetLocaleInfoPrimaryGroupingSizeNative(const char* localeName, + LocaleNumberData localeGroupingData); + +PALEXPORT int32_t GlobalizationNative_GetLocaleInfoSecondaryGroupingSizeNative(const char* localeName, + LocaleNumberData localeGroupingData); +#endif diff --git a/src/native/libs/System.Globalization.Native/pal_localeStringData.c b/src/native/libs/System.Globalization.Native/pal_localeStringData.c index 9120b89bd329b..488cbc8cb35f2 100644 --- a/src/native/libs/System.Globalization.Native/pal_localeStringData.c +++ b/src/native/libs/System.Globalization.Native/pal_localeStringData.c @@ -401,24 +401,3 @@ int32_t GlobalizationNative_GetLocaleInfoString(const UChar* localeName, return UErrorCodeToBool(status); } -/* -PAL Function: -GetLocaleTimeFormat - -Obtains time format information (in ICU format, it needs to be converted to .NET's format). -Returns 1 for success, 0 otherwise -*/ -int32_t GlobalizationNative_GetLocaleTimeFormat(const UChar* localeName, - int shortFormat, - UChar* value, - int32_t valueLength) -{ - UErrorCode err = U_ZERO_ERROR; - char locale[ULOC_FULLNAME_CAPACITY]; - GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); - UDateFormatStyle style = (shortFormat != 0) ? UDAT_SHORT : UDAT_MEDIUM; - UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale, NULL, 0, NULL, 0, &err); - udat_toPattern(pFormat, false, value, valueLength, &err); - udat_close(pFormat); - return UErrorCodeToBool(err); -} diff --git a/src/native/libs/System.Globalization.Native/pal_localeStringData.h b/src/native/libs/System.Globalization.Native/pal_localeStringData.h index e6030d8a4cf86..a6961c39761bf 100644 --- a/src/native/libs/System.Globalization.Native/pal_localeStringData.h +++ b/src/native/libs/System.Globalization.Native/pal_localeStringData.h @@ -52,9 +52,5 @@ PALEXPORT int32_t GlobalizationNative_GetLocaleInfoString(const UChar* localeNam #ifdef __APPLE__ PALEXPORT const char* GlobalizationNative_GetLocaleInfoStringNative(const char* localeName, LocaleStringData localeStringData); -#endif - -PALEXPORT int32_t GlobalizationNative_GetLocaleTimeFormat(const UChar* localeName, - int shortFormat, UChar* value, - int32_t valueLength); +#endif diff --git a/src/native/libs/System.Globalization.Native/pal_locale_internal.h b/src/native/libs/System.Globalization.Native/pal_locale_internal.h index 1f9edb7640cbf..c754554bbfdd5 100644 --- a/src/native/libs/System.Globalization.Native/pal_locale_internal.h +++ b/src/native/libs/System.Globalization.Native/pal_locale_internal.h @@ -4,7 +4,6 @@ #pragma once #include "pal_icushim_internal.h" -#include "pal_localeStringData.h" /* Function: @@ -61,21 +60,4 @@ DetectDefaultSystemLocaleName Detects the default locale string for Apple platforms */ char* DetectDefaultAppleLocaleName(void); - -/* -Function: -GlobalizationNative_GetLocaleNameNative - -Returns native locale name for Apple platforms -*/ -const char* GlobalizationNative_GetLocaleNameNative(const char* localeName); - -/* -Function: -GlobalizationNative_GetLocaleInfoStringNative - -Returns string locale information if found for the specified locale name for Apple platforms. -Returns empty string if not found. -*/ -const char* GlobalizationNative_GetLocaleInfoStringNative(const char* localeName, LocaleStringData localeStringData); #endif From 4db1ed26c5f16da78739a773548cea9546809a7a Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sun, 16 Apr 2023 10:31:20 -0400 Subject: [PATCH 07/32] Implement IUtf8SpanFormattable on Guid (#84553) --- .../Text/Utf8Formatter/Utf8Formatter.Guid.cs | 284 +---------- .../System.Private.CoreLib/src/System/Guid.cs | 462 +++++++++++------- .../System.Runtime/ref/System.Runtime.cs | 4 +- .../System.Runtime/tests/System/GuidTests.cs | 51 +- 4 files changed, 352 insertions(+), 449 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Guid.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Guid.cs index 8effbc24857b0..3e64fbd3ec754 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Guid.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Guid.cs @@ -1,83 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; -using System.Runtime.Intrinsics.X86; - namespace System.Buffers.Text { public static partial class Utf8Formatter { - #region Constants - - private const byte OpenBrace = (byte)'{'; - private const byte CloseBrace = (byte)'}'; - - private const byte OpenParen = (byte)'('; - private const byte CloseParen = (byte)')'; - - private const byte Dash = (byte)'-'; - - #endregion Constants - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static (Vector128, Vector128, Vector128) FormatGuidVector128Utf8(Guid value, bool useDashes) - { - Debug.Assert((Ssse3.IsSupported || AdvSimd.Arm64.IsSupported) && BitConverter.IsLittleEndian); - // Vectorized implementation for D, N, P and B formats: - // [{|(]dddddddd[-]dddd[-]dddd[-]dddd[-]dddddddddddd[}|)] - - Vector128 hexMap = Vector128.Create( - (byte)'0', (byte)'1', (byte)'2', (byte)'3', - (byte)'4', (byte)'5', (byte)'6', (byte)'7', - (byte)'8', (byte)'9', (byte)'a', (byte)'b', - (byte)'c', (byte)'d', (byte)'e', (byte)'f'); - - Vector128 srcVec = Unsafe.As>(ref value); - (Vector128 hexLow, Vector128 hexHigh) = - HexConverter.AsciiToHexVector128(srcVec, hexMap); - - // because of Guid's layout (int _a, short _b, _c, <8 byte fields>) - // we have to shuffle some bytes for _a, _b and _c - hexLow = Vector128.Shuffle(hexLow.AsInt16(), Vector128.Create(3, 2, 1, 0, 5, 4, 7, 6)).AsByte(); - - if (useDashes) - { - // We divide 16 bytes into 3 x Vector128: - // - // ________-____-____-____-____________ - // xxxxxxxxxxxxxxxx - // yyyyyyyyyyyyyyyy - // zzzzzzzzzzzzzzzz - // - // Vector "x" - just one dash, shift all elements after it. - Vector128 vecX = Vector128.Shuffle(hexLow, - Vector128.Create(0x706050403020100, 0xD0CFF0B0A0908FF).AsByte()); - - // Vector "y" - same here. - Vector128 vecY = Vector128.Shuffle(hexHigh, - Vector128.Create(0x7060504FF030201, 0xF0E0D0C0B0A0908).AsByte()); - - // Vector "z" - we need to merge some elements of hexLow with hexHigh and add 4 dashes. - Vector128 mid1 = Vector128.Shuffle(hexLow, - Vector128.Create(0x0D0CFF0B0A0908FF, 0xFFFFFFFFFFFF0F0E).AsByte()); - Vector128 mid2 = Vector128.Shuffle(hexHigh, - Vector128.Create(0xFFFFFFFFFFFFFFFF, 0xFF03020100FFFFFF).AsByte()); - Vector128 dashesMask = Vector128.Shuffle(Vector128.CreateScalarUnsafe((byte)'-'), - Vector128.Create(0xFFFF00FFFFFFFF00, 0x00FFFFFFFF00FFFF).AsByte()); - - Vector128 vecZ = (mid1 | mid2 | dashesMask); - return (vecX, vecY, vecZ); - } - - // N format - no dashes. - return (hexLow, hexHigh, default); - } - /// /// Formats a Guid as a UTF8 string. /// @@ -101,41 +28,24 @@ internal static (Vector128, Vector128, Vector128) FormatGuidVe /// public static bool TryFormat(Guid value, Span destination, out int bytesWritten, StandardFormat format = default) { - const int INSERT_DASHES = unchecked((int)0x80000000); - const int NO_DASHES = 0; - const int INSERT_CURLY_BRACES = (CloseBrace << 16) | (OpenBrace << 8); - const int INSERT_ROUND_BRACES = (CloseParen << 16) | (OpenParen << 8); - const int NO_BRACES = 0; - const int LEN_GUID_BASE = 32; - const int LEN_ADD_DASHES = 4; - const int LEN_ADD_BRACES = 2; - - // This is a 32-bit value whose contents (where 0 is the low byte) are: - // 0th byte: minimum required length of the output buffer, - // 1st byte: the ASCII byte to insert for the opening brace position (or 0 if no braces), - // 2nd byte: the ASCII byte to insert for the closing brace position (or 0 if no braces), - // 3rd byte: high bit set if dashes are to be inserted. - // - // The reason for keeping a single flag instead of separate vars is that we can avoid register spillage - // as we build up the output value. int flags; switch (FormattingHelpers.GetSymbolOrDefault(format, 'D')) { case 'D': // nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn - flags = INSERT_DASHES + NO_BRACES + LEN_GUID_BASE + LEN_ADD_DASHES; + flags = 36 + Guid.TryFormatFlags_UseDashes; break; case 'B': // {nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn} - flags = INSERT_DASHES + INSERT_CURLY_BRACES + LEN_GUID_BASE + LEN_ADD_DASHES + LEN_ADD_BRACES; + flags = 38 + Guid.TryFormatFlags_UseDashes + Guid.TryFormatFlags_CurlyBraces; break; case 'P': // (nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn) - flags = INSERT_DASHES + INSERT_ROUND_BRACES + LEN_GUID_BASE + LEN_ADD_DASHES + LEN_ADD_BRACES; + flags = 38 + Guid.TryFormatFlags_UseDashes + Guid.TryFormatFlags_Parens; break; case 'N': // nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn - flags = NO_BRACES + NO_DASHES + LEN_GUID_BASE; + flags = 32; break; default: @@ -143,191 +53,7 @@ public static bool TryFormat(Guid value, Span destination, out int bytesWr goto case 'D'; // unreachable } - // At this point, the low byte of flags contains the minimum required length - - if ((byte)flags > destination.Length) - { - bytesWritten = 0; - return false; - } - - bytesWritten = (byte)flags; - flags >>= 8; - - // At this point, the low byte of flags contains the opening brace char (if any) - - if ((byte)flags != 0) - { - destination[0] = (byte)flags; - destination = destination.Slice(1); - } - flags >>= 8; - - if ((Ssse3.IsSupported || AdvSimd.Arm64.IsSupported) && BitConverter.IsLittleEndian) - { - // Vectorized implementation for D, N, P and B formats: - // [{|(]dddddddd[-]dddd[-]dddd[-]dddd[-]dddddddddddd[}|)] - (Vector128 vecX, Vector128 vecY, Vector128 vecZ) = - FormatGuidVector128Utf8(value, flags < 0 /*dash*/); - - ref byte dest = ref MemoryMarshal.GetReference(destination); - if (flags < 0) - { - // We need to merge these vectors in this order: - // xxxxxxxxxxxxxxxx - // yyyyyyyyyyyyyyyy - // zzzzzzzzzzzzzzzz - vecX.StoreUnsafe(ref dest, 0); - vecY.StoreUnsafe(ref dest, 20); - vecZ.StoreUnsafe(ref dest, 8); - } - else - { - // xxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyy - vecX.StoreUnsafe(ref dest, 0); - vecY.StoreUnsafe(ref dest, 16); - } - if ((byte)flags != 0) - Unsafe.Add(ref dest, flags < 0 ? 36 : 32) = (byte)flags; - return true; - } - - // At this point, the low byte of flags contains the closing brace char (if any) - // And since we're performing arithmetic shifting the high bit of flags is set (flags is negative) if dashes are required - - DecomposedGuid guidAsBytes = default; - guidAsBytes.Guid = value; - - // When a GUID is blitted, the first three components are native-endian, and the last component is big-endian. - - // The line below forces the JIT to hoist the bounds check for the following segment. - // The JIT will optimize away the read, but it cannot optimize away the bounds check - // because it may have an observable side effect (throwing). - // We use 8 instead of 7 so that we also capture the dash if we're asked to insert one. - - { _ = destination[8]; } - if (BitConverter.IsLittleEndian) - { - HexConverter.ToBytesBuffer(guidAsBytes.Byte03, destination, 0, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte02, destination, 2, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte01, destination, 4, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte00, destination, 6, HexConverter.Casing.Lower); - } - else - { - HexConverter.ToBytesBuffer(guidAsBytes.Byte00, destination, 0, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte01, destination, 2, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte02, destination, 4, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte03, destination, 6, HexConverter.Casing.Lower); - } - - if (flags < 0 /* use dash? */) - { - destination[8] = Dash; - destination = destination.Slice(9); - } - else - { - destination = destination.Slice(8); - } - - { _ = destination[4]; } - if (BitConverter.IsLittleEndian) - { - HexConverter.ToBytesBuffer(guidAsBytes.Byte05, destination, 0, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte04, destination, 2, HexConverter.Casing.Lower); - } - else - { - HexConverter.ToBytesBuffer(guidAsBytes.Byte04, destination, 0, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte05, destination, 2, HexConverter.Casing.Lower); - } - - if (flags < 0 /* use dash? */) - { - destination[4] = Dash; - destination = destination.Slice(5); - } - else - { - destination = destination.Slice(4); - } - - { _ = destination[4]; } - if (BitConverter.IsLittleEndian) - { - HexConverter.ToBytesBuffer(guidAsBytes.Byte07, destination, 0, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte06, destination, 2, HexConverter.Casing.Lower); - } - else - { - HexConverter.ToBytesBuffer(guidAsBytes.Byte06, destination, 0, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte07, destination, 2, HexConverter.Casing.Lower); - } - - if (flags < 0 /* use dash? */) - { - destination[4] = Dash; - destination = destination.Slice(5); - } - else - { - destination = destination.Slice(4); - } - - { _ = destination[4]; } - HexConverter.ToBytesBuffer(guidAsBytes.Byte08, destination, 0, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte09, destination, 2, HexConverter.Casing.Lower); - - if (flags < 0 /* use dash? */) - { - destination[4] = Dash; - destination = destination.Slice(5); - } - else - { - destination = destination.Slice(4); - } - - { _ = destination[11]; } // can't hoist bounds check on the final brace (if exists) - HexConverter.ToBytesBuffer(guidAsBytes.Byte10, destination, 0, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte11, destination, 2, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte12, destination, 4, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte13, destination, 6, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte14, destination, 8, HexConverter.Casing.Lower); - HexConverter.ToBytesBuffer(guidAsBytes.Byte15, destination, 10, HexConverter.Casing.Lower); - - if ((byte)flags != 0) - { - destination[12] = (byte)flags; - } - - return true; - } - - /// - /// Used to provide access to the individual bytes of a GUID. - /// - [StructLayout(LayoutKind.Explicit)] - private struct DecomposedGuid - { - [FieldOffset(00)] public Guid Guid; - [FieldOffset(00)] public byte Byte00; - [FieldOffset(01)] public byte Byte01; - [FieldOffset(02)] public byte Byte02; - [FieldOffset(03)] public byte Byte03; - [FieldOffset(04)] public byte Byte04; - [FieldOffset(05)] public byte Byte05; - [FieldOffset(06)] public byte Byte06; - [FieldOffset(07)] public byte Byte07; - [FieldOffset(08)] public byte Byte08; - [FieldOffset(09)] public byte Byte09; - [FieldOffset(10)] public byte Byte10; - [FieldOffset(11)] public byte Byte11; - [FieldOffset(12)] public byte Byte12; - [FieldOffset(13)] public byte Byte13; - [FieldOffset(14)] public byte Byte14; - [FieldOffset(15)] public byte Byte15; + return value.TryFormatCore(destination, out bytesWritten, flags); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Guid.cs b/src/libraries/System.Private.CoreLib/src/System/Guid.cs index 4a1ede42b511a..ec28fdeb45aaa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Guid.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Guid.cs @@ -25,7 +25,8 @@ public readonly partial struct Guid IComparable, IComparable, IEquatable, - ISpanParsable + ISpanParsable, + IUtf8SpanFormattable { public static readonly Guid Empty; @@ -306,7 +307,7 @@ public static Guid ParseExact(ReadOnlySpan input, [StringSyntax(StringSynt if (format.Length != 1) { // all acceptable format strings are of length 1 - throw new FormatException(SR.Format_InvalidGuidFormatSpecification); + ThrowBadGuidFormatSpecification(); } input = input.Trim(); @@ -883,9 +884,6 @@ public bool TryWriteBytes(Span destination) return true; } - // Returns the guid in "registry" format. - public override string ToString() => ToString("D", null); - public override int GetHashCode() { // Simply XOR all the bits of the GUID 32 bits at a time. @@ -1054,192 +1052,221 @@ public int CompareTo(Guid value) public static bool operator !=(Guid a, Guid b) => !EqualsCore(a, b); - public string ToString([StringSyntax(StringSyntaxAttribute.GuidFormat)] string? format) - { - return ToString(format, null); - } - - private static unsafe int HexsToChars(char* guidChars, int a, int b) + private static unsafe int HexsToChars(TChar* guidChars, int a, int b) where TChar : unmanaged, IUtfChar { - guidChars[0] = HexConverter.ToCharLower(a >> 4); - guidChars[1] = HexConverter.ToCharLower(a); + guidChars[0] = TChar.CastFrom(HexConverter.ToCharLower(a >> 4)); + guidChars[1] = TChar.CastFrom(HexConverter.ToCharLower(a)); - guidChars[2] = HexConverter.ToCharLower(b >> 4); - guidChars[3] = HexConverter.ToCharLower(b); + guidChars[2] = TChar.CastFrom(HexConverter.ToCharLower(b >> 4)); + guidChars[3] = TChar.CastFrom(HexConverter.ToCharLower(b)); return 4; } - private static unsafe int HexsToCharsHexOutput(char* guidChars, int a, int b) + private static unsafe int HexsToCharsHexOutput(TChar* guidChars, int a, int b) where TChar : unmanaged, IUtfChar { - guidChars[0] = '0'; - guidChars[1] = 'x'; + guidChars[0] = TChar.CastFrom('0'); + guidChars[1] = TChar.CastFrom('x'); - guidChars[2] = HexConverter.ToCharLower(a >> 4); - guidChars[3] = HexConverter.ToCharLower(a); + guidChars[2] = TChar.CastFrom(HexConverter.ToCharLower(a >> 4)); + guidChars[3] = TChar.CastFrom(HexConverter.ToCharLower(a)); - guidChars[4] = ','; - guidChars[5] = '0'; - guidChars[6] = 'x'; + guidChars[4] = TChar.CastFrom(','); + guidChars[5] = TChar.CastFrom('0'); + guidChars[6] = TChar.CastFrom('x'); - guidChars[7] = HexConverter.ToCharLower(b >> 4); - guidChars[8] = HexConverter.ToCharLower(b); + guidChars[7] = TChar.CastFrom(HexConverter.ToCharLower(b >> 4)); + guidChars[8] = TChar.CastFrom(HexConverter.ToCharLower(b)); return 9; } + // Returns the guid in "registry" format. + public override string ToString() => ToString("d", null); + + public string ToString([StringSyntax(StringSyntaxAttribute.GuidFormat)] string? format) + { + return ToString(format, null); + } + // IFormattable interface // We currently ignore provider public string ToString([StringSyntax(StringSyntaxAttribute.GuidFormat)] string? format, IFormatProvider? provider) { + int guidSize; if (string.IsNullOrEmpty(format)) { - format = "D"; + guidSize = 36; } - - // all acceptable format strings are of length 1 - if (format.Length != 1) + else { - throw new FormatException(SR.Format_InvalidGuidFormatSpecification); - } + // all acceptable format strings are of length 1 + if (format.Length != 1) + { + ThrowBadGuidFormatSpecification(); + } - int guidSize; - switch (format[0]) - { - case 'D': - case 'd': - guidSize = 36; - break; - case 'N': - case 'n': - guidSize = 32; - break; - case 'B': - case 'b': - case 'P': - case 'p': - guidSize = 38; - break; - case 'X': - case 'x': - guidSize = 68; - break; - default: - throw new FormatException(SR.Format_InvalidGuidFormatSpecification); + switch (format[0] | 0x20) + { + case 'd': + guidSize = 36; + break; + + case 'n': + guidSize = 32; + break; + + case 'b' or 'p': + guidSize = 38; + break; + + case 'x': + guidSize = 68; + break; + + default: + guidSize = 0; + ThrowBadGuidFormatSpecification(); + break; + }; } string guidString = string.FastAllocateString(guidSize); - bool result = TryFormat(new Span(ref guidString.GetRawStringData(), guidString.Length), out int bytesWritten, format); + bool result = TryFormatCore(new Span(ref guidString.GetRawStringData(), guidString.Length), out int bytesWritten, format); Debug.Assert(result && bytesWritten == guidString.Length, "Formatting guid should have succeeded."); return guidString; } - // Returns whether the guid is successfully formatted as a span. - public bool TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.GuidFormat)] ReadOnlySpan format = default) + public bool TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.GuidFormat)] ReadOnlySpan format = default) => + TryFormatCore(destination, out charsWritten, format); + + bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.GuidFormat)] ReadOnlySpan format, IFormatProvider? provider) => + // Provider is ignored. + TryFormatCore(destination, out charsWritten, format); + + public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.GuidFormat)] ReadOnlySpan format = default) => + TryFormatCore(utf8Destination, out bytesWritten, format); + + bool IUtf8SpanFormattable.TryFormat(Span utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.GuidFormat)] ReadOnlySpan format, IFormatProvider? provider) => + // Provider is ignored. + TryFormatCore(utf8Destination, out bytesWritten, format); + + // TryFormatCore accepts an `int flags` composed of: + // - Lowest byte: required length + // - Second byte: opening brace char, or 0 if no braces + // - Third byte: closing brace char, or 0 if no braces + // - Highest bit: 1 if use dashes, else 0 + internal const int TryFormatFlags_UseDashes = unchecked((int)0x80000000); + internal const int TryFormatFlags_CurlyBraces = ('}' << 16) | ('{' << 8); + internal const int TryFormatFlags_Parens = (')' << 16) | ('(' << 8); + + private bool TryFormatCore(Span destination, out int charsWritten, ReadOnlySpan format) where TChar : unmanaged, IUtfChar { + int flags; + if (format.Length == 0) { - format = "D"; + flags = 36 + TryFormatFlags_UseDashes; } - // all acceptable format strings are of length 1 - if (format.Length != 1) + else { - throw new FormatException(SR.Format_InvalidGuidFormatSpecification); - } + if (format.Length != 1) + { + ThrowBadGuidFormatSpecification(); + } - bool dash = true; - bool hex = false; - int braces = 0; + switch (format[0] | 0x20) + { + case 'd': + flags = 36 + TryFormatFlags_UseDashes; + break; - int guidSize; + case 'p': + flags = 38 + TryFormatFlags_UseDashes + TryFormatFlags_Parens; + break; - switch (format[0]) - { - case 'D': - case 'd': - guidSize = 36; - break; - case 'N': - case 'n': - dash = false; - guidSize = 32; - break; - case 'B': - case 'b': - braces = '{' + ('}' << 16); - guidSize = 38; - break; - case 'P': - case 'p': - braces = '(' + (')' << 16); - guidSize = 38; - break; - case 'X': - case 'x': - braces = '{' + ('}' << 16); - dash = false; - hex = true; - guidSize = 68; - break; - default: - throw new FormatException(SR.Format_InvalidGuidFormatSpecification); + case 'b': + flags = 38 + TryFormatFlags_UseDashes + TryFormatFlags_CurlyBraces; + break; + + case 'n': + flags = 32; + break; + + case 'x': + return TryFormatX(destination, out charsWritten); + + default: + flags = 0; + ThrowBadGuidFormatSpecification(); + break; + } } - if (destination.Length < guidSize) + return TryFormatCore(destination, out charsWritten, flags); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] // only used from two callers + internal unsafe bool TryFormatCore(Span destination, out int charsWritten, int flags) where TChar : unmanaged, IUtfChar + { + // The low byte of flags contains the required length. + if ((byte)flags > destination.Length) { charsWritten = 0; return false; } - unsafe + charsWritten = (byte)flags; + flags >>= 8; + + fixed (TChar* guidChars = &MemoryMarshal.GetReference(destination)) { - fixed (char* guidChars = &MemoryMarshal.GetReference(destination)) + TChar* p = guidChars; + + // The low byte of flags now contains the opening brace char (if any) + if ((byte)flags != 0) { - char* p = guidChars; + *p++ = TChar.CastFrom((byte)flags); + } + flags >>= 8; - if (braces != 0) - *p++ = (char)braces; + if ((Ssse3.IsSupported || AdvSimd.Arm64.IsSupported) && BitConverter.IsLittleEndian) + { + // Vectorized implementation for D, N, P and B formats: + // [{|(]dddddddd[-]dddd[-]dddd[-]dddd[-]dddddddddddd[}|)] + (Vector128 vecX, Vector128 vecY, Vector128 vecZ) = FormatGuidVector128Utf8(this, flags < 0 /* dash */); - if (hex) + if (typeof(TChar) == typeof(byte)) { - // {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}} - *p++ = '0'; - *p++ = 'x'; - p += HexsToChars(p, _a >> 24, _a >> 16); - p += HexsToChars(p, _a >> 8, _a); - *p++ = ','; - *p++ = '0'; - *p++ = 'x'; - p += HexsToChars(p, _b >> 8, _b); - *p++ = ','; - *p++ = '0'; - *p++ = 'x'; - p += HexsToChars(p, _c >> 8, _c); - *p++ = ','; - *p++ = '{'; - p += HexsToCharsHexOutput(p, _d, _e); - *p++ = ','; - p += HexsToCharsHexOutput(p, _f, _g); - *p++ = ','; - p += HexsToCharsHexOutput(p, _h, _i); - *p++ = ','; - p += HexsToCharsHexOutput(p, _j, _k); - *p++ = '}'; + byte* pChar = (byte*)p; + if (flags < 0 /* dash */) + { + // We need to merge these vectors in this order: + // xxxxxxxxxxxxxxxx + // yyyyyyyyyyyyyyyy + // zzzzzzzzzzzzzzzz + vecX.Store(pChar); + vecY.Store(pChar + 20); + vecZ.Store(pChar + 8); + p += 36; + } + else + { + // xxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyy + vecX.Store(pChar); + vecY.Store(pChar + 16); + p += 32; + } } - else if ((Ssse3.IsSupported || AdvSimd.Arm64.IsSupported) && BitConverter.IsLittleEndian) + else { - // Vectorized implementation for D, N, P and B formats: - // [{|(]dddddddd[-]dddd[-]dddd[-]dddd[-]dddddddddddd[}|)] - (Vector128 vecX, Vector128 vecY, Vector128 vecZ) = - Buffers.Text.Utf8Formatter.FormatGuidVector128Utf8(this, dash); - // Expand to UTF-16 (Vector128 x0, Vector128 x1) = Vector128.Widen(vecX); (Vector128 y0, Vector128 y1) = Vector128.Widen(vecY); ushort* pChar = (ushort*)p; - if (dash) + if (flags < 0 /* dash */) { (Vector128 z0, Vector128 z1) = Vector128.Widen(vecZ); @@ -1247,7 +1274,7 @@ public bool TryFormat(Span destination, out int charsWritten, [StringSynta // xxxxxxxxxxxxxxxx // yyyyyyyyyyyyyyyy // zzzzzzzzzzzzzzzz - x0.Store(pChar + 0); + x0.Store(pChar); y0.Store(pChar + 20); y1.Store(pChar + 28); z0.Store(pChar + 8); // overlaps x1 @@ -1257,54 +1284,153 @@ public bool TryFormat(Span destination, out int charsWritten, [StringSynta else { // xxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyy - x0.Store(pChar + 0); + x0.Store(pChar); x1.Store(pChar + 8); y0.Store(pChar + 16); y1.Store(pChar + 24); p += 32; } - if (braces != 0) - *p = (char)(braces >> 16); - charsWritten = guidSize; - return true; } - else + } + else + { + // Non-vectorized fallback for D, N, P and B formats: + // [{|(]dddddddd[-]dddd[-]dddd[-]dddd[-]dddddddddddd[}|)] + p += HexsToChars(p, _a >> 24, _a >> 16); + p += HexsToChars(p, _a >> 8, _a); + if (flags < 0 /* dash */) { - // Non-vectorized fallback for D, N, P and B formats: - // [{|(]dddddddd[-]dddd[-]dddd[-]dddd[-]dddddddddddd[}|)] - p += HexsToChars(p, _a >> 24, _a >> 16); - p += HexsToChars(p, _a >> 8, _a); - if (dash) - *p++ = '-'; - p += HexsToChars(p, _b >> 8, _b); - if (dash) - *p++ = '-'; - p += HexsToChars(p, _c >> 8, _c); - if (dash) - *p++ = '-'; - p += HexsToChars(p, _d, _e); - if (dash) - *p++ = '-'; - p += HexsToChars(p, _f, _g); - p += HexsToChars(p, _h, _i); - p += HexsToChars(p, _j, _k); + *p++ = TChar.CastFrom('-'); } + p += HexsToChars(p, _b >> 8, _b); + if (flags < 0 /* dash */) + { + *p++ = TChar.CastFrom('-'); + } + p += HexsToChars(p, _c >> 8, _c); + if (flags < 0 /* dash */) + { + *p++ = TChar.CastFrom('-'); + } + p += HexsToChars(p, _d, _e); + if (flags < 0 /* dash */) + { + *p++ = TChar.CastFrom('-'); + } + p += HexsToChars(p, _f, _g); + p += HexsToChars(p, _h, _i); + p += HexsToChars(p, _j, _k); + } - if (braces != 0) - *p++ = (char)(braces >> 16); - - Debug.Assert(p - guidChars == guidSize); + // The low byte of flags now contains the closing brace char (if any) + if ((byte)flags != 0) + { + *p = TChar.CastFrom((byte)flags); } + + Debug.Assert(p == guidChars + charsWritten - ((byte)flags != 0 ? 1 : 0)); + } + + return true; + } + + private unsafe bool TryFormatX(Span destination, out int charsWritten) where TChar : unmanaged, IUtfChar + { + if (destination.Length < 68) + { + charsWritten = 0; + return false; + } + charsWritten = 68; + + fixed (TChar* guidChars = &MemoryMarshal.GetReference(destination)) + { + TChar* p = guidChars; + + // {0xdddddddd,0xdddd,0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}} + *p++ = TChar.CastFrom('{'); + *p++ = TChar.CastFrom('0'); + *p++ = TChar.CastFrom('x'); + p += HexsToChars(p, _a >> 24, _a >> 16); + p += HexsToChars(p, _a >> 8, _a); + *p++ = TChar.CastFrom(','); + *p++ = TChar.CastFrom('0'); + *p++ = TChar.CastFrom('x'); + p += HexsToChars(p, _b >> 8, _b); + *p++ = TChar.CastFrom(','); + *p++ = TChar.CastFrom('0'); + *p++ = TChar.CastFrom('x'); + p += HexsToChars(p, _c >> 8, _c); + *p++ = TChar.CastFrom(','); + *p++ = TChar.CastFrom('{'); + p += HexsToCharsHexOutput(p, _d, _e); + *p++ = TChar.CastFrom(','); + p += HexsToCharsHexOutput(p, _f, _g); + *p++ = TChar.CastFrom(','); + p += HexsToCharsHexOutput(p, _h, _i); + *p++ = TChar.CastFrom(','); + p += HexsToCharsHexOutput(p, _j, _k); + *p++ = TChar.CastFrom('}'); + *p = TChar.CastFrom('}'); + + Debug.Assert(p == guidChars + charsWritten - 1); } - charsWritten = guidSize; return true; } - bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.GuidFormat)] ReadOnlySpan format, IFormatProvider? provider) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static (Vector128, Vector128, Vector128) FormatGuidVector128Utf8(Guid value, bool useDashes) { - // Like with the IFormattable implementation, provider is ignored. - return TryFormat(destination, out charsWritten, format); + Debug.Assert((Ssse3.IsSupported || AdvSimd.Arm64.IsSupported) && BitConverter.IsLittleEndian); + // Vectorized implementation for D, N, P and B formats: + // [{|(]dddddddd[-]dddd[-]dddd[-]dddd[-]dddddddddddd[}|)] + + Vector128 hexMap = Vector128.Create( + (byte)'0', (byte)'1', (byte)'2', (byte)'3', + (byte)'4', (byte)'5', (byte)'6', (byte)'7', + (byte)'8', (byte)'9', (byte)'a', (byte)'b', + (byte)'c', (byte)'d', (byte)'e', (byte)'f'); + + Vector128 srcVec = Unsafe.As>(ref value); + (Vector128 hexLow, Vector128 hexHigh) = + HexConverter.AsciiToHexVector128(srcVec, hexMap); + + // because of Guid's layout (int _a, short _b, _c, <8 byte fields>) + // we have to shuffle some bytes for _a, _b and _c + hexLow = Vector128.Shuffle(hexLow.AsInt16(), Vector128.Create(3, 2, 1, 0, 5, 4, 7, 6)).AsByte(); + + if (useDashes) + { + // We divide 16 bytes into 3 x Vector128: + // + // ________-____-____-____-____________ + // xxxxxxxxxxxxxxxx + // yyyyyyyyyyyyyyyy + // zzzzzzzzzzzzzzzz + // + // Vector "x" - just one dash, shift all elements after it. + Vector128 vecX = Vector128.Shuffle(hexLow, + Vector128.Create(0x706050403020100, 0xD0CFF0B0A0908FF).AsByte()); + + // Vector "y" - same here. + Vector128 vecY = Vector128.Shuffle(hexHigh, + Vector128.Create(0x7060504FF030201, 0xF0E0D0C0B0A0908).AsByte()); + + // Vector "z" - we need to merge some elements of hexLow with hexHigh and add 4 dashes. + Vector128 mid1 = Vector128.Shuffle(hexLow, + Vector128.Create(0x0D0CFF0B0A0908FF, 0xFFFFFFFFFFFF0F0E).AsByte()); + Vector128 mid2 = Vector128.Shuffle(hexHigh, + Vector128.Create(0xFFFFFFFFFFFFFFFF, 0xFF03020100FFFFFF).AsByte()); + Vector128 dashesMask = Vector128.Shuffle(Vector128.CreateScalarUnsafe((byte)'-'), + Vector128.Create(0xFFFF00FFFFFFFF00, 0x00FFFFFFFF00FFFF).AsByte()); + + Vector128 vecZ = (mid1 | mid2 | dashesMask); + return (vecX, vecY, vecZ); + } + + // N format - no dashes. + return (hexLow, hexHigh, default); } // @@ -1574,5 +1700,9 @@ bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, [S /// public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out Guid result) => TryParse(s, out result); + + [DoesNotReturn] + private static void ThrowBadGuidFormatSpecification() => + throw new FormatException(SR.Format_InvalidGuidFormatSpecification); } } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index a9fd59e5af115..251edf1a3687b 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -2758,7 +2758,7 @@ public enum GCNotificationStatus Timeout = 3, NotApplicable = 4, } - public readonly partial struct Guid : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable + public readonly partial struct Guid : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.IUtf8SpanFormattable { private readonly int _dummyPrimitive; public static readonly System.Guid Empty; @@ -2788,11 +2788,13 @@ public enum GCNotificationStatus public static System.Guid ParseExact(System.ReadOnlySpan input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("GuidFormat")] System.ReadOnlySpan format) { throw null; } public static System.Guid ParseExact(string input, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("GuidFormat")] string format) { throw null; } bool System.ISpanFormattable.TryFormat(System.Span destination, out int charsWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("GuidFormat")] System.ReadOnlySpan format, System.IFormatProvider? provider) { throw null; } + bool System.IUtf8SpanFormattable.TryFormat(System.Span utf8Destination, out int bytesWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("GuidFormat")] System.ReadOnlySpan format, System.IFormatProvider? provider) { throw null; } public byte[] ToByteArray() { throw null; } public override string ToString() { throw null; } public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("GuidFormat")] string? format) { throw null; } public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("GuidFormat")] string? format, System.IFormatProvider? provider) { throw null; } public bool TryFormat(System.Span destination, out int charsWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("GuidFormat")] System.ReadOnlySpan format = default(System.ReadOnlySpan)) { throw null; } + public bool TryFormat(System.Span utf8Destination, out int bytesWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("GuidFormat")] System.ReadOnlySpan format = default(System.ReadOnlySpan)) { throw null; } public static bool TryParse(System.ReadOnlySpan input, out System.Guid result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? provider, out System.Guid result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, out System.Guid result) { throw null; } diff --git a/src/libraries/System.Runtime/tests/System/GuidTests.cs b/src/libraries/System.Runtime/tests/System/GuidTests.cs index 12742ad5df1f1..f71efb5d0e8df 100644 --- a/src/libraries/System.Runtime/tests/System/GuidTests.cs +++ b/src/libraries/System.Runtime/tests/System/GuidTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Text; using Xunit; namespace System.Tests @@ -847,6 +848,12 @@ public static void TryFormat_InvalidFormat_ThrowsFormatException(string format) { Assert.Throws(() => s_testGuid.TryFormat(new Span(), out int charsWritten, format)); Assert.Throws(() => s_testGuid.TryFormat(new Span(), out int charsWritten, format.ToUpperInvariant())); + + Assert.Throws(() => ((ISpanFormattable)s_testGuid).TryFormat(new Span(), out int charsWritten, format, null)); + Assert.Throws(() => ((ISpanFormattable)s_testGuid).TryFormat(new Span(), out int charsWritten, format.ToUpperInvariant(), null)); + + Assert.Throws(() => s_testGuid.TryFormat(new Span(), out int bytesWritten, format)); + Assert.Throws(() => s_testGuid.TryFormat(new Span(), out int bytesWritten, format.ToUpperInvariant())); } [Theory] @@ -854,8 +861,18 @@ public static void TryFormat_InvalidFormat_ThrowsFormatException(string format) public static void TryFormat_LengthTooSmall_ReturnsFalse(Guid guid, string format, string expected) { _ = expected; + Assert.False(guid.TryFormat(new Span(new char[guid.ToString(format).Length - 1]), out int charsWritten, format)); Assert.Equal(0, charsWritten); + + Assert.False(((ISpanFormattable)guid).TryFormat(new Span(new char[guid.ToString(format).Length - 1]), out charsWritten, format, null)); + Assert.Equal(0, charsWritten); + + Assert.False(guid.TryFormat(new Span(new byte[guid.ToString(format).Length - 1]), out int bytesWritten, format)); + Assert.Equal(0, bytesWritten); + + Assert.False(((IUtf8SpanFormattable)guid).TryFormat(new Span(new byte[guid.ToString(format).Length - 1]), out bytesWritten, format, null)); + Assert.Equal(0, bytesWritten); } [Theory] @@ -863,17 +880,45 @@ public static void TryFormat_LengthTooSmall_ReturnsFalse(Guid guid, string forma public static void TryFormat_CharsWritten_EqualsZero_WhenSpanTooSmall(Guid guid, string format, string expected) { _ = expected; + Assert.False(guid.TryFormat(new Span(new char[guid.ToString(format).Length - 1]), out int charsWritten, format)); Assert.Equal(0, charsWritten); + + Assert.False(((ISpanFormattable)guid).TryFormat(new Span(new char[guid.ToString(format).Length - 1]), out charsWritten, format, null)); + Assert.Equal(0, charsWritten); + + Assert.False(guid.TryFormat(new Span(new byte[guid.ToString(format).Length - 1]), out int bytesWritten, format)); + Assert.Equal(0, bytesWritten); + + Assert.False(((IUtf8SpanFormattable)guid).TryFormat(new Span(new byte[guid.ToString(format).Length - 1]), out bytesWritten, format, null)); + Assert.Equal(0, bytesWritten); } [Theory] [MemberData(nameof(ToString_TestData))] public static void TryFormat_ValidLength_ReturnsTrue(Guid guid, string format, string expected) { - char[] chars = new char[guid.ToString(format).Length]; - Assert.True(guid.TryFormat(new Span(chars), out int charsWritten, format)); - Assert.Equal(chars, expected.ToCharArray()); + for (int additionalSpace = 0; additionalSpace < 2; additionalSpace++) + { + char[] chars = new char[expected.Length + additionalSpace]; + byte[] bytes = new byte[expected.Length + additionalSpace]; + + Assert.True(guid.TryFormat(new Span(chars), out int charsWritten, format)); + Assert.Equal(expected.Length, charsWritten); + Assert.Equal(expected, chars.AsSpan(0, charsWritten).ToString()); + + Assert.True(((ISpanFormattable)guid).TryFormat(new Span(chars), out charsWritten, format, null)); + Assert.Equal(expected.Length, charsWritten); + Assert.Equal(expected, chars.AsSpan(0, charsWritten).ToString()); + + Assert.True(guid.TryFormat(new Span(bytes), out int bytesWritten, format)); + Assert.Equal(expected.Length, bytesWritten); + Assert.Equal(expected, Encoding.UTF8.GetString(bytes.AsSpan(0, bytesWritten))); + + Assert.True(((IUtf8SpanFormattable)guid).TryFormat(new Span(bytes), out bytesWritten, format, null)); + Assert.Equal(expected.Length, bytesWritten); + Assert.Equal(expected, Encoding.UTF8.GetString(bytes.AsSpan(0, bytesWritten))); + } } } } From bee65d373e98b6cec39abec54d2eade98b0a03c6 Mon Sep 17 00:00:00 2001 From: Weihan Li Date: Mon, 17 Apr 2023 01:56:02 +0800 Subject: [PATCH 08/32] fix a typo (#84897) --- .../src/System/Diagnostics/DistributedContextPropagator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DistributedContextPropagator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DistributedContextPropagator.cs index 087fb38a320c0..edcfabca1e023 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DistributedContextPropagator.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DistributedContextPropagator.cs @@ -42,7 +42,7 @@ public abstract class DistributedContextPropagator public abstract IReadOnlyCollection Fields { get; } /// - /// Injects the trace values stroed in the object into a carrier. For example, into the headers of an HTTP request. + /// Injects the trace values stored in the object into a carrier. For example, into the headers of an HTTP request. /// /// The Activity object has the distributed context to inject to the carrier. /// Carrier is the medium in which the distributed context will be stored. From 0099ffa86bc252262530f1245ba16890057875f7 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Sun, 16 Apr 2023 18:05:21 -0700 Subject: [PATCH 09/32] Revert use of raw pointers in System.Text.Json (#78741)" (#84899) Revert use of raw pointers for .NET Standard support. This particular raw pointer use does not work with .NET UWP toolchain. Also, convert uses of Enum.HasFlags to simple bit tests for better .NET Framework and .NET Standard support. Enum.HasFlags performs poorly (boxes) on .NET Framework and .NET Standard targets. Fixes #84895 --- .../Collection/JsonCollectionConverter.cs | 8 +-- .../Collection/JsonDictionaryConverter.cs | 4 +- .../Object/ObjectDefaultConverter.cs | 4 +- ...ctWithParameterizedConstructorConverter.cs | 4 +- .../Converters/Value/EnumConverter.cs | 51 ++++++++++--------- .../JsonConverter.MetadataHandling.cs | 2 +- .../JsonSerializer.Read.HandleMetadata.cs | 4 +- 7 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonCollectionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonCollectionConverter.cs index d7153aeb94427..e87b7f1c651c1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonCollectionConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonCollectionConverter.cs @@ -161,7 +161,7 @@ internal override bool OnTryRead( } // Dispatch to any polymorphic converters: should always be entered regardless of ObjectState progress - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Type) && + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Type) != 0 && state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStarted && ResolvePolymorphicConverter(jsonTypeInfo, ref state) is JsonConverter polymorphicConverter) { @@ -181,7 +181,7 @@ internal override bool OnTryRead( CreateCollection(ref reader, ref state, options); - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Id)) + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Id) != 0) { Debug.Assert(state.ReferenceId != null); Debug.Assert(options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.Preserve); @@ -245,7 +245,7 @@ internal override bool OnTryRead( state.Current.ObjectState = StackFrameObjectState.EndToken; // Array payload is nested inside a $values metadata property. - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Values)) + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Values) != 0) { if (!reader.Read()) { @@ -258,7 +258,7 @@ internal override bool OnTryRead( if (state.Current.ObjectState < StackFrameObjectState.EndTokenValidation) { // Array payload is nested inside a $values metadata property. - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Values)) + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Values) != 0) { if (reader.TokenType != JsonTokenType.EndObject) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonDictionaryConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonDictionaryConverter.cs index e1dbc744f2180..d6375439d8df5 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonDictionaryConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonDictionaryConverter.cs @@ -185,7 +185,7 @@ internal sealed override bool OnTryRead( } // Dispatch to any polymorphic converters: should always be entered regardless of ObjectState progress - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Type) && + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Type) != 0 && state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStarted && ResolvePolymorphicConverter(jsonTypeInfo, ref state) is JsonConverter polymorphicConverter) { @@ -206,7 +206,7 @@ internal sealed override bool OnTryRead( CreateCollection(ref reader, ref state); - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Id)) + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Id) != 0) { Debug.Assert(state.ReferenceId != null); Debug.Assert(options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.Preserve); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs index 2568f58560b0c..1a3ddf380b49c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs @@ -102,7 +102,7 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, } // Dispatch to any polymorphic converters: should always be entered regardless of ObjectState progress - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Type) && + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Type) != 0 && state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStarted && ResolvePolymorphicConverter(jsonTypeInfo, ref state) is JsonConverter polymorphicConverter) { @@ -133,7 +133,7 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, obj = jsonTypeInfo.CreateObject()!; - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Id)) + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Id) != 0) { Debug.Assert(state.ReferenceId != null); Debug.Assert(options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.Preserve); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.cs index 064a9a6d5ba5a..0edf2d220d8fc 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.cs @@ -132,7 +132,7 @@ internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToCo } // Dispatch to any polymorphic converters: should always be entered regardless of ObjectState progress - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Type) && + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Type) != 0 && state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStarted && ResolvePolymorphicConverter(jsonTypeInfo, ref state) is JsonConverter polymorphicConverter) { @@ -170,7 +170,7 @@ internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToCo obj = (T)CreateObject(ref state.Current); - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Id)) + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Id) != 0) { Debug.Assert(state.ReferenceId != null); Debug.Assert(options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.Preserve); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs index 4a5edd193f6ca..08d3e37e975d5 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs @@ -5,6 +5,7 @@ using System.Collections.Concurrent; using System.Diagnostics; using System.Globalization; +using System.Runtime.CompilerServices; using System.Text.Encodings.Web; namespace System.Text.Json.Serialization.Converters @@ -93,14 +94,13 @@ public EnumConverter(EnumConverterOptions converterOptions, JsonNamingPolicy? na } } -#pragma warning disable 8500 // address of managed types - public override unsafe T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { JsonTokenType token = reader.TokenType; if (token == JsonTokenType.String) { - if (!_converterOptions.HasFlag(EnumConverterOptions.AllowStrings)) + if ((_converterOptions & EnumConverterOptions.AllowStrings) == 0) { ThrowHelper.ThrowJsonException(); return default; @@ -122,7 +122,7 @@ public override unsafe T Read(ref Utf8JsonReader reader, Type typeToConvert, Jso #endif } - if (token != JsonTokenType.Number || !_converterOptions.HasFlag(EnumConverterOptions.AllowNumbers)) + if (token != JsonTokenType.Number || (_converterOptions & EnumConverterOptions.AllowNumbers) == 0) { ThrowHelper.ThrowJsonException(); return default; @@ -135,49 +135,51 @@ public override unsafe T Read(ref Utf8JsonReader reader, Type typeToConvert, Jso case TypeCode.Int32: if (reader.TryGetInt32(out int int32)) { - return *(T*)&int32; + // Use Unsafe.As instead of raw pointers for .NET Standard support. + // https://github.com/dotnet/runtime/issues/84895 + return Unsafe.As(ref int32); } break; case TypeCode.UInt32: if (reader.TryGetUInt32(out uint uint32)) { - return *(T*)&uint32; + return Unsafe.As(ref uint32); } break; case TypeCode.UInt64: if (reader.TryGetUInt64(out ulong uint64)) { - return *(T*)&uint64; + return Unsafe.As(ref uint64); } break; case TypeCode.Int64: if (reader.TryGetInt64(out long int64)) { - return *(T*)&int64; + return Unsafe.As(ref int64); } break; case TypeCode.SByte: if (reader.TryGetSByte(out sbyte byte8)) { - return *(T*)&byte8; + return Unsafe.As(ref byte8); } break; case TypeCode.Byte: if (reader.TryGetByte(out byte ubyte8)) { - return *(T*)&ubyte8; + return Unsafe.As(ref ubyte8); } break; case TypeCode.Int16: if (reader.TryGetInt16(out short int16)) { - return *(T*)&int16; + return Unsafe.As(ref int16); } break; case TypeCode.UInt16: if (reader.TryGetUInt16(out ushort uint16)) { - return *(T*)&uint16; + return Unsafe.As(ref uint16); } break; } @@ -186,10 +188,10 @@ public override unsafe T Read(ref Utf8JsonReader reader, Type typeToConvert, Jso return default; } - public override unsafe void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { // If strings are allowed, attempt to write it out as a string value - if (_converterOptions.HasFlag(EnumConverterOptions.AllowStrings)) + if ((_converterOptions & EnumConverterOptions.AllowStrings) != 0) { ulong key = ConvertToUInt64(value); @@ -226,7 +228,7 @@ public override unsafe void Write(Utf8JsonWriter writer, T value, JsonSerializer } } - if (!_converterOptions.HasFlag(EnumConverterOptions.AllowNumbers)) + if ((_converterOptions & EnumConverterOptions.AllowNumbers) == 0) { ThrowHelper.ThrowJsonException(); } @@ -234,35 +236,36 @@ public override unsafe void Write(Utf8JsonWriter writer, T value, JsonSerializer switch (s_enumTypeCode) { case TypeCode.Int32: - writer.WriteNumberValue(*(int*)&value); + // Use Unsafe.As instead of raw pointers for .NET Standard support. + // https://github.com/dotnet/runtime/issues/84895 + writer.WriteNumberValue(Unsafe.As(ref value)); break; case TypeCode.UInt32: - writer.WriteNumberValue(*(uint*)&value); + writer.WriteNumberValue(Unsafe.As(ref value)); break; case TypeCode.UInt64: - writer.WriteNumberValue(*(ulong*)&value); + writer.WriteNumberValue(Unsafe.As(ref value)); break; case TypeCode.Int64: - writer.WriteNumberValue(*(long*)&value); + writer.WriteNumberValue(Unsafe.As(ref value)); break; case TypeCode.Int16: - writer.WriteNumberValue(*(short*)&value); + writer.WriteNumberValue(Unsafe.As(ref value)); break; case TypeCode.UInt16: - writer.WriteNumberValue(*(ushort*)&value); + writer.WriteNumberValue(Unsafe.As(ref value)); break; case TypeCode.Byte: - writer.WriteNumberValue(*(byte*)&value); + writer.WriteNumberValue(Unsafe.As(ref value)); break; case TypeCode.SByte: - writer.WriteNumberValue(*(sbyte*)&value); + writer.WriteNumberValue(Unsafe.As(ref value)); break; default: ThrowHelper.ThrowJsonException(); break; } } -#pragma warning restore 8500 internal override T ReadAsPropertyNameCore(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.MetadataHandling.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.MetadataHandling.cs index 74345fa12ccb7..6a3de620ae1d0 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.MetadataHandling.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.MetadataHandling.cs @@ -15,7 +15,7 @@ public partial class JsonConverter { Debug.Assert(!IsValueType); Debug.Assert(CanHaveMetadata); - Debug.Assert(state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Type)); + Debug.Assert((state.Current.MetadataPropertyNames & MetadataPropertyName.Type) != 0); Debug.Assert(state.Current.PolymorphicSerializationState != PolymorphicSerializationState.PolymorphicReEntryStarted); Debug.Assert(jsonTypeInfo.PolymorphicTypeResolver?.UsesTypeDiscriminators == true); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs index 4326af6da116a..c9a9e6015fe19 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs @@ -50,7 +50,7 @@ internal static bool TryReadMetadata(JsonConverter converter, JsonTypeInfo jsonT // We just read a property. The only valid next tokens are EndObject and PropertyName. Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Ref)) + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Ref) != 0) { // No properties whatsoever should follow a $ref property. ThrowHelper.ThrowJsonException_MetadataReferenceObjectCannotContainOtherProperties(reader.GetSpan(), ref state); @@ -427,7 +427,7 @@ static string ReadAsStringMetadataValue(JsonNode? jsonNode) internal static void ValidateMetadataForObjectConverter(ref ReadStack state) { - if (state.Current.MetadataPropertyNames.HasFlag(MetadataPropertyName.Values)) + if ((state.Current.MetadataPropertyNames & MetadataPropertyName.Values) != 0) { // Object converters do not support $values metadata. ThrowHelper.ThrowJsonException_MetadataUnexpectedProperty(s_valuesPropertyName, ref state); From f92b9ef636a4cc9599b33446e30e7a489591ca46 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Mon, 17 Apr 2023 04:30:24 +0300 Subject: [PATCH 10/32] Generate SslConnectionInfo.Unix.cs with T4 template (#84690) * Generate SslConnectionInfo.Unix.cs with T4 template * Try fitting into ushort --- .../src/System.Net.Security.csproj | 16 +- .../Net/Security/SslConnectionInfo.Unix.cs | 378 +- .../Net/Security/SslConnectionInfo.Unix.tt | 91 + .../Net/Security/TlsCipherSuiteData.Lookup.cs | 3394 ----------------- .../Net/Security/TlsCipherSuiteData.Lookup.tt | 45 - .../System/Net/Security/TlsCipherSuiteData.cs | 70 - .../TlsCipherSuiteNameParser.ttinclude | 32 + 7 files changed, 500 insertions(+), 3526 deletions(-) create mode 100644 src/libraries/System.Net.Security/src/System/Net/Security/SslConnectionInfo.Unix.tt delete mode 100644 src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.Lookup.cs delete mode 100644 src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.Lookup.tt delete mode 100644 src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.cs diff --git a/src/libraries/System.Net.Security/src/System.Net.Security.csproj b/src/libraries/System.Net.Security/src/System.Net.Security.csproj index 56bf536c440c1..54f8c9feeb4d6 100644 --- a/src/libraries/System.Net.Security/src/System.Net.Security.csproj +++ b/src/libraries/System.Net.Security/src/System.Net.Security.csproj @@ -122,17 +122,17 @@ - + True True - TlsCipherSuiteData.Lookup.tt + SslConnectionInfo.Unix.tt - + True True - TlsCipherSuiteData.Lookup.tt + SslConnectionInfo.Unix.tt @@ -140,14 +140,14 @@ TextTemplatingFileGenerator TlsCipherSuite.cs - + TextTemplatingFileGenerator - TlsCipherSuiteData.Lookup.cs + SslConnectionInfo.Unix.cs - + @@ -285,8 +285,6 @@ Link="Common\System\Net\Security\Unix\SecChannelBindings.cs" /> - - keyExchangeAlgs = + new[] { (int)ExchangeAlgorithmType.None, (int)ExchangeAlgorithmType.RsaSign, (int)ExchangeAlgorithmType.RsaKeyX, (int)ExchangeAlgorithmType.DiffieHellman, }; + ReadOnlySpan dataCipherAlgs = + new[] { (int)CipherAlgorithmType.None, (int)CipherAlgorithmType.Null, (int)CipherAlgorithmType.Des, (int)CipherAlgorithmType.Rc2, (int)CipherAlgorithmType.TripleDes, (int)CipherAlgorithmType.Aes128, (int)CipherAlgorithmType.Aes192, (int)CipherAlgorithmType.Aes256, (int)CipherAlgorithmType.Aes, (int)CipherAlgorithmType.Rc4, }; + ReadOnlySpan dataKeySizes = + new[] { 0, 40, 56, 128, 168, 256 }; + ReadOnlySpan dataHashAlgs = + new[] { (int)HashAlgorithmType.None, (int)HashAlgorithmType.Md5, (int)HashAlgorithmType.Sha1, (int)HashAlgorithmType.Sha256, (int)HashAlgorithmType.Sha384, (int)HashAlgorithmType.Sha512, }; + ReadOnlySpan dataHashKeySizes = + new[] { 0, 128, 160, 256, 384, 512 }; + + int data = GetPackedData(cipherSuite); + Debug.Assert(data != 0, $"No mapping found for cipherSuite {cipherSuite}"); + + KeyExchangeAlg = keyExchangeAlgs[(data >> 12) & 0xF]; + DataCipherAlg = dataCipherAlgs[(data >> 8) & 0xF]; + DataKeySize = dataKeySizes[(data >> 4) & 0xF]; + DataHashAlg = dataHashAlgs[data & 0xF]; + DataHashKeySize = dataHashKeySizes[data & 0xF]; + + static int GetPackedData(TlsCipherSuite cipherSuite) + { + switch (cipherSuite) + { + case TlsCipherSuite.TLS_NULL_WITH_NULL_NULL: return 0 << 12 | 1 << 8 | 0 << 4 | 0; + case TlsCipherSuite.TLS_RSA_WITH_NULL_MD5: return 2 << 12 | 1 << 8 | 0 << 4 | 1; + case TlsCipherSuite.TLS_RSA_WITH_NULL_SHA: return 2 << 12 | 1 << 8 | 0 << 4 | 2; + case TlsCipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5: return 2 << 12 | 9 << 8 | 1 << 4 | 1; + case TlsCipherSuite.TLS_RSA_WITH_RC4_128_MD5: return 2 << 12 | 9 << 8 | 3 << 4 | 1; + case TlsCipherSuite.TLS_RSA_WITH_RC4_128_SHA: return 2 << 12 | 9 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5: return 2 << 12 | 3 << 8 | 1 << 4 | 1; + case TlsCipherSuite.TLS_RSA_WITH_IDEA_CBC_SHA: return 2 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA: return 2 << 12 | 2 << 8 | 1 << 4 | 2; + case TlsCipherSuite.TLS_RSA_WITH_DES_CBC_SHA: return 2 << 12 | 2 << 8 | 2 << 4 | 2; + case TlsCipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA: return 2 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: return 3 << 12 | 2 << 8 | 1 << 4 | 2; + case TlsCipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA: return 3 << 12 | 2 << 8 | 2 << 4 | 2; + case TlsCipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: return 3 << 12 | 2 << 8 | 1 << 4 | 2; + case TlsCipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA: return 3 << 12 | 2 << 8 | 2 << 4 | 2; + case TlsCipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: return 3 << 12 | 2 << 8 | 1 << 4 | 2; + case TlsCipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA: return 3 << 12 | 2 << 8 | 2 << 4 | 2; + case TlsCipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: return 3 << 12 | 2 << 8 | 1 << 4 | 2; + case TlsCipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA: return 3 << 12 | 2 << 8 | 2 << 4 | 2; + case TlsCipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_DH_anon_EXPORT_WITH_RC4_40_MD5: return 3 << 12 | 9 << 8 | 1 << 4 | 1; + case TlsCipherSuite.TLS_DH_anon_WITH_RC4_128_MD5: return 3 << 12 | 9 << 8 | 3 << 4 | 1; + case TlsCipherSuite.TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA: return 3 << 12 | 2 << 8 | 1 << 4 | 2; + case TlsCipherSuite.TLS_DH_anon_WITH_DES_CBC_SHA: return 3 << 12 | 2 << 8 | 2 << 4 | 2; + case TlsCipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_KRB5_WITH_DES_CBC_SHA: return 0 << 12 | 2 << 8 | 2 << 4 | 2; + case TlsCipherSuite.TLS_KRB5_WITH_3DES_EDE_CBC_SHA: return 0 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_KRB5_WITH_RC4_128_SHA: return 0 << 12 | 9 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_KRB5_WITH_IDEA_CBC_SHA: return 0 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_KRB5_WITH_DES_CBC_MD5: return 0 << 12 | 2 << 8 | 2 << 4 | 1; + case TlsCipherSuite.TLS_KRB5_WITH_3DES_EDE_CBC_MD5: return 0 << 12 | 4 << 8 | 4 << 4 | 1; + case TlsCipherSuite.TLS_KRB5_WITH_RC4_128_MD5: return 0 << 12 | 9 << 8 | 3 << 4 | 1; + case TlsCipherSuite.TLS_KRB5_WITH_IDEA_CBC_MD5: return 0 << 12 | 0 << 8 | 3 << 4 | 1; + case TlsCipherSuite.TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA: return 0 << 12 | 2 << 8 | 1 << 4 | 2; + case TlsCipherSuite.TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA: return 0 << 12 | 3 << 8 | 1 << 4 | 2; + case TlsCipherSuite.TLS_KRB5_EXPORT_WITH_RC4_40_SHA: return 0 << 12 | 9 << 8 | 1 << 4 | 2; + case TlsCipherSuite.TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5: return 0 << 12 | 2 << 8 | 1 << 4 | 1; + case TlsCipherSuite.TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5: return 0 << 12 | 3 << 8 | 1 << 4 | 1; + case TlsCipherSuite.TLS_KRB5_EXPORT_WITH_RC4_40_MD5: return 0 << 12 | 9 << 8 | 1 << 4 | 1; + case TlsCipherSuite.TLS_PSK_WITH_NULL_SHA: return 0 << 12 | 1 << 8 | 0 << 4 | 2; + case TlsCipherSuite.TLS_DHE_PSK_WITH_NULL_SHA: return 3 << 12 | 1 << 8 | 0 << 4 | 2; + case TlsCipherSuite.TLS_RSA_PSK_WITH_NULL_SHA: return 2 << 12 | 1 << 8 | 0 << 4 | 2; + case TlsCipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA: return 2 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA: return 2 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_RSA_WITH_NULL_SHA256: return 2 << 12 | 1 << 8 | 0 << 4 | 3; + case TlsCipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256: return 2 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256: return 2 << 12 | 7 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: return 2 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA: return 3 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA: return 3 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: return 3 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: return 3 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA: return 3 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256: return 3 << 12 | 7 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256: return 3 << 12 | 7 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: return 3 << 12 | 7 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: return 3 << 12 | 7 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: return 3 << 12 | 7 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: return 2 << 12 | 0 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA: return 3 << 12 | 0 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA: return 3 << 12 | 0 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: return 3 << 12 | 0 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: return 3 << 12 | 0 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA: return 3 << 12 | 0 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_PSK_WITH_RC4_128_SHA: return 0 << 12 | 9 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA: return 0 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA: return 0 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA: return 0 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA: return 3 << 12 | 9 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA: return 2 << 12 | 9 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: return 2 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA: return 2 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA: return 2 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_RSA_WITH_SEED_CBC_SHA: return 2 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA: return 3 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA: return 3 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA: return 3 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA: return 3 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA: return 3 << 12 | 0 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256: return 2 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384: return 2 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256: return 0 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384: return 0 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: return 2 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: return 2 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256: return 0 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384: return 0 << 12 | 7 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_PSK_WITH_NULL_SHA256: return 0 << 12 | 1 << 8 | 0 << 4 | 3; + case TlsCipherSuite.TLS_PSK_WITH_NULL_SHA384: return 0 << 12 | 1 << 8 | 0 << 4 | 4; + case TlsCipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256: return 3 << 12 | 1 << 8 | 0 << 4 | 3; + case TlsCipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384: return 3 << 12 | 1 << 8 | 0 << 4 | 4; + case TlsCipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256: return 2 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: return 2 << 12 | 7 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256: return 2 << 12 | 1 << 8 | 0 << 4 | 3; + case TlsCipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384: return 2 << 12 | 1 << 8 | 0 << 4 | 4; + case TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: return 2 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: return 2 << 12 | 0 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256: return 3 << 12 | 0 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256: return 3 << 12 | 0 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256: return 3 << 12 | 0 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: return 3 << 12 | 0 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256: return 3 << 12 | 0 << 8 | 5 << 4 | 3; + case TlsCipherSuite.TLS_AES_128_GCM_SHA256: return 0 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_AES_256_GCM_SHA384: return 0 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_CHACHA20_POLY1305_SHA256: return 0 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_AES_128_CCM_SHA256: return 0 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_AES_128_CCM_8_SHA256: return 0 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA: return 3 << 12 | 1 << 8 | 0 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA: return 3 << 12 | 9 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA: return 3 << 12 | 1 << 8 | 0 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: return 3 << 12 | 9 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA: return 3 << 12 | 1 << 8 | 0 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA: return 3 << 12 | 9 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA: return 3 << 12 | 1 << 8 | 0 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA: return 3 << 12 | 9 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_anon_WITH_NULL_SHA: return 3 << 12 | 1 << 8 | 0 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA: return 3 << 12 | 9 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: return 0 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: return 0 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: return 0 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA: return 0 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: return 0 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: return 0 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA: return 0 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: return 0 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: return 0 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA: return 3 << 12 | 9 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA: return 3 << 12 | 4 << 8 | 4 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA: return 3 << 12 | 5 << 8 | 3 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA: return 3 << 12 | 7 << 8 | 5 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA: return 3 << 12 | 1 << 8 | 0 << 4 | 2; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256: return 3 << 12 | 1 << 8 | 0 << 4 | 3; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384: return 3 << 12 | 1 << 8 | 0 << 4 | 4; + case TlsCipherSuite.TLS_RSA_WITH_ARIA_128_CBC_SHA256: return 2 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_RSA_WITH_ARIA_256_CBC_SHA384: return 2 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_DH_anon_WITH_ARIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DH_anon_WITH_ARIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_RSA_WITH_ARIA_128_GCM_SHA256: return 2 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_RSA_WITH_ARIA_256_GCM_SHA384: return 2 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DH_anon_WITH_ARIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DH_anon_WITH_ARIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_ARIA_128_CBC_SHA256: return 0 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_PSK_WITH_ARIA_256_CBC_SHA384: return 0 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256: return 2 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384: return 2 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_PSK_WITH_ARIA_128_GCM_SHA256: return 0 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_ARIA_256_GCM_SHA384: return 0 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256: return 2 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384: return 2 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256: return 2 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: return 2 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256: return 0 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384: return 0 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256: return 2 << 12 | 0 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384: return 2 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256: return 0 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384: return 0 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256: return 2 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384: return 2 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256: return 3 << 12 | 0 << 8 | 3 << 4 | 3; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: return 3 << 12 | 0 << 8 | 5 << 4 | 4; + case TlsCipherSuite.TLS_RSA_WITH_AES_128_CCM: return 2 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_RSA_WITH_AES_256_CCM: return 2 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_RSA_WITH_AES_128_CCM_8: return 2 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_RSA_WITH_AES_256_CCM_8: return 2 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_AES_128_CCM: return 0 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_AES_256_CCM: return 0 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_AES_128_CCM_8: return 0 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_AES_256_CCM_8: return 0 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECCPWD_WITH_AES_128_GCM_SHA256: return 0 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECCPWD_WITH_AES_256_GCM_SHA384: return 0 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECCPWD_WITH_AES_128_CCM_SHA256: return 0 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECCPWD_WITH_AES_256_CCM_SHA384: return 0 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_PSK_WITH_CHACHA20_POLY1305_SHA256: return 0 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256: return 3 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256: return 2 << 12 | 0 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384: return 3 << 12 | 7 << 8 | 5 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + case TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256: return 3 << 12 | 5 << 8 | 3 << 4 | 0; + default: return 0; + } + } } } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslConnectionInfo.Unix.tt b/src/libraries/System.Net.Security/src/System/Net/Security/SslConnectionInfo.Unix.tt new file mode 100644 index 0000000000000..6d853177e69c4 --- /dev/null +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslConnectionInfo.Unix.tt @@ -0,0 +1,91 @@ +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ import namespace="System" #> +<#@ assembly name="System.Core" #> +<#@ assembly name="System.Net.Primitives" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<#@ include file="TlsCipherSuiteNameParser.ttinclude" #><#@ + include file="TlsCipherSuite.cs" #> +<# Array tlsEnumValues = typeof(TlsCipherSuite).GetEnumValues(); #> +<# Array exchangeEnumValues = typeof(ExchangeAlgorithmTypeIndex).GetEnumValues(); #> +<# Array dataCipherAlgs = typeof(CipherAlgorithmTypeIndex).GetEnumValues(); #> +<# Array dataHashAlgs = typeof(HashAlgorithmTypeIndex).GetEnumValues(); #> + + +using System.Diagnostics; +using System.Security.Authentication; + +namespace System.Net.Security +{ + internal partial struct SslConnectionInfo + { + private void MapCipherSuite(TlsCipherSuite cipherSuite) + { + TlsCipherSuite = cipherSuite; + KeyExchKeySize = 0; + ReadOnlySpan keyExchangeAlgs = + new[] { <# +foreach (ExchangeAlgorithmTypeIndex val in exchangeEnumValues) +{ + #>(int)ExchangeAlgorithmType.<#= val #>, <# +} + #>}; + ReadOnlySpan dataCipherAlgs = + new[] { <# +foreach (CipherAlgorithmTypeIndex val in dataCipherAlgs) +{ + #>(int)CipherAlgorithmType.<#= val #>, <# +} + #>}; +<# +ReadOnlySpan strengths = new[] { 0, 40, 56, 128, 168, 256 }; +#> + ReadOnlySpan dataKeySizes = + new[] { <#= string.Join(", ", strengths.ToArray()) #> }; + ReadOnlySpan dataHashAlgs = + new[] { <# +foreach (HashAlgorithmTypeIndex val in dataHashAlgs) +{ + #>(int)HashAlgorithmType.<#= val #>, <# +} + #>}; + ReadOnlySpan dataHashKeySizes = + new[] { 0, 128, 160, 256, 384, 512 }; + + int data = GetPackedData(cipherSuite); + Debug.Assert(data != 0, $"No mapping found for cipherSuite {cipherSuite}"); + + KeyExchangeAlg = keyExchangeAlgs[(data >> 12) & 0xF]; + DataCipherAlg = dataCipherAlgs[(data >> 8) & 0xF]; + DataKeySize = dataKeySizes[(data >> 4) & 0xF]; + DataHashAlg = dataHashAlgs[data & 0xF]; + DataHashKeySize = dataHashKeySizes[data & 0xF]; + + static int GetPackedData(TlsCipherSuite cipherSuite) + { + switch (cipherSuite) + { +<# +foreach (TlsCipherSuite val in tlsEnumValues) +{ + TlsCipherSuiteData data = new CipherSuiteNameData(val.ToString()).Data; + int exchangeAlgorithmType = (int)Enum.Parse(EnumHelpers.ToFrameworkName(data.KeyExchangeAlgorithm)); + int cipherAlgorithmType = (int)Enum.Parse(EnumHelpers.ToFrameworkName(data.CipherAlgorithm)); + int cipherAlgorithmStrength = (int)strengths.IndexOf(data.CipherAlgorithmStrength); + int hashAlgorithmType = (int)Enum.Parse(EnumHelpers.ToFrameworkName(data.MACAlgorithm)); + + if (cipherAlgorithmStrength == -1) + throw new Exception($"Value '{data.CipherAlgorithmStrength}' is not found in 'strengths' array."); +#> + case TlsCipherSuite.<#= val #>: return <#= exchangeAlgorithmType #> << 12 | <#= cipherAlgorithmType #> << 8 | <#= cipherAlgorithmStrength #> << 4 | <#= hashAlgorithmType #>; +<# +} +#> + default: return 0; + } + } + } + } +} diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.Lookup.cs b/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.Lookup.cs deleted file mode 100644 index 9a97c04b1b634..0000000000000 --- a/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.Lookup.cs +++ /dev/null @@ -1,3394 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// This file has been auto-generated. Do not edit by hand. -// Instead open Developer Command prompt and run: TextTransform FileName.tt -// Or set AllowTlsCipherSuiteGeneration=true and open VS and edit there directly - -// This line is needed so that file compiles both as a T4 template and C# file - -using System.Collections.Generic; -using System.Security.Authentication; - -namespace System.Net.Security -{ - internal partial struct TlsCipherSuiteData - { - private const int LookupCount = 337; - - private static readonly Dictionary s_tlsLookup = - new Dictionary(LookupCount) - { - { - TlsCipherSuite.TLS_NULL_WITH_NULL_NULL, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_NULL_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_NULL_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_RC4_128_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_RC4_128_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Rc2, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_IDEA_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_DES_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 56, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 56, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 56, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 56, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 56, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_anon_EXPORT_WITH_RC4_40_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_RC4_128_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_DES_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 56, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_KRB5_WITH_DES_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 56, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_KRB5_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_KRB5_WITH_RC4_128_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_KRB5_WITH_IDEA_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_KRB5_WITH_DES_CBC_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 56, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_KRB5_WITH_3DES_EDE_CBC_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_KRB5_WITH_RC4_128_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_KRB5_WITH_IDEA_CBC_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Rc2, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_KRB5_EXPORT_WITH_RC4_40_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Des, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Rc2, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_KRB5_EXPORT_WITH_RC4_40_MD5, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 40, - MACAlgorithm = HashAlgorithmType.Md5, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_NULL_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_NULL_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_NULL_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_NULL_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_RC4_128_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_SEED_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_NULL_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_NULL_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_CHACHA20_POLY1305_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_AES_128_CCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_AES_128_CCM_8_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_anon_WITH_NULL_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Rc4, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.TripleDes, - CipherAlgorithmStrength = 168, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha1, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Null, - CipherAlgorithmStrength = 0, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.Sha256, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.Sha384, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_AES_128_CCM, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_AES_256_CCM, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_AES_128_CCM_8, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_WITH_AES_256_CCM_8, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_AES_128_CCM, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_AES_256_CCM, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_AES_128_CCM_8, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_AES_256_CCM_8, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECCPWD_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECCPWD_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECCPWD_WITH_AES_128_CCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECCPWD_WITH_AES_256_CCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.None, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.RsaKeyX, - CipherAlgorithm = CipherAlgorithmType.None, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes256, - CipherAlgorithmStrength = 256, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - { - TlsCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.DiffieHellman, - CipherAlgorithm = CipherAlgorithmType.Aes128, - CipherAlgorithmStrength = 128, - MACAlgorithm = HashAlgorithmType.None, - } - }, - }; - } -} diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.Lookup.tt b/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.Lookup.tt deleted file mode 100644 index a36c425ccb0a8..0000000000000 --- a/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.Lookup.tt +++ /dev/null @@ -1,45 +0,0 @@ -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ import namespace="System" #> -<#@ assembly name="System.Core" #> -<#@ assembly name="System.Net.Primitives" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> -<#@ output extension=".cs" #> -<#@ include file="TlsCipherSuiteNameParser.ttinclude" #><#@ - include file="TlsCipherSuite.cs" #> -<# Array enumValues = typeof(TlsCipherSuite).GetEnumValues(); #> - -using System.Collections.Generic; -using System.Security.Authentication; - -namespace System.Net.Security -{ - internal partial struct TlsCipherSuiteData - { - private const int LookupCount = <#= enumValues.Length #>; - - private static readonly Dictionary s_tlsLookup = - new Dictionary(LookupCount) - { -<# -foreach (TlsCipherSuite val in enumValues) -{ - TlsCipherSuiteData data = new CipherSuiteNameData(val.ToString()).Data; -#> - { - TlsCipherSuite.<#= val #>, - new TlsCipherSuiteData() - { - KeyExchangeAlgorithm = ExchangeAlgorithmType.<#= EnumHelpers.ToFrameworkName(data.KeyExchangeAlgorithm) #>, - CipherAlgorithm = CipherAlgorithmType.<#= EnumHelpers.ToFrameworkName(data.CipherAlgorithm) #>, - CipherAlgorithmStrength = <#= data.CipherAlgorithmStrength #>, - MACAlgorithm = HashAlgorithmType.<#= EnumHelpers.ToFrameworkName(data.MACAlgorithm) #>, - } - }, -<# -} -#> - }; - } -} diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.cs b/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.cs deleted file mode 100644 index c422b9a7528cb..0000000000000 --- a/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteData.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Diagnostics; -using System.Security.Authentication; - -namespace System.Net.Security -{ - internal partial struct TlsCipherSuiteData - { - internal ExchangeAlgorithmType KeyExchangeAlgorithm; - // The Key Exchange size isn't part of the CipherSuite - internal CipherAlgorithmType CipherAlgorithm; - internal int CipherAlgorithmStrength; - internal HashAlgorithmType MACAlgorithm; - internal int MACAlgorithmStrength => GetHashSize(MACAlgorithm); - -#if DEBUG - static TlsCipherSuiteData() - { - Debug.Assert( - s_tlsLookup.Count == LookupCount, - $"Lookup dictionary was of size {s_tlsLookup.Count} instead of {LookupCount}"); - - foreach (TlsCipherSuite value in Enum.GetValues()) - { - Debug.Assert(s_tlsLookup.ContainsKey(value), $"No mapping found for {value} ({value:X})"); - } - } - - public override string ToString() - { - return $"Kx={KeyExchangeAlgorithm} Enc={CipherAlgorithm} [{CipherAlgorithmStrength}] Mac={MACAlgorithm} [{MACAlgorithmStrength}]"; - } -#endif - - public static TlsCipherSuiteData GetCipherSuiteData(TlsCipherSuite cipherSuite) - { - if (s_tlsLookup.TryGetValue(cipherSuite, out TlsCipherSuiteData mapping)) - { - return mapping; - } - - Debug.Fail($"No mapping found for cipherSuite {cipherSuite}"); - return default(TlsCipherSuiteData); - } - - private static int GetHashSize(HashAlgorithmType hash) - { - switch (hash) - { - case HashAlgorithmType.None: - return 0; - case HashAlgorithmType.Md5: - return 128; - case HashAlgorithmType.Sha1: - return 160; - case HashAlgorithmType.Sha256: - return 256; - case HashAlgorithmType.Sha384: - return 384; - case HashAlgorithmType.Sha512: - return 512; - default: - throw new ArgumentOutOfRangeException(nameof(hash)); - } - } - } -} diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteNameParser.ttinclude b/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteNameParser.ttinclude index 7a3dee3296d80..a24c8a5b5d119 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteNameParser.ttinclude +++ b/src/libraries/System.Net.Security/src/System/Net/Security/TlsCipherSuiteNameParser.ttinclude @@ -70,6 +70,38 @@ public enum HashAlgorithmType Aead, } +public enum CipherAlgorithmTypeIndex +{ + None, + Null, + Des, + Rc2, + TripleDes, + Aes128, + Aes192, + Aes256, + Aes, + Rc4, +} + +public enum ExchangeAlgorithmTypeIndex +{ + None, + RsaSign, + RsaKeyX, + DiffieHellman, +} + +public enum HashAlgorithmTypeIndex +{ + None, + Md5, + Sha1, + Sha256, + Sha384, + Sha512 +} + internal static class EnumHelpers { public static string ToFrameworkName(ExchangeAlgorithmType val) From 7ce83de7a397cb9331242c178c687307c0e31f88 Mon Sep 17 00:00:00 2001 From: Dong-Heon Jung Date: Mon, 17 Apr 2023 14:51:51 +0900 Subject: [PATCH 11/32] [RISC-V] Fix build error (#84910) - Resolve assertion because size of DT_CONTEXT and T_CONTEXT is not equal --- src/coreclr/debug/inc/dbgtargetcontext.h | 1 + src/coreclr/inc/crosscomp.h | 5 ++--- src/coreclr/pal/inc/pal.h | 2 +- src/coreclr/vm/riscv64/asmconstants.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coreclr/debug/inc/dbgtargetcontext.h b/src/coreclr/debug/inc/dbgtargetcontext.h index fa6c7b92cb884..7f035463361d1 100644 --- a/src/coreclr/debug/inc/dbgtargetcontext.h +++ b/src/coreclr/debug/inc/dbgtargetcontext.h @@ -560,6 +560,7 @@ typedef DECLSPEC_ALIGN(16) struct { // /* +0x000 */ DWORD ContextFlags; + /* +0x004 */ DWORD Fcsr; // // Integer registers diff --git a/src/coreclr/inc/crosscomp.h b/src/coreclr/inc/crosscomp.h index 12adb32cc409d..bc208595be770 100644 --- a/src/coreclr/inc/crosscomp.h +++ b/src/coreclr/inc/crosscomp.h @@ -525,8 +525,7 @@ typedef struct _T_KNONVOLATILE_CONTEXT_POINTERS { // // Specify the number of breakpoints and watchpoints that the OS -// will track. Architecturally, LOONGARCH64 supports up to 16. In practice, -// however, almost no one implements more than 4 of each. +// will track. // #define RISCV64_MAX_BREAKPOINTS 8 @@ -541,6 +540,7 @@ typedef struct DECLSPEC_ALIGN(16) _T_CONTEXT { // /* +0x000 */ DWORD ContextFlags; + /* +0x004 */ DWORD Fcsr; // // Integer registers @@ -584,7 +584,6 @@ typedef struct DECLSPEC_ALIGN(16) _T_CONTEXT { // //TODO-RISCV64: support the SIMD. ULONGLONG F[32]; - DWORD Fcsr; } T_CONTEXT, *PT_CONTEXT; // _IMAGE_RISCV64_RUNTIME_FUNCTION_ENTRY (see ExternalAPIs\Win9CoreSystem\inc\winnt.h) diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index f96c671165c6f..82c5429493013 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -2280,6 +2280,7 @@ typedef struct DECLSPEC_ALIGN(16) _CONTEXT { // /* +0x000 */ DWORD ContextFlags; + /* +0x004 */ DWORD Fcsr; // // Integer registers. @@ -2323,7 +2324,6 @@ typedef struct DECLSPEC_ALIGN(16) _CONTEXT { // // TODO-RISCV64: support the SIMD. ULONGLONG F[32]; - DWORD Fcsr; } CONTEXT, *PCONTEXT, *LPCONTEXT; // diff --git a/src/coreclr/vm/riscv64/asmconstants.h b/src/coreclr/vm/riscv64/asmconstants.h index 12aedda2db5f8..e61abe2ea57e7 100644 --- a/src/coreclr/vm/riscv64/asmconstants.h +++ b/src/coreclr/vm/riscv64/asmconstants.h @@ -141,7 +141,7 @@ ASMCONSTANTS_C_ASSERT(SIZEOF__GSCookie == sizeof(GSCookie)); #define SIZEOF__Frame 0x10 ASMCONSTANTS_C_ASSERT(SIZEOF__Frame == sizeof(Frame)); -#define SIZEOF__CONTEXT 0x220 +#define SIZEOF__CONTEXT 0x210 ASMCONSTANTS_C_ASSERT(SIZEOF__CONTEXT == sizeof(T_CONTEXT)); From 23be50f86942679460fc945bf4aaf4c2610b4b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rylek?= Date: Mon, 17 Apr 2023 09:00:40 +0200 Subject: [PATCH 12/32] Baseline two systemic failures in the CoreCLR outerloop pipeline (#84904) On Windows arm, several tests typically fail in the coreclr-runtime outerloop pipeline. This change introduces issues.targets exclusions for two tests that fail all the time and apparently due to a different cause than the rest of the tests that involve non-deterministic nullrefs the cause of which hasn't yet been established to my knowledge. Thanks Tomas --- src/tests/issues.targets | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index b7214078e9c60..cbeecf67ed298 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -509,6 +509,12 @@ https://github.com/dotnet/runtime/issues/66745 + + https://github.com/dotnet/runtime/issues/84750 + + + https://github.com/dotnet/runtime/issues/84750 + https://github.com/dotnet/runtime/issues/81241 From c1b7a9feb6f3b4d9ca27dc4f74d8260e4edb73e8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 09:48:00 +0200 Subject: [PATCH 13/32] [main] Upload buildlogs with an _Attempt suffix (#83826) Co-authored-by: Matt Mitchell --- eng/pipelines/official/jobs/prepare-signed-artifacts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/pipelines/official/jobs/prepare-signed-artifacts.yml b/eng/pipelines/official/jobs/prepare-signed-artifacts.yml index 29b227a272729..c6d1624603fe1 100644 --- a/eng/pipelines/official/jobs/prepare-signed-artifacts.yml +++ b/eng/pipelines/official/jobs/prepare-signed-artifacts.yml @@ -2,7 +2,7 @@ parameters: dependsOn: [] PublishRidAgnosticPackagesFromPlatform: '' isOfficialBuild: false - logArtifactName: 'Logs-PrepareSignedArtifacts' + logArtifactName: 'Logs-PrepareSignedArtifacts_Attempt$(System.JobAttempt)' jobs: - job: PrepareSignedArtifacts From e121d77db3dbf7e1196cccea1fb250be5038419a Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Mon, 17 Apr 2023 13:15:01 +0200 Subject: [PATCH 14/32] Fix JitDisasmWithAlignmentBoundaries (#84827) --- src/coreclr/jit/emit.cpp | 196 +++++++++++++++++++++------------------ 1 file changed, 104 insertions(+), 92 deletions(-) diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 04eca4b9aadf2..d8295a496bf38 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -7145,129 +7145,141 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, emitCurIG = ig; - for (unsigned cnt = ig->igInsCnt; cnt > 0; cnt--) + // Fast loop without any JitDisasm/JitDump TP overhead + if (!emitComp->opts.disAsm INDEBUG(&&!emitComp->verbose)) { -#ifdef DEBUG - if ((emitComp->opts.disAsm || emitComp->verbose) && (JitConfig.JitDisasmWithDebugInfo() != 0) && - (id->idCodeSize() > 0)) + for (unsigned cnt = ig->igInsCnt; cnt > 0; cnt--) { - UNATIVE_OFFSET curCodeOffs = emitCurCodeOffs(cp); - while (nextMapping != emitComp->genRichIPmappings.end()) - { - UNATIVE_OFFSET mappingOffs = nextMapping->nativeLoc.CodeOffset(this); - - if (mappingOffs > curCodeOffs) - { - // Still haven't reached instruction that next mapping belongs to. - break; - } - - // We reached the mapping or went past it. - if (mappingOffs == curCodeOffs) - { - emitDispInsIndent(); - printf("; "); - nextMapping->debugInfo.Dump(true); - printf("\n"); - } - - ++nextMapping; - } + size_t curInstrAddr = (size_t)cp; + instrDesc* curInstrDesc = id; + size_t insSize = emitIssue1Instr(ig, id, &cp); + emitAdvanceInstrDesc(&id, insSize); } -#endif - size_t insSize = emitIssue1Instr(ig, id, &cp); - emitAdvanceInstrDesc(&id, insSize); } - - // Print the alignment boundary - if ((emitComp->opts.disAsm INDEBUG(|| emitComp->verbose)) && - (INDEBUG(emitComp->opts.disAddr ||) emitComp->opts.disAlignment)) + else { for (unsigned cnt = ig->igInsCnt; cnt > 0; cnt--) { size_t curInstrAddr = (size_t)cp; instrDesc* curInstrDesc = id; +#ifdef DEBUG + if ((emitComp->opts.disAsm || emitComp->verbose) && (JitConfig.JitDisasmWithDebugInfo() != 0) && + (id->idCodeSize() > 0)) + { + UNATIVE_OFFSET curCodeOffs = emitCurCodeOffs(cp); + while (nextMapping != emitComp->genRichIPmappings.end()) + { + UNATIVE_OFFSET mappingOffs = nextMapping->nativeLoc.CodeOffset(this); - size_t afterInstrAddr = (size_t)cp; - instruction curIns = curInstrDesc->idIns(); - bool isJccAffectedIns = false; - -#if defined(TARGET_XARCH) + if (mappingOffs > curCodeOffs) + { + // Still haven't reached instruction that next mapping belongs to. + break; + } - // Determine if this instruction is part of a set that matches the Intel jcc erratum characteristic - // described here: - // https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf - // This is the case when a jump instruction crosses a 32-byte boundary, or ends on a 32-byte boundary. - // "Jump instruction" in this case includes conditional jump (jcc), macro-fused op-jcc (where 'op' is - // one of cmp, test, add, sub, and, inc, or dec), direct unconditional jump, indirect jump, - // direct/indirect call, and return. + // We reached the mapping or went past it. + if (mappingOffs == curCodeOffs) + { + emitDispInsIndent(); + printf("; "); + nextMapping->debugInfo.Dump(true); + printf("\n"); + } - size_t jccAlignBoundary = 32; - size_t jccAlignBoundaryMask = jccAlignBoundary - 1; - size_t jccLastBoundaryAddr = afterInstrAddr & ~jccAlignBoundaryMask; + ++nextMapping; + } + } +#endif + size_t insSize = emitIssue1Instr(ig, id, &cp); + emitAdvanceInstrDesc(&id, insSize); - if (curInstrAddr < jccLastBoundaryAddr) + // Print the alignment boundary + if ((emitComp->opts.disAsm INDEBUG(|| emitComp->verbose)) && + (INDEBUG(emitComp->opts.disAddr ||) emitComp->opts.disAlignment)) { - isJccAffectedIns = IsJccInstruction(curIns) || IsJmpInstruction(curIns) || (curIns == INS_call) || - (curIns == INS_ret); + size_t afterInstrAddr = (size_t)cp; + instruction curIns = curInstrDesc->idIns(); + bool isJccAffectedIns = false; - // For op-Jcc there are two cases: (1) curIns is the jcc, in which case the above condition - // already covers us. (2) curIns is the `op` and the next instruction is the `jcc`. Note that - // we will never have a `jcc` as the first instruction of a group, so we don't need to worry - // about looking ahead to the next group after a an `op` of `op-Jcc`. +#if defined(TARGET_XARCH) - if (!isJccAffectedIns && (cnt > 1)) + // Determine if this instruction is part of a set that matches the Intel jcc erratum characteristic + // described here: + // https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf + // This is the case when a jump instruction crosses a 32-byte boundary, or ends on a 32-byte + // boundary. + // "Jump instruction" in this case includes conditional jump (jcc), macro-fused op-jcc (where 'op' + // is + // one of cmp, test, add, sub, and, inc, or dec), direct unconditional jump, indirect jump, + // direct/indirect call, and return. + + size_t jccAlignBoundary = 32; + size_t jccAlignBoundaryMask = jccAlignBoundary - 1; + size_t jccLastBoundaryAddr = afterInstrAddr & ~jccAlignBoundaryMask; + + if (curInstrAddr < jccLastBoundaryAddr) { - // The current `id` is valid, namely, there is another instruction in this group. - instruction nextIns = id->idIns(); - if (((curIns == INS_cmp) || (curIns == INS_test) || (curIns == INS_add) || - (curIns == INS_sub) || (curIns == INS_and) || (curIns == INS_inc) || - (curIns == INS_dec)) && - IsJccInstruction(nextIns)) + isJccAffectedIns = IsJccInstruction(curIns) || IsJmpInstruction(curIns) || + (curIns == INS_call) || (curIns == INS_ret); + + // For op-Jcc there are two cases: (1) curIns is the jcc, in which case the above condition + // already covers us. (2) curIns is the `op` and the next instruction is the `jcc`. Note that + // we will never have a `jcc` as the first instruction of a group, so we don't need to worry + // about looking ahead to the next group after a an `op` of `op-Jcc`. + + if (!isJccAffectedIns && (cnt > 1)) { - isJccAffectedIns = true; + // The current `id` is valid, namely, there is another instruction in this group. + instruction nextIns = id->idIns(); + if (((curIns == INS_cmp) || (curIns == INS_test) || (curIns == INS_add) || + (curIns == INS_sub) || (curIns == INS_and) || (curIns == INS_inc) || + (curIns == INS_dec)) && + IsJccInstruction(nextIns)) + { + isJccAffectedIns = true; + } } - } - if (isJccAffectedIns) - { - unsigned bytesCrossedBoundary = (unsigned)(afterInstrAddr & jccAlignBoundaryMask); - printf("; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (%s: %d ; jcc erratum) %dB boundary " - "...............................\n", - codeGen->genInsDisplayName(curInstrDesc), bytesCrossedBoundary, jccAlignBoundary); + if (isJccAffectedIns) + { + unsigned bytesCrossedBoundary = (unsigned)(afterInstrAddr & jccAlignBoundaryMask); + printf("; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (%s: %d ; jcc erratum) %dB boundary " + "...............................\n", + codeGen->genInsDisplayName(curInstrDesc), bytesCrossedBoundary, jccAlignBoundary); + } } - } #elif defined(TARGET_LOONGARCH64) - isJccAffectedIns = true; + isJccAffectedIns = true; #elif defined(TARGET_RISCV64) - isJccAffectedIns = true; + isJccAffectedIns = true; #endif // TARGET_RISCV64 - // Jcc affected instruction boundaries were printed above; handle other cases here. - if (!isJccAffectedIns) - { - size_t alignBoundaryMask = (size_t)emitComp->opts.compJitAlignLoopBoundary - 1; - size_t lastBoundaryAddr = afterInstrAddr & ~alignBoundaryMask; - - // draw boundary if beforeAddr was before the lastBoundary. - if (curInstrAddr < lastBoundaryAddr) + // Jcc affected instruction boundaries were printed above; handle other cases here. + if (!isJccAffectedIns) { - // Indicate if instruction is at the alignment boundary or is split - unsigned bytesCrossedBoundary = (unsigned)(afterInstrAddr & alignBoundaryMask); - if (bytesCrossedBoundary != 0) - { - printf("; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (%s: %d)", - codeGen->genInsDisplayName(curInstrDesc), bytesCrossedBoundary); - } - else + size_t alignBoundaryMask = (size_t)emitComp->opts.compJitAlignLoopBoundary - 1; + size_t lastBoundaryAddr = afterInstrAddr & ~alignBoundaryMask; + + // draw boundary if beforeAddr was before the lastBoundary. + if (curInstrAddr < lastBoundaryAddr) { - printf("; ..............................."); + // Indicate if instruction is at the alignment boundary or is split + unsigned bytesCrossedBoundary = (unsigned)(afterInstrAddr & alignBoundaryMask); + if (bytesCrossedBoundary != 0) + { + printf("; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (%s: %d)", + codeGen->genInsDisplayName(curInstrDesc), bytesCrossedBoundary); + } + else + { + printf("; ..............................."); + } + printf(" %dB boundary ...............................\n", + emitComp->opts.compJitAlignLoopBoundary); } - printf(" %dB boundary ...............................\n", - emitComp->opts.compJitAlignLoopBoundary); } } } From 7dbf6a5f2fd636db350f9cc31b2dfd3af0eff1a8 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Mon, 17 Apr 2023 15:54:35 +0200 Subject: [PATCH 15/32] Improve SeqEquals shape (#84524) --- .../src/System/MemoryExtensions.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs index bdeebbf560b7c..d12bf4f4fae0e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs @@ -1426,17 +1426,18 @@ private static void ThrowNullLowHighInclusive(T? lowInclusive, T? highInclusi public static unsafe bool SequenceEqual(this Span span, ReadOnlySpan other) where T : IEquatable? { int length = span.Length; + int otherLength = other.Length; if (RuntimeHelpers.IsBitwiseEquatable()) { - return length == other.Length && + return length == otherLength && SpanHelpers.SequenceEqual( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), ref Unsafe.As(ref MemoryMarshal.GetReference(other)), - ((uint)length) * (nuint)sizeof(T)); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking. + ((uint)otherLength) * (nuint)sizeof(T)); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking. } - return length == other.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other), length); + return length == otherLength && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other), length); } /// @@ -2161,16 +2162,18 @@ public static int LastIndexOfAny(this ReadOnlySpan span, IndexOfAnyValues< public static unsafe bool SequenceEqual(this ReadOnlySpan span, ReadOnlySpan other) where T : IEquatable? { int length = span.Length; + int otherLength = other.Length; + if (RuntimeHelpers.IsBitwiseEquatable()) { - return length == other.Length && + return length == otherLength && SpanHelpers.SequenceEqual( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), ref Unsafe.As(ref MemoryMarshal.GetReference(other)), - ((uint)length) * (nuint)sizeof(T)); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this API in such a case so we choose not to take the overhead of checking. + ((uint)otherLength) * (nuint)sizeof(T)); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this API in such a case so we choose not to take the overhead of checking. } - return length == other.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other), length); + return length == otherLength && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other), length); } /// From d4f70b17d6ee9bc0afa29a39eb38c7a1c8e90074 Mon Sep 17 00:00:00 2001 From: Jan Dupej <109523496+jandupej@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:41:58 +0200 Subject: [PATCH 16/32] [mono][jit] Adding Vector128.Narrow,Widen as intrinsics on arm64. (#84837) * Adding Vector128.Narrow as intrinsic. * Adding Vector128.WidenLower,WidenUpper as intrinsics on arm64. * Fixed WASM builds. --- src/mono/mono/arch/arm64/arm64-codegen.h | 54 ++++++++-------------- src/mono/mono/mini/cpu-arm64.mdesc | 5 ++ src/mono/mono/mini/mini-arm64.c | 28 +++++++++++- src/mono/mono/mini/mini-ops.h | 1 + src/mono/mono/mini/simd-arm64.h | 6 +++ src/mono/mono/mini/simd-intrinsics.c | 58 ++++++++++++++++-------- 6 files changed, 98 insertions(+), 54 deletions(-) diff --git a/src/mono/mono/arch/arm64/arm64-codegen.h b/src/mono/mono/arch/arm64/arm64-codegen.h index 2687b9fe0e903..8593d3f35cf0e 100644 --- a/src/mono/mono/arch/arm64/arm64-codegen.h +++ b/src/mono/mono/arch/arm64/arm64-codegen.h @@ -1208,6 +1208,8 @@ arm_encode_arith_imm (int imm, guint32 *shift) // type - data type of vector elements, one of {TYPE_I8, TYPE_I16, TYPE_I32, TYPE_I64} #define arm_neon_abs(p, width, type, rd, rn) arm_neon_2mvec_opcode ((p), (width), 0b0, (type), 0b01011, (rd), (rn)) #define arm_neon_neg(p, width, type, rd, rn) arm_neon_2mvec_opcode ((p), (width), 0b1, (type), 0b01011, (rd), (rn)) +#define arm_neon_xtn(p, type, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, (type), 0b10010, (rd), (rn)) +#define arm_neon_xtn2(p, type, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, (type), 0b10010, (rd), (rn)) // Parametrized variants of the float opcodes // width - determines if full register or its lower half is used one of {VREG_LOW, VREG_FULL} @@ -1215,6 +1217,11 @@ arm_encode_arith_imm (int imm, guint32 *shift) #define arm_neon_fabs(p, width, type, rd, rn) arm_neon_2mvec_opcode ((p), (width), 0b0, 0b10 | (type), 0b01111, (rd), (rn)) #define arm_neon_fneg(p, width, type, rd, rn) arm_neon_2mvec_opcode ((p), (width), 0b1, 0b10 | (type), 0b01111, (rd), (rn)) #define arm_neon_fsqrt(p, width, type, rd, rn) arm_neon_2mvec_opcode ((p), (width), 0b1, 0b10 | (type), 0b11111, (rd), (rn)) +#define arm_neon_fcvtn(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_2, 0b10110, (rd), (rn)) +#define arm_neon_fcvtn2(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_2, 0b10110, (rd), (rn)) +#define arm_neon_fcvtl(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_2, 0b10111, (rd), (rn)) +#define arm_neon_fcvtl2(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_2, 0b10111, (rd), (rn)) + // Parametrized variants of the bitwise opcodes // width - determines if full register or its lower half is used, one of {VREG_LOW, VREG_FULL} @@ -1304,13 +1311,6 @@ arm_encode_arith_imm (int imm, guint32 *shift) #define arm_neon_abs_4s(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_4, 0b01011, (rd), (rn)) #define arm_neon_abs_2d(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_8, 0b01011, (rd), (rn)) -#define arm_neon_xtn_8b(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_1, 0b10010, (rd), (rn)) -#define arm_neon_xtn2_8b(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_1, 0b10010, (rd), (rn)) -#define arm_neon_xtn_4h(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_2, 0b10010, (rd), (rn)) -#define arm_neon_xtn2_8h(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_2, 0b10010, (rd), (rn)) -#define arm_neon_xtn_2s(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_4, 0b10010, (rd), (rn)) -#define arm_neon_xtn2_4s(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_4, 0b10010, (rd), (rn)) - #define arm_neon_sqxtn_8b(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_1, 0b10100, (rd), (rn)) #define arm_neon_sqxtn2_8b(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_1, 0b10100, (rd), (rn)) #define arm_neon_sqxtn_4h(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_2, 0b10100, (rd), (rn)) @@ -1318,16 +1318,6 @@ arm_encode_arith_imm (int imm, guint32 *shift) #define arm_neon_sqxtn_2s(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_4, 0b10100, (rd), (rn)) #define arm_neon_sqxtn2_4s(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_4, 0b10100, (rd), (rn)) -#define arm_neon_fcvtn_4h(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_1, 0b10110, (rd), (rn)) -#define arm_neon_fcvtn2_4h(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_1, 0b10110, (rd), (rn)) -#define arm_neon_fcvtn_2s(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_2, 0b10110, (rd), (rn)) -#define arm_neon_fcvtn2_2s(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_2, 0b10110, (rd), (rn)) - -#define arm_neon_fcvtl_4h(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_1, 0b10111, (rd), (rn)) -#define arm_neon_fcvtl2_4h(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_1, 0b10111, (rd), (rn)) -#define arm_neon_fcvtl_2s(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_2, 0b10111, (rd), (rn)) -#define arm_neon_fcvtl2_2s(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_2, 0b10111, (rd), (rn)) - #define arm_neon_frintn_2s(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_LOW, 0b0, SIZE_1, 0b11000, (rd), (rn)) #define arm_neon_frintn_4s(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_1, 0b11000, (rd), (rn)) #define arm_neon_frintn_2d(p, rd, rn) arm_neon_2mvec_opcode ((p), VREG_FULL, 0b0, SIZE_2, 0b11000, (rd), (rn)) @@ -2284,18 +2274,26 @@ arm_encode_arith_imm (int imm, guint32 *shift) #define arm_neon_shimm_opcode(p, q, u, immh, immb, opcode, rd, rn) arm_neon_opcode_2reg ((p), (q), 0b00001111000000000000010000000000 | (u) << 29 | (immh) << 19 | (immb) << 16 | (opcode) << 11, (rd), (rn)) #define arm_neon_shimm_shr_immh_immb(size, shift) (((shift) - (16 << (size))) & 0b01111111) #define arm_neon_shimm_shr_opcode(p, q, u, size, opcode, rd, rn, shift) do { \ - int32_t ___temp_emit0 = arm_neon_shimm_shr_immh_immb ((size), (shift)); \ - arm_neon_shimm_opcode ((p), (q), (u), (__temp_emit0 >> 3) & 0b1111, __temp_emit0 & 0b111, (opcode), (rd), (rn)) \ + int32_t __temp_emit0 = arm_neon_shimm_shr_immh_immb ((size), (shift)); \ + arm_neon_shimm_opcode ((p), (q), (u), (__temp_emit0 >> 3) & 0b1111, __temp_emit0 & 0b111, (opcode), (rd), (rn)); \ } while (0) #define arm_neon_shimm_shl_immh_immb(size, shift) (((shift) + (8 << (size))) & 0b01111111) #define arm_neon_shimm_shl_opcode(p, q, u, size, opcode, rd, rn, shift) do { \ - int32_t ___temp_emit0 = arm_neon_shimm_shl_immh_immb ((size), (shift)); \ - arm_neon_shimm_opcode ((p), (q), (u), (__temp_emit0 >> 3) & 0b1111, __temp_emit0 & 0b111, (opcode), (rd), (rn)) \ + int32_t __temp_emit0 = arm_neon_shimm_shl_immh_immb ((size), (shift)); \ + arm_neon_shimm_opcode ((p), (q), (u), (__temp_emit0 >> 3) & 0b1111, __temp_emit0 & 0b111, (opcode), (rd), (rn)); \ } while (0) #define arm_neon_sli(p, width, type, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), (width), 0b1, (type), 0b01010, (rd), (rn), (shift)) #define arm_neon_shrn(p, type, rd, rn, shift) arm_neon_shimm_shr_opcode ((p), VREG_LOW, 0b0, (type), 0b10000, (rd), (rn), (shift)) +#define arm_neon_sshll(p, type, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_LOW, 0b0, (type), 0b10100, (rd), (rn), (shift)) +#define arm_neon_sshll2(p, type, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_FULL, 0b0, (type), 0b10100, (rd), (rn), (shift)) +#define arm_neon_sxtl(p, type, rd, rn) arm_neon_sshll ((p), (type), (rd), (rn), 0) +#define arm_neon_sxtl2(p, type, rd, rn) arm_neon_sshll2 ((p), (type), (rd), (rn), 0) +#define arm_neon_ushll(p, type, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_LOW, 0b1, (type), 0b10100, (rd), (rn), (shift)) +#define arm_neon_ushll2(p, type, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_FULL, 0b1, (type), 0b10100, (rd), (rn), (shift)) +#define arm_neon_uxtl(p, type, rd, rn) arm_neon_ushll ((p), (type), (rd), (rn), 0) +#define arm_neon_uxtl2(p, type, rd, rn) arm_neon_ushll2 ((p), (type), (rd), (rn), 0) #define arm_neon_sshr_8b(p, rd, rn, shift) arm_neon_shimm_shr_opcode ((p), VREG_LOW, 0b0, SIZE_1, 0b00000, (rd), (rn), (shift)) #define arm_neon_sshr_16b(p, rd, rn, shift) arm_neon_shimm_shr_opcode ((p), VREG_FULL, 0b0, SIZE_1, 0b00000, (rd), (rn), (shift)) @@ -2373,13 +2371,6 @@ arm_encode_arith_imm (int imm, guint32 *shift) #define arm_neon_sqrshrn_2s(p, rd, rn, shift) arm_neon_shimm_shr_opcode ((p), VREG_LOW, 0b0, SIZE_4, 0b10011, (rd), (rn), (shift)) #define arm_neon_sqrshrn2_2s(p, rd, rn, shift) arm_neon_shimm_shr_opcode ((p), VREG_FULL, 0b0, SIZE_4, 0b10011, (rd), (rn), (shift)) -#define arm_neon_shll_i_8b(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_LOW, 0b0, SIZE_1, 0b10100, (rd), (rn), (shift)) -#define arm_neon_shll2_i_8b(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_FULL, 0b0, SIZE_1, 0b10100, (rd), (rn), (shift)) -#define arm_neon_shll_i_4h(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_LOW, 0b0, SIZE_2, 0b10100, (rd), (rn), (shift)) -#define arm_neon_shll2_i_4h(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_FULL, 0b0, SIZE_2, 0b10100, (rd), (rn), (shift)) -#define arm_neon_shll_i_2s(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_LOW, 0b0, SIZE_4, 0b10100, (rd), (rn), (shift)) -#define arm_neon_shll2_i_2s(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_FULL, 0b0, SIZE_4, 0b10100, (rd), (rn), (shift)) - #define arm_neon_scvtf_i_4h(p, rd, rn, fbits) arm_neon_shimm_shr_opcode ((p), VREG_LOW, 0b0, SIZE_2, 0b11100, (rd), (rn), (fbits)) #define arm_neon_scvtf_i_8h(p, rd, rn, fbits) arm_neon_shimm_shr_opcode ((p), VREG_FULL, 0b0, SIZE_2, 0b11100, (rd), (rn), (fbits)) #define arm_neon_scvtf_i_2s(p, rd, rn, fbits) arm_neon_shimm_shr_opcode ((p), VREG_LOW, 0b0, SIZE_4, 0b11100, (rd), (rn), (fbits)) @@ -2476,13 +2467,6 @@ arm_encode_arith_imm (int imm, guint32 *shift) #define arm_neon_uqrshrn_2s(p, rd, rn, shift) arm_neon_shimm_shr_opcode ((p), VREG_LOW, 0b1, SIZE_4, 0b10011, (rd), (rn), (shift)) #define arm_neon_uqrshrn2_2s(p, rd, rn, shift) arm_neon_shimm_shr_opcode ((p), VREG_FULL, 0b1, SIZE_4, 0b10011, (rd), (rn), (shift)) -#define arm_neon_ushll_8b(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_LOW, 0b1, SIZE_1, 0b10100, (rd), (rn), (shift)) -#define arm_neon_ushll2_8b(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_FULL, 0b1, SIZE_1, 0b10100, (rd), (rn), (shift)) -#define arm_neon_ushll_4h(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_LOW, 0b1, SIZE_2, 0b10100, (rd), (rn), (shift)) -#define arm_neon_ushll2_4h(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_FULL, 0b1, SIZE_2, 0b10100, (rd), (rn), (shift)) -#define arm_neon_ushll_2s(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_LOW, 0b1, SIZE_4, 0b10100, (rd), (rn), (shift)) -#define arm_neon_ushll2_2s(p, rd, rn, shift) arm_neon_shimm_shl_opcode ((p), VREG_FULL, 0b1, SIZE_4, 0b10100, (rd), (rn), (shift)) - #define arm_neon_ucvtf_i_4h(p, rd, rn, shift) arm_neon_shimm_shr_opcode ((p), VREG_LOW, 0b1, SIZE_2, 0b11100, (rd), (rn), (shift)) #define arm_neon_ucvtf_i_8h(p, rd, rn, shift) arm_neon_shimm_shr_opcode ((p), VREG_FULL, 0b1, SIZE_2, 0b11100, (rd), (rn), (shift)) #define arm_neon_ucvtf_i_2s(p, rd, rn, shift) arm_neon_shimm_shr_opcode ((p), VREG_LOW, 0b1, SIZE_4, 0b11100, (rd), (rn), (shift)) diff --git a/src/mono/mono/mini/cpu-arm64.mdesc b/src/mono/mono/mini/cpu-arm64.mdesc index 8640097829724..a2af821a08171 100644 --- a/src/mono/mono/mini/cpu-arm64.mdesc +++ b/src/mono/mono/mini/cpu-arm64.mdesc @@ -533,6 +533,11 @@ create_scalar_unsafe_int: dest:x src1:i len:4 create_scalar_unsafe_float: dest:x src1:f len:4 arm64_bic: dest:x src1:x src2:x len:4 bitwise_select: dest:x src1:x src2:x src3:x len:12 +arm64_xtn: dest:x src1:x len:4 +arm64_xtn2: dest:x src1:x src2:x len:4 clob:1 +arm64_fcvtn: dest:x src1:x len:4 +arm64_fcvtn2: dest:x src1:x src2:x len:4 clob:1 +xunop: dest:x src1:x len:4 arm64_ushl: dest:x src1:x src2:x len:4 arm64_ext_imm: dest:x src1:x src2:x len:4 diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index b4dfb333ddfed..062eeb7dd76cc 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -35,6 +35,8 @@ #define EXPAND(x) x #define PARENTHESIZE(...) (__VA_ARGS__) #define EXPAND_FUN(m, ...) EXPAND(m PARENTHESIZE(__VA_ARGS__)) +#define OPFMT_DS dreg, sreg1 +#define OPFMT_TDS _t, dreg, sreg1 #define OPFMT_WDSS _w, dreg, sreg1, sreg2 #define OPFMT_WTDS _w, _t, dreg, sreg1 #define OPFMT_WTDSS _w, _t, dreg, sreg1, sreg2 @@ -3774,7 +3776,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) code = emit_ldrfpq (code, dreg, sreg1, ins->inst_offset); break; case OP_XMOVE: - arm_neon_mov (code, dreg, sreg1); + if(dreg != sreg1) + arm_neon_mov (code, dreg, sreg1); break; case OP_XCONST: { if (cfg->compile_aot && cfg->code_exec_only) { @@ -3848,6 +3851,29 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) arm_neon_ins_e(code, t, dreg, sreg1, ins->inst_c0, 0); break; } + case OP_ARM64_XTN: + // The '-1' here and in XTN2 is to account for the arm_neon_xtn macro defining + // its type as the type of the destination. Here inst_c1 is the type of the + // source data. Since XTN(2) steps down the type by one; e.g. I4 to I2, we + // subtract unity. + arm_neon_xtn (code, get_type_size_macro (ins->inst_c1) - 1, dreg, sreg1); + break; + + case OP_ARM64_XTN2: + g_assert (dreg == sreg1); + arm_neon_xtn2 (code, get_type_size_macro (ins->inst_c1) - 1, dreg, sreg2); + break; + + case OP_ARM64_FCVTN: + // Only double->float is supported here, while arm64 can also do float->half. + arm_neon_fcvtn (code, dreg, sreg1); + break; + + case OP_ARM64_FCVTN2: + g_assert (dreg == sreg1); + arm_neon_fcvtn2 (code, dreg, sreg2); + break; + case OP_ARM64_XADDV: { switch (ins->inst_c0) { case INTRINS_AARCH64_ADV_SIMD_FADDV: diff --git a/src/mono/mono/mini/mini-ops.h b/src/mono/mono/mini/mini-ops.h index 9b70bdc1c7cd1..335532e6338f0 100644 --- a/src/mono/mono/mini/mini-ops.h +++ b/src/mono/mono/mini/mini-ops.h @@ -1498,6 +1498,7 @@ MINI_OP(OP_XEXTRACT, "xextract", IREG, XREG, NONE) /* * Generic SIMD operations, the rest of the JIT doesn't care about the exact operation. */ +MINI_OP(OP_XUNOP, "xunop", XREG, XREG, NONE) MINI_OP(OP_XBINOP, "xbinop", XREG, XREG, XREG) MINI_OP(OP_XBINOP_FORCEINT, "xbinop_forceint", XREG, XREG, XREG) MINI_OP(OP_XBINOP_SCALAR, "xbinop_scalar", XREG, XREG, XREG) diff --git a/src/mono/mono/mini/simd-arm64.h b/src/mono/mono/mini/simd-arm64.h index 1f10471b708e6..68ee77aeb47fa 100644 --- a/src/mono/mono/mini/simd-arm64.h +++ b/src/mono/mono/mini/simd-arm64.h @@ -49,6 +49,12 @@ SIMD_OP (128, OP_XCOMPARE_FP, CMP_GE, WTDSS, _UNDEF, SIMD_OP (128, OP_XCOMPARE_FP, CMP_LT, WTDSS_REV, _UNDEF, _UNDEF, _UNDEF, _UNDEF, arm_neon_fcmgt, arm_neon_fcmgt) SIMD_OP (128, OP_XCOMPARE_FP, CMP_LE, WTDSS_REV, _UNDEF, _UNDEF, _UNDEF, _UNDEF, arm_neon_fcmge, arm_neon_fcmge) +SIMD_OP (128, OP_XUNOP, OP_SIMD_FCVTL, DS, _UNDEF, _UNDEF, _UNDEF, _UNDEF, arm_neon_fcvtl, _UNDEF) +SIMD_OP (128, OP_XUNOP, OP_SIMD_FCVTL2, DS, _UNDEF, _UNDEF, _UNDEF, _UNDEF, arm_neon_fcvtl2, _UNDEF) +SIMD_OP (128, OP_XUNOP, OP_ARM64_SXTL, TDS, arm_neon_sxtl, arm_neon_sxtl, arm_neon_sxtl, _UNDEF, _UNDEF, _UNDEF) +SIMD_OP (128, OP_XUNOP, OP_ARM64_SXTL2, TDS, arm_neon_sxtl2, arm_neon_sxtl2, arm_neon_sxtl2, _UNDEF, _UNDEF, _UNDEF) +SIMD_OP (128, OP_XUNOP, OP_ARM64_UXTL, TDS, arm_neon_uxtl, arm_neon_uxtl, arm_neon_uxtl, _UNDEF, _UNDEF, _UNDEF) +SIMD_OP (128, OP_XUNOP, OP_ARM64_UXTL2, TDS, arm_neon_uxtl2, arm_neon_uxtl2, arm_neon_uxtl2, _UNDEF, _UNDEF, _UNDEF) SIMD_OP (128, OP_XBINOP, OP_IADD, WTDSS, arm_neon_add, arm_neon_add, arm_neon_add, arm_neon_add, _UNDEF, _UNDEF) SIMD_OP (128, OP_XBINOP, OP_FADD, WTDSS, _UNDEF, _UNDEF, _UNDEF, _UNDEF, arm_neon_fadd, arm_neon_fadd) SIMD_OP (128, OP_XBINOP, OP_ISUB, WTDSS, arm_neon_sub, arm_neon_sub, arm_neon_sub, arm_neon_sub, _UNDEF, _UNDEF) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index f88c861f90882..0b4ada44a8fde 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1328,12 +1328,9 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_GetElement: case SN_GetLower: case SN_GetUpper: - case SN_Narrow: case SN_Shuffle: case SN_ToVector128: case SN_ToVector128Unsafe: - case SN_WidenLower: - case SN_WidenUpper: case SN_WithElement: return NULL; default: @@ -1782,8 +1779,11 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi if (size == 16) { switch (arg0_type) { case MONO_TYPE_R8: { - MonoInst *ins = emit_simd_ins (cfg, arg_class, OP_ARM64_FCVTN, args [0]->dreg, -1); - return emit_simd_ins (cfg, arg_class, OP_ARM64_FCVTN2, ins->dreg, args [1]->dreg); + MonoInst* ins = emit_simd_ins (cfg, arg_class, OP_ARM64_FCVTN, args [0]->dreg, -1); + ins->inst_c1 = arg0_type; + MonoInst* ret = emit_simd_ins (cfg, arg_class, OP_ARM64_FCVTN2, ins->dreg, args [1]->dreg); + ret->inst_c1 = arg0_type; + return ret; } case MONO_TYPE_I2: case MONO_TYPE_I4: @@ -1791,13 +1791,19 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case MONO_TYPE_U2: case MONO_TYPE_U4: case MONO_TYPE_U8: { - MonoInst *ins = emit_simd_ins (cfg, arg_class, OP_ARM64_XTN, args [0]->dreg, -1); - return emit_simd_ins (cfg, arg_class, OP_ARM64_XTN2, ins->dreg, args [1]->dreg); + MonoInst* ins = emit_simd_ins (cfg, arg_class, OP_ARM64_XTN, args [0]->dreg, -1); + ins->inst_c1 = arg0_type; + MonoInst* ret = emit_simd_ins (cfg, arg_class, OP_ARM64_XTN2, ins->dreg, args [1]->dreg); + ret->inst_c1 = arg0_type; + return ret; } default: return NULL; } } else { + if (!COMPILE_LLVM (cfg)) + return NULL; + switch (arg0_type) { case MONO_TYPE_R8: { //Widen arg0 @@ -1971,20 +1977,36 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi } case SN_WidenLower: case SN_WidenUpper: { -#if defined(TARGET_ARM64) || defined(TARGET_WASM) if (!is_element_type_primitive (fsig->params [0])) return NULL; - - int op = id == SN_WidenLower ? OP_XLOWER : OP_XUPPER; - MonoInst *lower_or_upper_half = emit_simd_ins_for_sig (cfg, klass, op, 0, arg0_type, fsig, args); - if (type_enum_is_float (arg0_type)) { - return emit_simd_ins (cfg, klass, OP_SIMD_FCVTL, lower_or_upper_half->dreg, -1); - } else { - int zero = alloc_ireg (cfg); - MONO_EMIT_NEW_ICONST (cfg, zero, 0); - op = type_enum_is_unsigned (arg0_type) ? OP_SIMD_USHLL : OP_SIMD_SSHLL; - return emit_simd_ins (cfg, klass, op, lower_or_upper_half->dreg, zero); +#if defined(TARGET_ARM64) + if (!COMPILE_LLVM (cfg)) { + int subop = 0; + gboolean is_upper = (id == SN_WidenUpper); + if (type_enum_is_float (arg0_type)) + subop = is_upper ? OP_SIMD_FCVTL2 : OP_SIMD_FCVTL; + else if (type_enum_is_unsigned (arg0_type)) + subop = is_upper ? OP_ARM64_UXTL2 : OP_ARM64_UXTL; + else + subop = is_upper ? OP_ARM64_SXTL2 : OP_ARM64_SXTL; + + MonoInst* ins = emit_simd_ins (cfg, klass, OP_XUNOP, args [0]->dreg, -1); + ins->inst_c0 = subop; + ins->inst_c1 = arg0_type; + return ins; } +#endif +#if defined(TARGET_ARM64) || defined(TARGET_WASM) + int op = id == SN_WidenLower ? OP_XLOWER : OP_XUPPER; + MonoInst *lower_or_upper_half = emit_simd_ins_for_sig (cfg, klass, op, 0, arg0_type, fsig, args); + if (type_enum_is_float (arg0_type)) { + return emit_simd_ins (cfg, klass, OP_SIMD_FCVTL, lower_or_upper_half->dreg, -1); + } else { + int zero = alloc_ireg (cfg); + MONO_EMIT_NEW_ICONST (cfg, zero, 0); + op = type_enum_is_unsigned (arg0_type) ? OP_SIMD_USHLL : OP_SIMD_SSHLL; + return emit_simd_ins (cfg, klass, op, lower_or_upper_half->dreg, zero); + } #else return NULL; #endif From e3f55cbfd83162bc85d73d69c765e7f44c478e6d Mon Sep 17 00:00:00 2001 From: Jan Dupej <109523496+jandupej@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:42:45 +0200 Subject: [PATCH 17/32] [mono][jit] Adding Vector128.Dot as intrinsic for arm64. (#84245) * [mono][jit] Adding Vector128.Dot as intrinsic for arm64. * Fixed the (u)int64 case, which now falls back to unoptimized code. * Fixed klass. * Disabled the intrinsic for native ints, enabled for LLVM. * Fixed COMPILE_LLVM condition. * Relaxing non-LLVM restriction for WASM. --- src/mono/mono/mini/simd-arm64.h | 2 +- src/mono/mono/mini/simd-intrinsics.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/mini/simd-arm64.h b/src/mono/mono/mini/simd-arm64.h index 68ee77aeb47fa..b9c0b7507236f 100644 --- a/src/mono/mono/mini/simd-arm64.h +++ b/src/mono/mono/mini/simd-arm64.h @@ -65,7 +65,7 @@ SIMD_OP (128, OP_XBINOP, OP_FMAX, WTDSS, _UNDEF, SIMD_OP (128, OP_XBINOP, OP_IMIN, WTDSS, arm_neon_smin, arm_neon_smin, arm_neon_smin, _SKIP, _UNDEF, _UNDEF) SIMD_OP (128, OP_XBINOP, OP_IMIN_UN, WTDSS, arm_neon_umin, arm_neon_umin, arm_neon_umin, _SKIP, _UNDEF, _UNDEF) SIMD_OP (128, OP_XBINOP, OP_FMIN, WTDSS, _UNDEF, _UNDEF, _UNDEF, _UNDEF, arm_neon_fmin, arm_neon_fmin) -SIMD_OP (128, OP_XBINOP, OP_IMUL, WTDSS, arm_neon_mul, arm_neon_mul, arm_neon_mul, arm_neon_mul, _UNDEF, _UNDEF) +SIMD_OP (128, OP_XBINOP, OP_IMUL, WTDSS, arm_neon_mul, arm_neon_mul, arm_neon_mul, _UNDEF, _UNDEF, _UNDEF) SIMD_OP (128, OP_XBINOP, OP_FMUL, WTDSS, _UNDEF, _UNDEF, _UNDEF, _UNDEF, arm_neon_fmul, arm_neon_fmul) SIMD_OP (128, OP_XBINOP, OP_FDIV, WTDSS, _UNDEF, _UNDEF, _UNDEF, _UNDEF, arm_neon_fdiv, arm_neon_fdiv) SIMD_OP (128, OP_XBINOP_FORCEINT, XBINOP_FORCEINT_AND, WDSS, arm_neon_and, arm_neon_and, arm_neon_and, arm_neon_and, arm_neon_and, arm_neon_and) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 0b4ada44a8fde..07058f8ac1cc6 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1324,7 +1324,6 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_ConvertToUInt32: case SN_ConvertToUInt64: case SN_Create: - case SN_Dot: case SN_GetElement: case SN_GetLower: case SN_GetUpper: @@ -1339,7 +1338,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi } #endif - MonoClass *klass = cmethod->klass; + MonoClass* klass = fsig->param_count > 0 ? args[0]->klass : cmethod->klass; MonoTypeEnum arg0_type = fsig->param_count > 0 ? get_underlying_type (fsig->params [0]) : MONO_TYPE_VOID; if (cfg->verbose_level > 1) { @@ -1554,10 +1553,17 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_Dot: { if (!is_element_type_primitive (fsig->params [0])) return NULL; +#if defined(TARGET_WASM) + if (!COMPILE_LLVM (cfg) && (arg0_type == MONO_TYPE_I8 || arg0_type == MONO_TYPE_U8)) + return NULL; +#elif defined(TARGET_ARM64) + if (!COMPILE_LLVM (cfg) && (arg0_type == MONO_TYPE_I8 || arg0_type == MONO_TYPE_U8 || arg0_type == MONO_TYPE_I || arg0_type == MONO_TYPE_U)) + return NULL; +#endif + #if defined(TARGET_ARM64) || defined(TARGET_WASM) int instc0 = type_enum_is_float (arg0_type) ? OP_FMUL : OP_IMUL; MonoInst *pairwise_multiply = emit_simd_ins_for_sig (cfg, klass, OP_XBINOP, instc0, arg0_type, fsig, args); - return emit_sum_vector (cfg, fsig->params [0], arg0_type, pairwise_multiply); #elif defined(TARGET_AMD64) int instc =-1; From d414646a1e8e400b9e0b06d5ddebae0069f28199 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Mon, 17 Apr 2023 11:21:04 -0400 Subject: [PATCH 18/32] Implement IUtf8SpanFormattable on Complex (#84779) --- .../ref/System.Runtime.Numerics.cs | 5 +- .../src/System/Numerics/Complex.cs | 90 +++++++++++-------- .../tests/ComplexTests.cs | 83 ++++++++++++++--- 3 files changed, 125 insertions(+), 53 deletions(-) diff --git a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs index 0d371c4d7886c..eb870ed17e3d5 100644 --- a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs +++ b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs @@ -240,7 +240,7 @@ namespace System.Numerics public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? value, out System.Numerics.BigInteger result) { throw null; } public bool TryWriteBytes(System.Span destination, out int bytesWritten, bool isUnsigned = false, bool isBigEndian = false) { throw null; } } - public readonly partial struct Complex : System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IDecrementOperators, System.Numerics.IDivisionOperators, System.Numerics.IEqualityOperators, System.Numerics.IIncrementOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators, System.Numerics.INumberBase, System.Numerics.ISignedNumber, System.Numerics.ISubtractionOperators, System.Numerics.IUnaryNegationOperators, System.Numerics.IUnaryPlusOperators + public readonly partial struct Complex : System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.Numerics.IAdditionOperators, System.Numerics.IAdditiveIdentity, System.Numerics.IDecrementOperators, System.Numerics.IDivisionOperators, System.Numerics.IEqualityOperators, System.Numerics.IIncrementOperators, System.Numerics.IMultiplicativeIdentity, System.Numerics.IMultiplyOperators, System.Numerics.INumberBase, System.Numerics.ISignedNumber, System.Numerics.ISubtractionOperators, System.Numerics.IUnaryNegationOperators, System.Numerics.IUnaryPlusOperators, System.IUtf8SpanFormattable { private readonly int _dummyPrimitive; public static readonly System.Numerics.Complex ImaginaryOne; @@ -376,7 +376,8 @@ namespace System.Numerics public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string? format) { throw null; } public string ToString([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] string? format, System.IFormatProvider? provider) { throw null; } - public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format, System.IFormatProvider? provider) { throw null; } + public bool TryFormat(System.Span destination, out int charsWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] System.ReadOnlySpan format = default, System.IFormatProvider? provider = null) { throw null; } + public bool TryFormat(System.Span utf8Destination, out int bytesWritten, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("NumericFormat")] System.ReadOnlySpan format = default, System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Numerics.Complex result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? provider, out System.Numerics.Complex result) { throw null; } public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Numerics.Complex result) { throw null; } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs index 0e73eb3b94960..88f8ef25fe205 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs @@ -19,7 +19,8 @@ public readonly struct Complex : IEquatable, IFormattable, INumberBase, - ISignedNumber + ISignedNumber, + IUtf8SpanFormattable { private const NumberStyles DefaultNumberStyle = NumberStyles.Float | NumberStyles.AllowThousands; @@ -393,14 +394,23 @@ public bool Equals(Complex value) public override int GetHashCode() => HashCode.Combine(m_real, m_imaginary); - public override string ToString() => $"<{m_real}; {m_imaginary}>"; + public override string ToString() => ToString(null, null); public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format) => ToString(format, null); public string ToString(IFormatProvider? provider) => ToString(null, provider); - public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format, IFormatProvider? provider) => - $"<{m_real.ToString(format, provider)}; {m_imaginary.ToString(format, provider)}>"; + public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format, IFormatProvider? provider) + { + // $"<{m_real.ToString(format, provider)}; {m_imaginary.ToString(format, provider)}>"; + var handler = new DefaultInterpolatedStringHandler(4, 2, provider, stackalloc char[512]); + handler.AppendLiteral("<"); + handler.AppendFormatted(m_real, format); + handler.AppendLiteral("; "); + handler.AppendFormatted(m_imaginary, format); + handler.AppendLiteral(">"); + return handler.ToStringAndClear(); + } public static Complex Sin(Complex value) { @@ -2199,46 +2209,52 @@ public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, I // /// - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) - { - int charsWrittenSoFar = 0; - - // We have at least 6 more characters for: <0; 0> - if (destination.Length < 6) - { - charsWritten = charsWrittenSoFar; - return false; - } + public bool TryFormat(Span destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) => + TryFormatCore(destination, out charsWritten, format, provider); - destination[charsWrittenSoFar++] = '<'; + public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan format = default, IFormatProvider? provider = null) => + TryFormatCore(utf8Destination, out bytesWritten, format, provider); - bool tryFormatSucceeded = m_real.TryFormat(destination.Slice(charsWrittenSoFar), out int tryFormatCharsWritten, format, provider); - charsWrittenSoFar += tryFormatCharsWritten; + private bool TryFormatCore(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) where TChar : unmanaged, IBinaryInteger + { + Debug.Assert(typeof(TChar) == typeof(char) || typeof(TChar) == typeof(byte)); - // We have at least 4 more characters for: ; 0> - if (!tryFormatSucceeded || (destination.Length < (charsWrittenSoFar + 4))) + // We have at least 6 more characters for: <0; 0> + if (destination.Length >= 6) { - charsWritten = charsWrittenSoFar; - return false; - } - - destination[charsWrittenSoFar++] = ';'; - destination[charsWrittenSoFar++] = ' '; - - tryFormatSucceeded = m_imaginary.TryFormat(destination.Slice(charsWrittenSoFar), out tryFormatCharsWritten, format, provider); - charsWrittenSoFar += tryFormatCharsWritten; + int realChars; + if (typeof(TChar) == typeof(char) ? + m_real.TryFormat(MemoryMarshal.Cast(destination.Slice(1)), out realChars, format, provider) : + m_real.TryFormat(MemoryMarshal.Cast(destination.Slice(1)), out realChars, format, provider)) + { + destination[0] = TChar.CreateTruncating('<'); + destination = destination.Slice(1 + realChars); // + 1 for < - // We have at least 1 more character for: > - if (!tryFormatSucceeded || (destination.Length < (charsWrittenSoFar + 1))) - { - charsWritten = charsWrittenSoFar; - return false; + // We have at least 4 more characters for: ; 0> + if (destination.Length >= 4) + { + int imaginaryChars; + if (typeof(TChar) == typeof(char) ? + m_imaginary.TryFormat(MemoryMarshal.Cast(destination.Slice(2)), out imaginaryChars, format, provider) : + m_imaginary.TryFormat(MemoryMarshal.Cast(destination.Slice(2)), out imaginaryChars, format, provider)) + { + // We have 1 more character for: > + if ((uint)(2 + imaginaryChars) < (uint)destination.Length) + { + destination[0] = TChar.CreateTruncating(';'); + destination[1] = TChar.CreateTruncating(' '); + destination[2 + imaginaryChars] = TChar.CreateTruncating('>'); + + charsWritten = realChars + imaginaryChars + 4; + return true; + } + } + } + } } - destination[charsWrittenSoFar++] = '>'; - - charsWritten = charsWrittenSoFar; - return true; + charsWritten = 0; + return false; } // diff --git a/src/libraries/System.Runtime.Numerics/tests/ComplexTests.cs b/src/libraries/System.Runtime.Numerics/tests/ComplexTests.cs index c5f0f4fefaa81..ea37fb5dc4614 100644 --- a/src/libraries/System.Runtime.Numerics/tests/ComplexTests.cs +++ b/src/libraries/System.Runtime.Numerics/tests/ComplexTests.cs @@ -3,8 +3,9 @@ using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Runtime.CompilerServices; - +using System.Text; using Xunit; namespace System.Numerics.Tests @@ -1730,25 +1731,79 @@ public static void Tanh_Advanced(double real, double imaginary, double expectedR public static void ToStringTest(double real, double imaginary) { var complex = new Complex(real, imaginary); + NumberFormatInfo numberFormatInfo = CultureInfo.CurrentCulture.NumberFormat; - string expected = "<" + real.ToString() + "; " + imaginary.ToString() + ">"; - string actual = complex.ToString(); - Assert.Equal(expected, actual); + Assert.Equal($"<{real}; {imaginary}>", complex.ToString()); - NumberFormatInfo numberFormatInfo = CultureInfo.CurrentCulture.NumberFormat; - expected = "<" + real.ToString(numberFormatInfo) + "; " + imaginary.ToString(numberFormatInfo) + ">"; - actual = complex.ToString(numberFormatInfo); - Assert.Equal(expected, complex.ToString(numberFormatInfo)); + Assert.Equal($"<{real.ToString(numberFormatInfo)}; {imaginary.ToString(numberFormatInfo)}>", complex.ToString(numberFormatInfo)); + Assert.Equal($"<{real.ToString((string)null)}; {imaginary.ToString((string)null)}>", complex.ToString((string)null)); + Assert.Equal($"<{real.ToString((string)null, numberFormatInfo)}; {imaginary.ToString((string)null, numberFormatInfo)}>", complex.ToString((string)null, numberFormatInfo)); foreach (string format in s_supportedStandardNumericFormats) { - expected = "<" + real.ToString(format) + "; " + imaginary.ToString(format) + ">"; - actual = complex.ToString(format); - Assert.Equal(expected, actual); + Assert.Equal($"<{real.ToString(format)}; {imaginary.ToString(format)}>", complex.ToString(format)); + Assert.Equal($"<{real.ToString(format, numberFormatInfo)}; {imaginary.ToString(format, numberFormatInfo)}>", complex.ToString(format, numberFormatInfo)); + } + } + + [Theory] + [MemberData(nameof(Boundaries_2_TestData))] + [MemberData(nameof(Primitives_2_TestData))] + [MemberData(nameof(Random_2_TestData))] + [MemberData(nameof(SmallRandom_2_TestData))] + [MemberData(nameof(Invalid_2_TestData))] + public static void TryFormatTest(double real, double imaginary) + { + var complex = new Complex(real, imaginary); + + // UTF16 + { + foreach (NumberFormatInfo numberFormatInfo in new[] { CultureInfo.CurrentCulture.NumberFormat, null }) + { + foreach (string format in s_supportedStandardNumericFormats.Append(null)) + { + string expected = $"<{real.ToString(format, numberFormatInfo)}; {imaginary.ToString(format, numberFormatInfo)}>"; + int charsWritten; + + // Just right or larger than required storage + for (int additional = 0; additional < 2; additional++) + { + char[] chars = new char[expected.Length + additional]; + Assert.True(complex.TryFormat(chars, out charsWritten, format, numberFormatInfo)); + Assert.Equal(expected.Length, charsWritten); + Assert.Equal(expected, new string(expected.AsSpan(0, expected.Length))); + } + + // Too small storage + Assert.False(complex.TryFormat(new char[expected.Length - 1], out charsWritten, format, numberFormatInfo)); + Assert.Equal(0, charsWritten); + } + } + } - expected = "<" + real.ToString(format, numberFormatInfo) + "; " + imaginary.ToString(format, numberFormatInfo) + ">"; - actual = complex.ToString(format, numberFormatInfo); - Assert.Equal(expected, actual); + // UTF8 + { + foreach (NumberFormatInfo numberFormatInfo in new[] { CultureInfo.CurrentCulture.NumberFormat, null }) + { + foreach (string format in s_supportedStandardNumericFormats.Append(null)) + { + byte[] expected = Encoding.UTF8.GetBytes($"<{real.ToString(format, numberFormatInfo)}; {imaginary.ToString(format, numberFormatInfo)}>"); + int bytesWritten; + + // Just right or larger than required storage + for (int additional = 0; additional < 2; additional++) + { + byte[] bytes = new byte[expected.Length + additional]; + Assert.True(complex.TryFormat(bytes, out bytesWritten, format, numberFormatInfo)); + Assert.Equal(expected.Length, bytesWritten); + Assert.Equal(expected, bytes.AsSpan(0, expected.Length).ToArray()); + } + + // Too small storage + Assert.False(complex.TryFormat(new byte[expected.Length - 1], out bytesWritten, format, numberFormatInfo)); + Assert.Equal(0, bytesWritten); + } + } } } From 636682c9ca5f9e7c38950399b9e00488062ef19d Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 17 Apr 2023 18:12:07 +0200 Subject: [PATCH 19/32] [wasm] PackedSimd, add extending integer arithmetic (#84687) * [wasm] PackedSimd, add extended integer arithmetic * Add ref methods and build fix * Implement the new PackedSimd intrinsics --- .../Wasm/PackedSimd.PlatformNotSupported.cs | 21 +++++ .../Runtime/Intrinsics/Wasm/PackedSimd.cs | 85 +++++++++++++++++++ .../ref/System.Runtime.Intrinsics.cs | 16 ++++ src/mono/mono/mini/llvm-intrinsics.h | 4 + src/mono/mono/mini/mini-llvm.c | 38 ++++++++- src/mono/mono/mini/mini-ops.h | 4 + src/mono/mono/mini/simd-intrinsics.c | 27 ++++++ src/mono/mono/mini/simd-methods.h | 8 +- 8 files changed, 196 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.PlatformNotSupported.cs index 4c7a813829a2b..d284f4221334d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.PlatformNotSupported.cs @@ -102,6 +102,27 @@ public abstract class PackedSimd public static Vector128 Negate(Vector128 value) { throw new PlatformNotSupportedException(); } public static Vector128 Negate(Vector128 value) { throw new PlatformNotSupportedException(); } + // Extended integer arithmetic + + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + public static Vector128 AddPairwiseWidening(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw new PlatformNotSupportedException(); } + // Bit shifts public static Vector128 ShiftLeft(Vector128 value, int count) { throw new PlatformNotSupportedException(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.cs index 3fb4a1f32b947..d17d6164ef859 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Wasm/PackedSimd.cs @@ -430,6 +430,91 @@ public abstract class PackedSimd [Intrinsic] public static Vector128 Negate(Vector128 value) => Negate(value); + // Extended integer arithmetic + + /// + /// i16x8.extmul_low_i8x16_s + /// + [Intrinsic] + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) => MultiplyWideningLower(left, right); + /// + /// i16x8.extmul_low_i8x16_u + /// + [Intrinsic] + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) => MultiplyWideningLower(left, right); + /// + /// i32x4.extmul_low_i16x8_s + /// + [Intrinsic] + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) => MultiplyWideningLower(left, right); + /// + /// i32x4.extmul_low_i16x8_u + /// + [Intrinsic] + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) => MultiplyWideningLower(left, right); + /// + /// i64x2.extmul_low_i32x4_s + /// + [Intrinsic] + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) => MultiplyWideningLower(left, right); + /// + /// i64x2.extmul_low_i32x4_u + /// + [Intrinsic] + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) => MultiplyWideningLower(left, right); + + /// + /// i16x8.extmul_high_i8x16_s + /// + [Intrinsic] + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + /// + /// i16x8.extmul_high_i8x16_u + /// + [Intrinsic] + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + /// + /// i32x4.extmul_high_i16x8_s + /// + [Intrinsic] + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + /// + /// i32x4.extmul_high_i16x8_u + /// + [Intrinsic] + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + /// + /// i64x2.extmul_high_i32x4_s + /// + [Intrinsic] + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + /// + /// i64x2.extmul_high_i32x4_u + /// + [Intrinsic] + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + + /// + /// i16x8.extadd_pairwise_i8x16_s + /// + [Intrinsic] + public static Vector128 AddPairwiseWidening(Vector128 value) => AddPairwiseWidening(value); + /// + /// i16x8.extadd_pairwise_i8x16_u + /// + [Intrinsic] + public static Vector128 AddPairwiseWidening(Vector128 value) => AddPairwiseWidening(value); + /// + /// i32x4.extadd_pairwise_i16x8_s + /// + [Intrinsic] + public static Vector128 AddPairwiseWidening(Vector128 value) => AddPairwiseWidening(value); + /// + /// i32x4.extadd_pairwise_i16x8_u + /// + [Intrinsic] + public static Vector128 AddPairwiseWidening(Vector128 value) => AddPairwiseWidening(value); + // Bit shifts /// diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index eef63aed18e00..32d3dd7ea39e7 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -5514,6 +5514,22 @@ public abstract partial class PackedSimd public static Vector128 Negate(Vector128 value) { throw null; } public static Vector128 Negate(Vector128 value) { throw null; } public static Vector128 Negate(Vector128 value) { throw null; } + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw null; } + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw null; } + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw null; } + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw null; } + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw null; } + public static Vector128 MultiplyWideningLower(Vector128 left, Vector128 right) { throw null; } + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw null; } + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw null; } + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw null; } + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw null; } + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw null; } + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw null; } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw null; } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw null; } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw null; } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw null; } public static Vector128 ShiftLeft(Vector128 value, int count) { throw null; } public static Vector128 ShiftLeft(Vector128 value, int count) { throw null; } public static Vector128 ShiftLeft(Vector128 value, int count) { throw null; } diff --git a/src/mono/mono/mini/llvm-intrinsics.h b/src/mono/mono/mini/llvm-intrinsics.h index dad8452029721..df1ec108d59f0 100644 --- a/src/mono/mono/mini/llvm-intrinsics.h +++ b/src/mono/mono/mini/llvm-intrinsics.h @@ -253,6 +253,10 @@ INTRINS_OVR(SSE_SSUB_SATI16, ssub_sat, Generic, v128_i2_t) INTRINS_OVR(SSE_USUB_SATI16, usub_sat, Generic, v128_i2_t) #endif #if defined(TARGET_WASM) +INTRINS_OVR(WASM_EXTADD_PAIRWISE_SIGNED_V16, wasm_extadd_pairwise_signed, Wasm, sse_i2_t) +INTRINS_OVR(WASM_EXTADD_PAIRWISE_SIGNED_V8, wasm_extadd_pairwise_signed, Wasm, sse_i4_t) +INTRINS_OVR(WASM_EXTADD_PAIRWISE_UNSIGNED_V16, wasm_extadd_pairwise_unsigned, Wasm, sse_i2_t) +INTRINS_OVR(WASM_EXTADD_PAIRWISE_UNSIGNED_V8, wasm_extadd_pairwise_unsigned, Wasm, sse_i4_t) INTRINS_OVR(WASM_ALLTRUE_V16, wasm_alltrue, Wasm, sse_i1_t) INTRINS_OVR(WASM_ALLTRUE_V8, wasm_alltrue, Wasm, sse_i2_t) INTRINS_OVR(WASM_ALLTRUE_V4, wasm_alltrue, Wasm, sse_i4_t) diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index e9adc6f69bbbf..d4e3e3754966b 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -5178,15 +5178,28 @@ bitcast_to_integral (EmitContext *ctx, LLVMValueRef vec) } static LLVMValueRef -extract_high_elements (EmitContext *ctx, LLVMValueRef src_vec) +extract_half_elements (EmitContext *ctx, LLVMValueRef src_vec, gboolean high) { LLVMTypeRef src_t = LLVMTypeOf (src_vec); unsigned int src_elems = LLVMGetVectorSize (src_t); unsigned int dst_elems = src_elems / 2; + unsigned int offset = high ? dst_elems : 0; int mask [MAX_VECTOR_ELEMS] = { 0 }; for (guint i = 0; i < dst_elems; ++i) - mask [i] = dst_elems + i; - return LLVMBuildShuffleVector (ctx->builder, src_vec, LLVMGetUndef (src_t), create_const_vector_i32 (mask, dst_elems), "extract_high"); + mask [i] = offset + i; + return LLVMBuildShuffleVector (ctx->builder, src_vec, LLVMGetUndef (src_t), create_const_vector_i32 (mask, dst_elems), high ? "extract_high" : "extract_low"); +} + +static LLVMValueRef +extract_high_elements (EmitContext *ctx, LLVMValueRef src_vec) +{ + return extract_half_elements (ctx, src_vec, TRUE); +} + +static LLVMValueRef +extract_low_elements (EmitContext *ctx, LLVMValueRef src_vec) +{ + return extract_half_elements (ctx, src_vec, FALSE); } static LLVMValueRef @@ -9974,6 +9987,25 @@ MONO_RESTORE_WARNING values [ins->dreg] = LLVMBuildBitCast (builder, shuffle, LLVMVectorType (itype, nelems * 2), ""); break; } + case OP_WASM_EXTMUL_LOWER_U: + case OP_WASM_EXTMUL_UPPER_U: + case OP_WASM_EXTMUL_LOWER: + case OP_WASM_EXTMUL_UPPER: { + LLVMTypeRef src_t = LLVMTypeOf (lhs); + int nelems = LLVMGetVectorSize (src_t) / 2; + unsigned int width = mono_llvm_get_prim_size_bits (LLVMGetElementType(src_t)); + LLVMTypeRef int_t = LLVMIntType (width * 2); + LLVMTypeRef ret_t = LLVMVectorType (int_t, nelems); + int lower = ins->opcode == OP_WASM_EXTMUL_LOWER || ins->opcode == OP_WASM_EXTMUL_LOWER_U; + gboolean is_unsigned = ins->opcode == OP_WASM_EXTMUL_LOWER_U || ins->opcode == OP_WASM_EXTMUL_UPPER_U; + LLVMValueRef part1 = lower ? extract_low_elements (ctx, lhs) : extract_high_elements(ctx, lhs); + LLVMValueRef part2 = lower ? extract_low_elements (ctx, rhs) : extract_high_elements(ctx, rhs); + LLVMValueRef ext1 = is_unsigned ? LLVMBuildZExt (builder, part1, ret_t, "") : LLVMBuildSExt (builder, part1, ret_t, ""); + LLVMValueRef ext2 = is_unsigned ? LLVMBuildZExt (builder, part2, ret_t, "") : LLVMBuildSExt (builder, part2, ret_t, ""); + values [ins->dreg] = LLVMBuildMul (builder, ext1, ext2, ""); + + break; + } #endif #if defined(TARGET_ARM64) || defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_WASM) case OP_XEQUAL: { diff --git a/src/mono/mono/mini/mini-ops.h b/src/mono/mono/mini/mini-ops.h index 335532e6338f0..29c6809e24335 100644 --- a/src/mono/mono/mini/mini-ops.h +++ b/src/mono/mono/mini/mini-ops.h @@ -855,6 +855,10 @@ MINI_OP3(OP_WASM_SIMD_SHUFFLE, "wasm_shuffle", XREG, XREG, XREG, XREG) MINI_OP(OP_WASM_SIMD_SUM, "wasm_sum", XREG, XREG, NONE) MINI_OP(OP_WASM_SIMD_SWIZZLE, "wasm_swizzle", XREG, XREG, XREG) MINI_OP(OP_WASM_EXTRACT_NARROW, "wasm_extract_narrow", XREG, XREG, XREG) +MINI_OP(OP_WASM_EXTMUL_LOWER, "wasm_extmul_lower", XREG, XREG, XREG) +MINI_OP(OP_WASM_EXTMUL_UPPER, "wasm_extmul_upper", XREG, XREG, XREG) +MINI_OP(OP_WASM_EXTMUL_LOWER_U, "wasm_extmul_lower_u", XREG, XREG, XREG) +MINI_OP(OP_WASM_EXTMUL_UPPER_U, "wasm_extmul_upper_u", XREG, XREG, XREG) #endif #if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_WASM) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 07058f8ac1cc6..a01b2a7a2c095 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -4892,6 +4892,7 @@ static SimdIntrinsic wasmbase_methods [] = { static SimdIntrinsic packedsimd_methods [] = { {SN_Add}, + {SN_AddPairwiseWidening}, {SN_And, OP_XBINOP_FORCEINT, XBINOP_FORCEINT_AND}, {SN_Bitmask, OP_WASM_SIMD_BITMASK}, {SN_CompareEqual}, @@ -4901,6 +4902,8 @@ static SimdIntrinsic packedsimd_methods [] = { {SN_Dot, OP_XOP_X_X_X, INTRINS_WASM_DOT}, {SN_ExtractLane}, {SN_Multiply}, + {SN_MultiplyWideningLower, OP_WASM_EXTMUL_LOWER, 0, OP_WASM_EXTMUL_LOWER_U}, + {SN_MultiplyWideningUpper, OP_WASM_EXTMUL_UPPER, 0, OP_WASM_EXTMUL_UPPER_U}, {SN_Negate}, {SN_ReplaceLane}, {SN_ShiftLeft, OP_SIMD_SHL}, @@ -4991,6 +4994,30 @@ emit_wasm_supported_intrinsics ( return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id); case SN_Negate: return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, id); + case SN_AddPairwiseWidening: { + op = OP_XOP_X_X; + + switch (arg0_type) { + case MONO_TYPE_I1: + c0 = INTRINS_WASM_EXTADD_PAIRWISE_SIGNED_V16; + break; + case MONO_TYPE_I2: + c0 = INTRINS_WASM_EXTADD_PAIRWISE_SIGNED_V8; + break; + case MONO_TYPE_U1: + c0 = INTRINS_WASM_EXTADD_PAIRWISE_UNSIGNED_V16; + break; + case MONO_TYPE_U2: + c0 = INTRINS_WASM_EXTADD_PAIRWISE_UNSIGNED_V8; + break; + } + + // continue with default emit + if (c0 != 0) + break; + + return NULL; + } case SN_CompareEqual: return emit_simd_ins_for_sig (cfg, klass, type_enum_is_float (arg0_type) ? OP_XCOMPARE_FP : OP_XCOMPARE, CMP_EQ, arg0_type, fsig, args); case SN_CompareNotEqual: diff --git a/src/mono/mono/mini/simd-methods.h b/src/mono/mono/mini/simd-methods.h index 25d9d66a17e0f..0e38696380cc5 100644 --- a/src/mono/mono/mini/simd-methods.h +++ b/src/mono/mono/mini/simd-methods.h @@ -635,10 +635,10 @@ METHOD(MultiplyRoundedDoublingScalarBySelectedScalarAndSubtractSaturateHigh) METHOD(DotProductBySelectedQuadruplet) // Wasm METHOD(Bitmask) -METHOD(Splat) -METHOD(ExtractLane) -METHOD(ReplaceLane) -METHOD(Swizzle) METHOD(ConvertNarrowingSignedSaturate) METHOD(ConvertNarrowingUnsignedSaturate) +METHOD(ExtractLane) +METHOD(ReplaceLane) METHOD(ShiftLeft) +METHOD(Splat) +METHOD(Swizzle) From dbd42332f91d08e0b149931e22bd70a4f5215945 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 17 Apr 2023 18:12:51 +0200 Subject: [PATCH 20/32] [wasm] Bump emscripten to 3.1.34 (#83998) * [wasm] Bump emscripten to 3.1.34 * Update emsdk deps * Update icu deps * Use new images * Use emscripten_main_runtime_thread_id * Ignore ExitStatus exceptions This should fix these errors: [wasm test] [23:10:04] dbug: Reached wasm exit [wasm test] [23:10:04] info: node:internal/process/promises:246 [wasm test] [23:10:04] info: triggerUncaughtException(err, true /* fromPromise */); [wasm test] [23:10:04] info: ^ [wasm test] [23:10:04] info: [wasm test] [23:10:04] info: [UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "#".] { [wasm test] [23:10:04] info: code: 'ERR_UNHANDLED_REJECTION' [wasm test] [23:10:04] info: } [wasm test] [23:10:04] info: [wasm test] [23:10:04] info: Node.js v17.3.1 [wasm test] [23:10:04] info: Process node.exe exited with 1 * Handle UnhandledPromiseRejection for ExitStatus * Exclude 2 failing tests * Updade ICU deps * Revert "Updade ICU deps" This reverts commit ad92e213c38b339d4ab685c91880d355190334ba. Looks like main is behind and doesn't work with latest ICU, so go back to the one with 3.1.34 bump --- eng/Version.Details.xml | 6 +++--- eng/Versions.props | 4 ++-- .../common/templates/pipeline-with-resources.yml | 4 ++-- eng/pipelines/libraries/helix-queues-setup.yml | 2 +- src/mono/mono/utils/mono-threads-wasm.c | 2 +- src/mono/wasm/Wasm.Build.Tests/data/test-main-7.0.js | 10 ++++++++++ src/mono/wasm/emscripten-version.txt | 2 +- src/mono/wasm/runtime/pthreads/shared/index.ts | 2 +- src/mono/wasm/test-main.js | 10 ++++++++++ src/mono/wasm/wasm.proj | 1 - src/tests/issues.targets | 6 ++++++ 11 files changed, 37 insertions(+), 12 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3fb11084dea6d..29e53e5552079 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,6 +1,6 @@ - + https://github.com/dotnet/icu 389d19d09d3cf16ec0143dba065fcd704ab8e48c @@ -85,9 +85,9 @@ 9a7551fa7ba8218affbc1148eabc4b5c9f4e1151 - + https://github.com/dotnet/emsdk - 07ca08d31022f545d37fbc8d1254d3441645fce2 + e4089ed2abe29bdc25bab2c261940175d0846824 diff --git a/eng/Versions.props b/eng/Versions.props index 7578f8e4bf072..1158e28fa9758 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -217,7 +217,7 @@ 0.11.4-alpha.23178.1 - 8.0.0-preview.4.23203.1 + 8.0.0-preview.4.23177.3 2.1.7 8.0.0-alpha.1.23180.2 @@ -236,7 +236,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.0-preview.4.23205.3 + 8.0.0-preview.4.23177.1 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml index e92ae5f615753..4d6f8a22c6cc4 100644 --- a/eng/pipelines/common/templates/pipeline-with-resources.yml +++ b/eng/pipelines/common/templates/pipeline-with-resources.yml @@ -70,10 +70,10 @@ resources: image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7 - container: browser_wasm - image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-webassembly-net8-20230322221728-80fdceb + image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-webassembly-net8-20230327150025-4404b5c - container: wasi_wasm - image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-webassembly-net8-20230322221804-80fdceb + image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-webassembly-net8-20230327150037-4404b5c - container: freebsd_x64 image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-freebsd-12 diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index 32681c5466b01..6c6837a74938a 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -201,6 +201,6 @@ jobs: # Browser WebAssembly windows - ${{ if in(parameters.platform, 'browser_wasm_win', 'wasi_wasm_win') }}: - - (Windows.Amd64.Server2022.Open)windows.amd64.server2022.open@mcr.microsoft.com/dotnet-buildtools/prereqs:windowsservercore-ltsc2022-helix-webassembly-net8-20230319084205-80fdceb + - (Windows.Amd64.Server2022.Open)windows.amd64.server2022.open@mcr.microsoft.com/dotnet-buildtools/prereqs:windowsservercore-ltsc2022-helix-webassembly-net8-20230327150108-4404b5c ${{ insert }}: ${{ parameters.jobParameters }} diff --git a/src/mono/mono/utils/mono-threads-wasm.c b/src/mono/mono/utils/mono-threads-wasm.c index 74cc69825f29f..96e5446388a43 100644 --- a/src/mono/mono/utils/mono-threads-wasm.c +++ b/src/mono/mono/utils/mono-threads-wasm.c @@ -403,7 +403,7 @@ mono_threads_wasm_browser_thread_tid (void) #ifdef DISABLE_THREADS return (MonoNativeThreadId)1; #else - return (MonoNativeThreadId)emscripten_main_browser_thread_id (); + return (MonoNativeThreadId)emscripten_main_runtime_thread_id (); #endif } diff --git a/src/mono/wasm/Wasm.Build.Tests/data/test-main-7.0.js b/src/mono/wasm/Wasm.Build.Tests/data/test-main-7.0.js index bac3f856160c5..3b32add2f39e5 100644 --- a/src/mono/wasm/Wasm.Build.Tests/data/test-main-7.0.js +++ b/src/mono/wasm/Wasm.Build.Tests/data/test-main-7.0.js @@ -23,6 +23,16 @@ if (is_node && process.versions.node.split(".")[0] < 14) { throw new Error(`NodeJS at '${process.execPath}' has too low version '${process.versions.node}'`); } +if (is_node) { + // the emscripten 3.1.34 stopped handling these when MODULARIZE is enabled + process.on('uncaughtException', function(ex) { + // ignore UnhandledPromiseRejection exceptions with exit status + if (ex !== 'unwind' && (ex.name !== "UnhandledPromiseRejection" || !ex.message.includes('"#"'))) { + throw ex; + } + }); +} + if (typeof globalThis.crypto === 'undefined') { // **NOTE** this is a simple insecure polyfill for testing purposes only // /dev/random doesn't work on js shells, so define our own diff --git a/src/mono/wasm/emscripten-version.txt b/src/mono/wasm/emscripten-version.txt index f4e47c2e5e20a..45dd392530866 100644 --- a/src/mono/wasm/emscripten-version.txt +++ b/src/mono/wasm/emscripten-version.txt @@ -1 +1 @@ -3.1.30 \ No newline at end of file +3.1.34 \ No newline at end of file diff --git a/src/mono/wasm/runtime/pthreads/shared/index.ts b/src/mono/wasm/runtime/pthreads/shared/index.ts index c71a27f5f3967..774dbc76ec8af 100644 --- a/src/mono/wasm/runtime/pthreads/shared/index.ts +++ b/src/mono/wasm/runtime/pthreads/shared/index.ts @@ -20,7 +20,7 @@ export const MainThread: PThreadInfo = { let browser_thread_id_lazy: pthread_ptr | undefined; export function getBrowserThreadID(): pthread_ptr { if (browser_thread_id_lazy === undefined) { - browser_thread_id_lazy = (Module)["_emscripten_main_browser_thread_id"]() as pthread_ptr; + browser_thread_id_lazy = (Module)["_emscripten_main_runtime_thread_id"]() as pthread_ptr; } return browser_thread_id_lazy; } diff --git a/src/mono/wasm/test-main.js b/src/mono/wasm/test-main.js index 60c5473492962..3d835c0bb6140 100644 --- a/src/mono/wasm/test-main.js +++ b/src/mono/wasm/test-main.js @@ -23,6 +23,16 @@ if (is_node && process.versions.node.split(".")[0] < 14) { throw new Error(`NodeJS at '${process.execPath}' has too low version '${process.versions.node}'`); } +if (is_node) { + // the emscripten 3.1.34 stopped handling these when MODULARIZE is enabled + process.on('uncaughtException', function(ex) { + // ignore UnhandledPromiseRejection exceptions with exit status + if (ex !== 'unwind' && (ex.name !== "UnhandledPromiseRejection" || !ex.message.includes('"#"'))) { + throw ex; + } + }); +} + if (!is_node && !is_browser && typeof globalThis.crypto === 'undefined') { // **NOTE** this is a simple insecure polyfill for testing purposes only // /dev/random doesn't work on js shells, so define our own diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index 9755e405afed4..8342ee12786eb 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -293,7 +293,6 @@ <_EmccLinkFlags Include="-s EXPORTED_RUNTIME_METHODS=$(_EmccExportedRuntimeMethods)" /> <_EmccLinkFlags Include="-s EXPORTED_FUNCTIONS=$(_EmccExportedFunctions)" /> <_EmccLinkFlags Include="--source-map-base http://example.com" /> - <_EmccLinkFlags Include="-s STRICT_JS=1" /> <_EmccLinkFlags Include="-s WASM_BIGINT=1" /> <_EmccLinkFlags Include="-s EXPORT_NAME="'createDotnetRuntime'"" /> <_EmccLinkFlags Include="-s MODULARIZE=1"/> diff --git a/src/tests/issues.targets b/src/tests/issues.targets index cbeecf67ed298..3f409b5c33135 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -3704,6 +3704,12 @@ https://github.com/dotnet/runtime/issues/41472 + + https://github.com/dotnet/runtime/issues/84786 + + + https://github.com/dotnet/runtime/issues/84786 + needs triage From 048467b13160399d493b97a90b2117f58f01ac51 Mon Sep 17 00:00:00 2001 From: Miha Zupan Date: Mon, 17 Apr 2023 19:12:21 +0200 Subject: [PATCH 21/32] Add status code and exception info to System.Net.Http events (#84036) * Add status code and exception info to System.Net.Http events * Update HttpTelemetry fake --- .../src/System/Net/Http/HttpClient.cs | 18 +++---- .../src/System/Net/Http/HttpMessageInvoker.cs | 20 +++++--- .../src/System/Net/Http/HttpTelemetry.cs | 50 +++++++++++++++---- .../Http/SocketsHttpHandler/Http2Stream.cs | 3 +- .../SocketsHttpHandler/Http3RequestStream.cs | 2 +- .../Http/SocketsHttpHandler/HttpConnection.cs | 2 +- .../tests/FunctionalTests/TelemetryTest.cs | 37 +++++++++++--- .../tests/UnitTests/Fakes/HttpTelemetry.cs | 4 +- 8 files changed, 99 insertions(+), 37 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs index 5c96ddaa896bb..822090c0819e1 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs @@ -227,7 +227,7 @@ private async Task GetStringAsyncCore(HttpRequestMessage request, Cancel } finally { - FinishSend(cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); + FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); } } @@ -306,7 +306,7 @@ private async Task GetByteArrayAsyncCore(HttpRequestMessage request, Can } finally { - FinishSend(cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); + FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); } } @@ -352,7 +352,7 @@ private async Task GetStreamAsyncCore(HttpRequestMessage request, Cancel } finally { - FinishSend(cts, disposeCts, telemetryStarted, responseContentTelemetryStarted: false); + FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted: false); } } @@ -496,7 +496,7 @@ public HttpResponseMessage Send(HttpRequestMessage request, HttpCompletionOption } finally { - FinishSend(cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); + FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); } } @@ -551,7 +551,7 @@ async Task Core( } finally { - FinishSend(cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); + FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted); } } } @@ -583,8 +583,6 @@ private static bool ShouldBufferResponse(HttpCompletionOption completionOption, private void HandleFailure(Exception e, bool telemetryStarted, HttpResponseMessage? response, CancellationTokenSource cts, CancellationToken cancellationToken, CancellationTokenSource pendingRequestsCts) { - LogRequestFailed(telemetryStarted); - response?.Dispose(); Exception? toThrow = null; @@ -623,6 +621,8 @@ private void HandleFailure(Exception e, bool telemetryStarted, HttpResponseMessa e = toThrow = CancellationHelper.CreateOperationCanceledException(e, cancellationToken.IsCancellationRequested ? cancellationToken : cts.Token); } + LogRequestFailed(e, telemetryStarted); + if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(this, e); if (toThrow != null) @@ -642,7 +642,7 @@ private static bool StartSend(HttpRequestMessage request) return false; } - private static void FinishSend(CancellationTokenSource cts, bool disposeCts, bool telemetryStarted, bool responseContentTelemetryStarted) + private static void FinishSend(HttpResponseMessage? response, CancellationTokenSource cts, bool disposeCts, bool telemetryStarted, bool responseContentTelemetryStarted) { // Log completion. if (HttpTelemetry.Log.IsEnabled() && telemetryStarted) @@ -652,7 +652,7 @@ private static void FinishSend(CancellationTokenSource cts, bool disposeCts, boo HttpTelemetry.Log.ResponseContentStop(); } - HttpTelemetry.Log.RequestStop(); + HttpTelemetry.Log.RequestStop(response); } // Dispose of the CancellationTokenSource if it was created specially for this request diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpMessageInvoker.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpMessageInvoker.cs index a06da5b9ed5a2..ceb93c06a2aae 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpMessageInvoker.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpMessageInvoker.cs @@ -41,18 +41,20 @@ public virtual HttpResponseMessage Send(HttpRequestMessage request, Cancellation { HttpTelemetry.Log.RequestStart(request); + HttpResponseMessage? response = null; try { - return _handler.Send(request, cancellationToken); + response = _handler.Send(request, cancellationToken); + return response; } - catch when (LogRequestFailed(telemetryStarted: true)) + catch (Exception ex) when (LogRequestFailed(ex, telemetryStarted: true)) { // Unreachable as LogRequestFailed will return false throw; } finally { - HttpTelemetry.Log.RequestStop(); + HttpTelemetry.Log.RequestStop(response); } } else @@ -78,18 +80,20 @@ static async Task SendAsyncWithTelemetry(HttpMessageHandler { HttpTelemetry.Log.RequestStart(request); + HttpResponseMessage? response = null; try { - return await handler.SendAsync(request, cancellationToken).ConfigureAwait(false); + response = await handler.SendAsync(request, cancellationToken).ConfigureAwait(false); + return response; } - catch when (LogRequestFailed(telemetryStarted: true)) + catch (Exception ex) when (LogRequestFailed(ex, telemetryStarted: true)) { // Unreachable as LogRequestFailed will return false throw; } finally { - HttpTelemetry.Log.RequestStop(); + HttpTelemetry.Log.RequestStop(response); } } } @@ -100,11 +104,11 @@ private static bool ShouldSendWithTelemetry(HttpRequestMessage request) => request.RequestUri is Uri requestUri && requestUri.IsAbsoluteUri; - internal static bool LogRequestFailed(bool telemetryStarted) + internal static bool LogRequestFailed(Exception exception, bool telemetryStarted) { if (HttpTelemetry.Log.IsEnabled() && telemetryStarted) { - HttpTelemetry.Log.RequestFailed(); + HttpTelemetry.Log.RequestFailed(exception); } return false; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs index 131748bddf5a8..8126bda265a33 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs @@ -13,6 +13,11 @@ internal sealed partial class HttpTelemetry : EventSource { public static readonly HttpTelemetry Log = new HttpTelemetry(); + public static class Keywords + { + public const EventKeywords RequestFailedDetailed = (EventKeywords)1; + } + private long _startedRequests; private long _stoppedRequests; private long _failedRequests; @@ -50,18 +55,39 @@ public void RequestStart(HttpRequestMessage request) request.VersionPolicy); } - [Event(2, Level = EventLevel.Informational)] - public void RequestStop() + [NonEvent] + public void RequestStop(HttpResponseMessage? response) + { + RequestStop(response is null ? -1 : (int)response.StatusCode); + } + + [Event(2, Level = EventLevel.Informational, Version = 1)] + private void RequestStop(int statusCode) { Interlocked.Increment(ref _stoppedRequests); - WriteEvent(eventId: 2); + WriteEvent(eventId: 2, statusCode); } - [Event(3, Level = EventLevel.Error)] - public void RequestFailed() + [NonEvent] + public void RequestFailed(Exception exception) { Interlocked.Increment(ref _failedRequests); - WriteEvent(eventId: 3); + + if (IsEnabled(EventLevel.Error, EventKeywords.None)) + { + RequestFailed(exceptionMessage: exception.Message); + + if (IsEnabled(EventLevel.Error, Keywords.RequestFailedDetailed)) + { + RequestFailedDetailed(exception: exception.ToString()); + } + } + } + + [Event(3, Level = EventLevel.Error, Version = 1)] + private void RequestFailed(string exceptionMessage) + { + WriteEvent(eventId: 3, exceptionMessage); } [Event(4, Level = EventLevel.Informational)] @@ -112,10 +138,10 @@ public void ResponseHeadersStart() WriteEvent(eventId: 11); } - [Event(12, Level = EventLevel.Informational)] - public void ResponseHeadersStop() + [Event(12, Level = EventLevel.Informational, Version = 1)] + public void ResponseHeadersStop(int statusCode) { - WriteEvent(eventId: 12); + WriteEvent(eventId: 12, statusCode); } [Event(13, Level = EventLevel.Informational)] @@ -130,6 +156,12 @@ public void ResponseContentStop() WriteEvent(eventId: 14); } + [Event(15, Level = EventLevel.Error, Keywords = Keywords.RequestFailedDetailed)] + private void RequestFailedDetailed(string exception) + { + WriteEvent(eventId: 15, exception); + } + [NonEvent] public void Http11ConnectionEstablished() { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs index d5199afc6deb5..81aeaa63a9e29 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs @@ -1024,7 +1024,8 @@ public async Task ReadResponseHeadersAsync(CancellationToken cancellationToken) Debug.Assert(!wait); } - if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop(); + Debug.Assert(_response is not null); + if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop((int)_response.StatusCode); } catch { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs index 70b1690707ccb..5bb3a2941cd6f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs @@ -352,7 +352,7 @@ private async Task ReadResponseAsync(CancellationToken cancellationToken) _headerState = HeaderState.TrailingHeaders; - if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop(); + if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop((int)_response.StatusCode); } private async Task SendContentAsync(HttpContent content, CancellationToken cancellationToken) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs index fbfa024a647cb..ba3b895b65e23 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs @@ -696,7 +696,7 @@ public async Task SendAsync(HttpRequestMessage request, boo await FillForHeadersAsync(async).ConfigureAwait(false); } - if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop(); + if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.ResponseHeadersStop((int)response.StatusCode); if (allowExpect100ToContinue != null) { diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/TelemetryTest.cs index b6bee89d36db7..9ac7d79660035 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/TelemetryTest.cs @@ -6,7 +6,6 @@ using System.Diagnostics.Tracing; using System.IO; using System.Linq; -using System.Net.Quic; using System.Net.Test.Common; using System.Text; using System.Threading; @@ -412,19 +411,40 @@ private static void ValidateStartFailedStopEvents(ConcurrentQueue<(EventWrittenE Assert.Equal(count, starts.Length); (EventWrittenEventArgs Event, Guid ActivityId)[] stops = events.Where(e => e.Event.EventName == "RequestStop").ToArray(); - Assert.All(stops, stopEvent => Assert.Empty(stopEvent.Event.Payload)); + foreach (EventWrittenEventArgs stopEvent in stops.Select(e => e.Event)) + { + object payload = Assert.Single(stopEvent.Payload); + int statusCode = Assert.IsType(payload); + Assert.Equal(shouldHaveFailures ? -1 : 200, statusCode); + } ValidateSameActivityIds(starts, stops); (EventWrittenEventArgs Event, Guid ActivityId)[] failures = events.Where(e => e.Event.EventName == "RequestFailed").ToArray(); - Assert.All(failures, failedEvent => Assert.Empty(failedEvent.Event.Payload)); + (EventWrittenEventArgs Event, Guid ActivityId)[] detailedFailures = events.Where(e => e.Event.EventName == "RequestFailedDetailed").ToArray(); if (shouldHaveFailures) { + foreach (EventWrittenEventArgs failedEvent in failures.Select(e => e.Event)) + { + object payload = Assert.Single(failedEvent.Payload); + string exceptionMessage = Assert.IsType(payload); + Assert.Equal(new OperationCanceledException().Message, exceptionMessage); + } + + foreach (EventWrittenEventArgs failedEvent in detailedFailures.Select(e => e.Event)) + { + object payload = Assert.Single(failedEvent.Payload); + string exception = Assert.IsType(payload); + Assert.StartsWith("System.Threading.Tasks.TaskCanceledException", exception); + } + ValidateSameActivityIds(starts, failures); + ValidateSameActivityIds(starts, detailedFailures); } else { Assert.Empty(failures); + Assert.Empty(detailedFailures); } } @@ -470,8 +490,8 @@ private static void ValidateRequestResponseStartStopEvents(ConcurrentQueue<(Even foreach (EventWrittenEventArgs requestContentStop in requestContentStops.Select(e => e.Event)) { object payload = Assert.Single(requestContentStop.Payload); - Assert.True(payload is long); - Assert.Equal(requestContentLength.Value, (long)payload); + long contentLength = Assert.IsType(payload); + Assert.Equal(requestContentLength.Value, contentLength); } ValidateSameActivityIds(requestContentStarts, requestContentStops); @@ -482,7 +502,12 @@ private static void ValidateRequestResponseStartStopEvents(ConcurrentQueue<(Even (EventWrittenEventArgs Event, Guid ActivityId)[] responseHeadersStops = events.Where(e => e.Event.EventName == "ResponseHeadersStop").ToArray(); Assert.Equal(count, responseHeadersStops.Length); - Assert.All(responseHeadersStops, r => Assert.Empty(r.Event.Payload)); + foreach (EventWrittenEventArgs responseHeadersStop in responseHeadersStops.Select(e => e.Event)) + { + object payload = Assert.Single(responseHeadersStop.Payload); + int statusCode = Assert.IsType(payload); + Assert.Equal(200, statusCode); + } ValidateSameActivityIds(responseHeadersStarts, responseHeadersStops); diff --git a/src/libraries/System.Net.Http/tests/UnitTests/Fakes/HttpTelemetry.cs b/src/libraries/System.Net.Http/tests/UnitTests/Fakes/HttpTelemetry.cs index 5667687e632e2..26ac057e31bd8 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/Fakes/HttpTelemetry.cs +++ b/src/libraries/System.Net.Http/tests/UnitTests/Fakes/HttpTelemetry.cs @@ -11,9 +11,9 @@ public class HttpTelemetry public void RequestStart(HttpRequestMessage request) { } - public void RequestStop() { } + public void RequestStop(HttpResponseMessage response) { } - public void RequestFailed() { } + public void RequestFailed(Exception exception) { } public void ResponseContentStart() { } From 35ef7666ec9a33beccac68196ba359c9ff6e83ff Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 17 Apr 2023 11:32:38 -0700 Subject: [PATCH 22/32] [JIT] ARM64 - Combine `cmp` and shift ops into a single `cmp` op (#84605) * Combine compare and shift ops into a single compare op * Fix comment * Expanding IsContainableBinaryOp. * Remove commented code * Added more cases * Update codegenarm64.cpp * Feedback * Feedback --- src/coreclr/jit/codegen.h | 1 + src/coreclr/jit/codegenarm64.cpp | 60 +++++++++++++++++++------------- src/coreclr/jit/lowerarmarch.cpp | 34 ++++++++++++++++-- 3 files changed, 68 insertions(+), 27 deletions(-) diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index 8b5957dfb8aa9..da92e4cd66013 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -1573,6 +1573,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #if defined(TARGET_ARM64) static insCond JumpKindToInsCond(emitJumpKind condition); + static insOpts ShiftOpToInsOpts(genTreeOps op); #elif defined(TARGET_XARCH) static instruction JumpKindToCmov(emitJumpKind condition); #endif diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index b177186cedeca..6ecfb818a4daf 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -2626,31 +2626,7 @@ void CodeGen::genCodeForBinary(GenTreeOp* tree) } } - switch (op2->gtOper) - { - case GT_LSH: - { - opt = INS_OPTS_LSL; - break; - } - - case GT_RSH: - { - opt = INS_OPTS_ASR; - break; - } - - case GT_RSZ: - { - opt = INS_OPTS_LSR; - break; - } - - default: - { - unreached(); - } - } + opt = ShiftOpToInsOpts(op2->gtOper); emit->emitIns_R_R_R_I(ins, emitActualTypeSize(tree), targetReg, a->GetRegNum(), b->GetRegNum(), c->AsIntConCommon()->IconValue(), opt); @@ -4546,6 +4522,15 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree) emit->emitIns_R_I(ins, cmpSize, op1Reg, intConst->IconValue()); } + else if (op2->isContained()) + { + assert(op2->OperIs(GT_LSH, GT_RSH, GT_RSZ)); + assert(op2->gtGetOp2()->IsCnsIntOrI()); + assert(op2->gtGetOp2()->isContained()); + + emit->emitIns_R_R_I(ins, cmpSize, op1->GetRegNum(), op2->gtGetOp1()->GetRegNum(), + op2->gtGetOp2()->AsIntConCommon()->IntegralValue(), ShiftOpToInsOpts(op2->gtOper)); + } else { emit->emitIns_R_R(ins, cmpSize, op1->GetRegNum(), op2->GetRegNum()); @@ -10389,4 +10374,29 @@ insCond CodeGen::JumpKindToInsCond(emitJumpKind condition) } } +//------------------------------------------------------------------------ +// ShiftOpToInsOpts: Convert a shift-op to a insOpts. +// +// Arguments: +// shiftOp - the shift-op +// +insOpts CodeGen::ShiftOpToInsOpts(genTreeOps shiftOp) +{ + switch (shiftOp) + { + case GT_LSH: + return INS_OPTS_LSL; + + case GT_RSH: + return INS_OPTS_ASR; + + case GT_RSZ: + return INS_OPTS_LSR; + + default: + NO_WAY("expected a shift-op"); + return INS_OPTS_NONE; + } +} + #endif // TARGET_ARM64 diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index e082d3c4d1eb0..23b57ef894963 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -269,7 +269,7 @@ bool Lowering::IsContainableBinaryOp(GenTree* parentNode, GenTree* childNode) co return false; } - if (parentNode->OperIs(GT_CMP, GT_OR, GT_XOR)) + if (parentNode->OperIs(GT_CMP, GT_OR, GT_XOR) || parentNode->OperIsCompare()) { if (IsInvariantInRange(childNode, parentNode)) { @@ -2268,7 +2268,37 @@ void Lowering::ContainCheckCast(GenTreeCast* node) // void Lowering::ContainCheckCompare(GenTreeOp* cmp) { - CheckImmedAndMakeContained(cmp, cmp->gtOp2); + GenTree* op1 = cmp->gtGetOp1(); + GenTree* op2 = cmp->gtGetOp2(); + + if (CheckImmedAndMakeContained(cmp, op2)) + return; + + if (cmp->OperIsCompare() && CheckImmedAndMakeContained(cmp, op1)) + { + std::swap(cmp->gtOp1, cmp->gtOp2); + cmp->ChangeOper(cmp->SwapRelop(cmp->gtOper)); + return; + } + +#ifdef TARGET_ARM64 + if (comp->opts.OptimizationEnabled() && cmp->OperIsCompare()) + { + if (IsContainableBinaryOp(cmp, op2)) + { + MakeSrcContained(cmp, op2); + return; + } + + if (IsContainableBinaryOp(cmp, op1)) + { + MakeSrcContained(cmp, op1); + std::swap(cmp->gtOp1, cmp->gtOp2); + cmp->ChangeOper(cmp->SwapRelop(cmp->gtOper)); + return; + } + } +#endif } #ifdef TARGET_ARM64 From 223d1528740baaa806095797330577e930fdfb8b Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Mon, 17 Apr 2023 20:40:18 +0200 Subject: [PATCH 23/32] Enable AVX-512 for string/span Equals/StartsWith (#84885) --- src/coreclr/jit/importervectorization.cpp | 141 +++++++--------------- 1 file changed, 41 insertions(+), 100 deletions(-) diff --git a/src/coreclr/jit/importervectorization.cpp b/src/coreclr/jit/importervectorization.cpp index 9f7c6f3cefab2..da313d5e339bd 100644 --- a/src/coreclr/jit/importervectorization.cpp +++ b/src/coreclr/jit/importervectorization.cpp @@ -6,8 +6,8 @@ #pragma hdrstop #endif -// For now the max possible size is Vector256.Count * 2 -#define MaxPossibleUnrollSize 32 +// For now the max possible size is Vector512.Count * 2 +#define MaxPossibleUnrollSize 64 //------------------------------------------------------------------------ // importer_vectorization.cpp @@ -71,7 +71,7 @@ static bool ConvertToLowerCase(WCHAR* input, WCHAR* mask, int length) #if defined(FEATURE_HW_INTRINSICS) //------------------------------------------------------------------------ // impExpandHalfConstEqualsSIMD: Attempts to unroll and vectorize -// Equals against a constant WCHAR data for Length in [8..32] range +// Equals against a constant WCHAR data for Length in [8..64] range // using SIMD instructions. C# equivalent of what this function emits: // // bool IsTestString(ReadOnlySpan span) @@ -108,31 +108,20 @@ GenTree* Compiler::impExpandHalfConstEqualsSIMD( { assert(len >= 8 && len <= MaxPossibleUnrollSize); - if (!IsBaselineSimdIsaSupported()) + const int byteLen = len * sizeof(WCHAR); + const int simdSize = (int)roundDownSIMDSize(byteLen); + if (byteLen > (simdSize * 2)) { - // We need baseline SIMD support at least + // Data is too big to be processed via two SIMD loads + // or baseline has no SIMD support return nullptr; } - - CorInfoType baseType = CORINFO_TYPE_NATIVEUINT; - - int simdSize; - var_types simdType; - - NamedIntrinsic niEquals; - - GenTreeVecCon* cnsVec1 = nullptr; - GenTreeVecCon* cnsVec2 = nullptr; - GenTree* toLowerVec1 = nullptr; - GenTree* toLowerVec2 = nullptr; - - // Optimization: don't use two vectors for Length == 8 or 16 - bool useSingleVector = false; + assert((byteLen >= simdSize) && (simdSize >= 16)); WCHAR cnsValue[MaxPossibleUnrollSize] = {}; WCHAR toLowerMask[MaxPossibleUnrollSize] = {}; - memcpy((UINT8*)cnsValue, (UINT8*)cns, len * sizeof(WCHAR)); + memcpy(cnsValue, cns, byteLen); if ((cmpMode == OrdinalIgnoreCase) && !ConvertToLowerCase(cnsValue, toLowerMask, len)) { @@ -140,89 +129,23 @@ GenTree* Compiler::impExpandHalfConstEqualsSIMD( return nullptr; } -#if defined(TARGET_XARCH) - if (compOpportunisticallyDependsOn(InstructionSet_Vector256) && len >= 16) - { - // Handle [16..32] inputs via two Vector256 - assert(len >= 16 && len <= 32); - - simdSize = 32; - simdType = TYP_SIMD32; - - niEquals = NI_Vector256_op_Equality; - - // Special case: use a single vector for Length == 16 - useSingleVector = len == 16; - - cnsVec1 = gtNewVconNode(simdType, cnsValue); - cnsVec2 = gtNewVconNode(simdType, cnsValue + len - 16); - - if (cmpMode == OrdinalIgnoreCase) - { - toLowerVec1 = gtNewVconNode(simdType, toLowerMask); - toLowerVec2 = gtNewVconNode(simdType, toLowerMask + len - 16); - } - } - else -#endif // TARGET_XARCH - if (len <= 16) - { - // Handle [8..16] inputs via two Vector128 - assert(len >= 8 && len <= 16); - - simdSize = 16; - simdType = TYP_SIMD16; + const var_types simdType = getSIMDTypeForSize(simdSize); + const CorInfoType baseType = CORINFO_TYPE_NATIVEUINT; - niEquals = NI_Vector128_op_Equality; + GenTreeVecCon* cnsVec1 = gtNewVconNode(simdType, cnsValue); + GenTreeVecCon* cnsVec2 = gtNewVconNode(simdType, (BYTE*)cnsValue + byteLen - simdSize); - // Special case: use a single vector for Length == 8 - useSingleVector = len == 8; - - cnsVec1 = gtNewVconNode(simdType, cnsValue); - cnsVec2 = gtNewVconNode(simdType, cnsValue + len - 8); - - if (cmpMode == OrdinalIgnoreCase) - { - toLowerVec1 = gtNewVconNode(simdType, toLowerMask); - toLowerVec2 = gtNewVconNode(simdType, toLowerMask + len - 8); - } - } - else - { - JITDUMP("impExpandHalfConstEqualsSIMD: No V256 support and data is too big for V128\n"); - // NOTE: We might consider using four V128 for ARM64 - return nullptr; - } - - GenTree* zero = gtNewZeroConNode(simdType); - - GenTree* offset1 = gtNewIconNode(dataOffset, TYP_I_IMPL); - GenTree* offset2 = gtNewIconNode(dataOffset + len * sizeof(USHORT) - simdSize, TYP_I_IMPL); - GenTree* dataPtr1 = gtNewOperNode(GT_ADD, TYP_BYREF, data, offset1); - GenTree* dataPtr2 = gtNewOperNode(GT_ADD, TYP_BYREF, gtClone(data), offset2); - - GenTree* vec1 = gtNewIndir(simdType, dataPtr1); - GenTree* vec2 = gtNewIndir(simdType, dataPtr2); - - // TODO-Unroll-CQ: Spill vec1 and vec2 for better pipelining, currently we end up emitting: - // - // vmovdqu xmm0, xmmword ptr [rcx+12] - // vpxor xmm0, xmm0, xmmword ptr[reloc @RWD00] - // vmovdqu xmm1, xmmword ptr [rcx+20] - // vpxor xmm1, xmm1, xmmword ptr[reloc @RWD16] - // - // While we should re-order them to be: - // - // vmovdqu xmm0, xmmword ptr [rcx+12] - // vmovdqu xmm1, xmmword ptr [rcx+20] - // vpxor xmm0, xmm0, xmmword ptr[reloc @RWD00] - // vpxor xmm1, xmm1, xmmword ptr[reloc @RWD16] - // + GenTree* offset1 = gtNewIconNode(dataOffset, TYP_I_IMPL); + GenTree* offset2 = gtNewIconNode(dataOffset + byteLen - simdSize, TYP_I_IMPL); + GenTree* vec1 = gtNewIndir(simdType, gtNewOperNode(GT_ADD, TYP_BYREF, data, offset1)); + GenTree* vec2 = gtNewIndir(simdType, gtNewOperNode(GT_ADD, TYP_BYREF, gtClone(data), offset2)); if (cmpMode == OrdinalIgnoreCase) { // Apply ASCII-only ToLowerCase mask (bitwise OR 0x20 for all a-Z chars) - assert((toLowerVec1 != nullptr) && (toLowerVec2 != nullptr)); + GenTreeVecCon* toLowerVec1 = gtNewVconNode(simdType, toLowerMask); + GenTreeVecCon* toLowerVec2 = gtNewVconNode(simdType, (BYTE*)toLowerMask + byteLen - simdSize); + vec1 = gtNewSimdBinOpNode(GT_OR, simdType, vec1, toLowerVec1, baseType, simdSize); vec2 = gtNewSimdBinOpNode(GT_OR, simdType, vec2, toLowerVec2, baseType, simdSize); } @@ -231,7 +154,25 @@ GenTree* Compiler::impExpandHalfConstEqualsSIMD( GenTree* xor1 = gtNewSimdBinOpNode(GT_XOR, simdType, vec1, cnsVec1, baseType, simdSize); GenTree* xor2 = gtNewSimdBinOpNode(GT_XOR, simdType, vec2, cnsVec2, baseType, simdSize); GenTree* orr = gtNewSimdBinOpNode(GT_OR, simdType, xor1, xor2, baseType, simdSize); - return gtNewSimdHWIntrinsicNode(TYP_BOOL, useSingleVector ? xor1 : orr, zero, niEquals, baseType, simdSize); + + // Optimization: use a single load when byteLen equals simdSize. + // For code simplicity we always create nodes for two vectors case. + const bool useSingleVector = simdSize == byteLen; + return gtNewSimdCmpOpAllNode(GT_EQ, TYP_BOOL, useSingleVector ? xor1 : orr, gtNewZeroConNode(simdType), baseType, + simdSize); + + // Codegen example for byteLen=40 and OrdinalIgnoreCase mode with AVX: + // + // vmovups ymm0, ymmword ptr [rcx+0CH] + // vpor ymm0, ymm0, ymmword ptr [reloc @RWD00] + // vpxor ymm0, ymm0, ymmword ptr [reloc @RWD32] + // vmovups ymm1, ymmword ptr [rcx+28H] + // vpor ymm1, ymm1, ymmword ptr [reloc @RWD64] + // vpxor ymm1, ymm1, ymmword ptr [reloc @RWD96] + // vpor ymm0, ymm0, ymm1 + // vptest ymm0, ymm0 + // sete al + // movzx rax, al } #endif // defined(FEATURE_HW_INTRINSICS) @@ -491,7 +432,7 @@ GenTree* Compiler::impExpandHalfConstEquals(GenTreeLclVar* data, indirCmp = impExpandHalfConstEqualsSWAR(gtClone(data)->AsLclVar(), cnsData, len, dataOffset, cmpMode); } #if defined(FEATURE_HW_INTRINSICS) - else if (len <= 32) + else if (IsBaselineSimdIsaSupported()) { indirCmp = impExpandHalfConstEqualsSIMD(gtClone(data)->AsLclVar(), cnsData, len, dataOffset, cmpMode); } From b2fa5bdeb3bab8e21524c162fb9042030ae1ac9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Mon, 17 Apr 2023 22:24:50 +0200 Subject: [PATCH 24/32] Integrate compression from StaticWebAssets (#84924) --- ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 3fe69f51c2e0e..c610f34c1b689 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -31,6 +31,10 @@ Copyright (c) .NET Foundation. All rights reserved. <_WebAssemblySdkTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">net8.0 <_WebAssemblySdkTasksTFM Condition=" '$(MSBuildRuntimeType)' != 'Core'">net472 <_WebAssemblySdkTasksAssembly>$(WebAssemblySdkDirectoryRoot)tools\$(_WebAssemblySdkTasksTFM)\Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.dll + + + $(CompressionIncludePatterns);_framework\** + true @@ -77,28 +81,48 @@ Copyright (c) .NET Foundation. All rights reserved. + $(ResolveStaticWebAssetsInputsDependsOn); _AddWasmStaticWebAssets; - _GenerateBuildWasmBootJson; $(StaticWebAssetsPrepareForRunDependsOn) - $(ResolvePublishStaticWebAssetsDependsOn); ProcessPublishFilesForWasm; ComputeWasmExtensions; _AddPublishWasmBootJsonToStaticWebAssets; - $(GenerateStaticWebAssetsPublishManifestDependsOn); GeneratePublishWasmBootJson; + + + $(ResolveCompressedFilesDependsOn); + ResolveWasmOutputs; + _AddWasmStaticWebAssets; + + + $(ResolveCompressedFilesForPublishDependsOn); + ProcessPublishFilesForWasm; + ComputeWasmExtensions; + _AddPublishWasmBootJsonToStaticWebAssets; + + + $(CompressFilesDependsOn) + _GenerateBuildWasmBootJson; + + + $(CompressFilesForPublishDependsOn); + GeneratePublishWasmBootJson; + + + $(AddWasmStaticWebAssetsDependsOn); ResolveWasmOutputs; @@ -381,6 +405,7 @@ Copyright (c) .NET Foundation. All rights reserved. + From 63b9a3ae133942f4f8ea64f057f82f5fd8a2ffe5 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 17 Apr 2023 13:43:19 -0700 Subject: [PATCH 25/32] Fix nativeaot libraries test cross-build (#84870) --- eng/testing/tests.singlefile.targets | 30 +++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/eng/testing/tests.singlefile.targets b/eng/testing/tests.singlefile.targets index 821e8f93750b4..6b869bd02c60a 100644 --- a/eng/testing/tests.singlefile.targets +++ b/eng/testing/tests.singlefile.targets @@ -23,7 +23,7 @@ $(CoreCLRILCompilerDir) - $(CoreCLRCrossILCompilerDir) + $(CoreCLRCrossILCompilerDir) $(ROOTFS_DIR) $(CoreCLRILCompilerDir)netstandard/ILCompiler.Build.Tasks.dll $(CoreCLRAotSdkDir) @@ -36,6 +36,34 @@ true + + + + + $(RuntimeIdentifier) + + + x86_64 + aarch64 + arm64 + + + $(CrossCompileArch)-linux-gnu + $(CrossCompileArch)-alpine-linux-musl + $(CrossCompileArch)-unknown-freebsd12 + + + + + + + + + + + $(DefineConstants);SINGLE_FILE_TEST_RUNNER From 1212946a276b1356b982c005893a2dd9fbf98793 Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Mon, 17 Apr 2023 14:05:07 -0700 Subject: [PATCH 26/32] Fix JIT use of BitScan* APIs (#84915) * Fix JIT use of BitScan* APIs windows.h defines the BitScan* APIs with a leading underscore and includes `#define` definitions of non-underscore versions to the underscore versions. This is annoying in the JIT, where we have a BitOperations class that uses these same names; the class members end up with leading underscores and it confuses Visual Studio source browsing. In the JIT, `#undef` the windows.h underscore defines. Define pass-through non-underscore functions to call the actual functions. (We need to always call the non-underscore versions because that is what is defined in the PAL.) Replace usage of bitposition.h in the JIT and remove it from utilcode.h (only one other place in the CLR uses it and they already include it.) * Fixes 1. Remove unused genFindHighestBit 2. Remove genFindLowestReg 3. Remove BitScanForwardPtr 4. Put BitScanForward64/BitScanReverse64 under `HOST_64BIT` --- src/coreclr/inc/utilcode.h | 2 - src/coreclr/jit/compiler.cpp | 8 --- src/coreclr/jit/compiler.hpp | 125 +++++------------------------------ src/coreclr/jit/emit.cpp | 2 +- src/coreclr/jit/emitarm.cpp | 2 +- src/coreclr/jit/gcencode.cpp | 6 +- src/coreclr/jit/hashbv.h | 4 +- src/coreclr/jit/jitpch.h | 16 +++++ src/coreclr/jit/utils.h | 33 +++++++-- 9 files changed, 66 insertions(+), 132 deletions(-) diff --git a/src/coreclr/inc/utilcode.h b/src/coreclr/inc/utilcode.h index 1b39056d057fd..bbfac6e210e92 100644 --- a/src/coreclr/inc/utilcode.h +++ b/src/coreclr/inc/utilcode.h @@ -872,8 +872,6 @@ inline int CountBits(int iNum) return (iBits); } -#include "bitposition.h" - // Convert the currency to a decimal and canonicalize. inline void VarDecFromCyCanonicalize(CY cyIn, DECIMAL* dec) { diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 09b2d3e7f292f..8215b4e1b56a8 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -26,14 +26,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX extern ICorJitHost* g_jitHost; -#if defined(DEBUG) -// Column settings for DOTNET_JitDumpIR. We could(should) make these programmable. -#define COLUMN_OPCODE 30 -#define COLUMN_OPERANDS (COLUMN_OPCODE + 25) -#define COLUMN_KINDS 110 -#define COLUMN_FLAGS (COLUMN_KINDS + 32) -#endif - unsigned Compiler::jitTotalMethodCompiled = 0; #if defined(DEBUG) diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 4957a1c30e65e..7e4eb4c14d895 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -97,53 +97,9 @@ inline T genFindLowestBit(T value) return (value & (0 - value)); } -//------------------------------------------------------------------------ -// genFindHighestBit: Return the highest bit that is set (that is, a mask that includes just the -// highest bit). -// -// Return Value: -// The highest position (0 is LSB) of bit that is set in the 'value'. -// -// Note: -// It performs the "LeadingZeroCount " operation using intrinsics and then mask out everything -// but the highest bit. -inline unsigned int genFindHighestBit(unsigned int mask) -{ - assert(mask != 0); -#if defined(_MSC_VER) - unsigned long index; -#else - unsigned int index; -#endif - BitScanReverse(&index, mask); - return 1L << index; -} - -//------------------------------------------------------------------------ -// genFindHighestBit: Return the highest bit that is set (that is, a mask that includes just the -// highest bit). -// -// Return Value: -// The highest position (0 is LSB) of bit that is set in the 'value'. -// -// Note: -// It performs the "LeadingZeroCount " operation using intrinsics and then mask out everything -// but the highest bit. -inline unsigned __int64 genFindHighestBit(unsigned __int64 mask) -{ - assert(mask != 0); -#if defined(_MSC_VER) - unsigned long index; -#else - unsigned int index; -#endif - BitScanReverse64(&index, mask); - return 1LL << index; -} - /***************************************************************************** * -* Return true if the given 64-bit value has exactly zero or one bits set. +* Return true if the given value has exactly zero or one bits set. */ template @@ -154,17 +110,7 @@ inline bool genMaxOneBit(T value) /***************************************************************************** * -* Return true if the given 32-bit value has exactly zero or one bits set. -*/ - -inline bool genMaxOneBit(unsigned value) -{ - return (value & (value - 1)) == 0; -} - -/***************************************************************************** -* -* Return true if the given 64-bit value has exactly one bit set. +* Return true if the given value has exactly one bit set. */ template @@ -173,16 +119,6 @@ inline bool genExactlyOneBit(T value) return ((value != 0) && genMaxOneBit(value)); } -/***************************************************************************** -* -* Return true if the given 32-bit value has exactly zero or one bits set. -*/ - -inline bool genExactlyOneBit(unsigned value) -{ - return ((value != 0) && genMaxOneBit(value)); -} - /***************************************************************************** * * Given a value that has exactly one bit set, return the position of that @@ -190,47 +126,14 @@ inline bool genExactlyOneBit(unsigned value) */ inline unsigned genLog2(unsigned value) { - return BitPosition(value); -} - -// Given an unsigned 64-bit value, returns the lower 32-bits in unsigned format -// -inline unsigned ulo32(unsigned __int64 value) -{ - return static_cast(value); -} - -// Given an unsigned 64-bit value, returns the upper 32-bits in unsigned format -// -inline unsigned uhi32(unsigned __int64 value) -{ - return static_cast(value >> 32); + assert(genExactlyOneBit(value)); + return BitOperations::BitScanForward(value); } -/***************************************************************************** - * - * Given a value that has exactly one bit set, return the position of that - * bit, in other words return the logarithm in base 2 of the given value. - */ - inline unsigned genLog2(unsigned __int64 value) { -#ifdef HOST_64BIT - return BitPosition(value); -#else // HOST_32BIT - unsigned lo32 = ulo32(value); - unsigned hi32 = uhi32(value); - - if (lo32 != 0) - { - assert(hi32 == 0); - return genLog2(lo32); - } - else - { - return genLog2(hi32) + 32; - } -#endif + assert(genExactlyOneBit(value)); + return BitOperations::BitScanForward(value); } #ifdef __APPLE__ @@ -240,14 +143,18 @@ inline unsigned genLog2(size_t value) } #endif // __APPLE__ -/***************************************************************************** - * - * Return the lowest bit that is set in the given register mask. - */ +// Given an unsigned 64-bit value, returns the lower 32-bits in unsigned format +// +inline unsigned ulo32(unsigned __int64 value) +{ + return static_cast(value); +} -inline regMaskTP genFindLowestReg(regMaskTP value) +// Given an unsigned 64-bit value, returns the upper 32-bits in unsigned format +// +inline unsigned uhi32(unsigned __int64 value) { - return (regMaskTP)genFindLowestBit(value); + return static_cast(value >> 32); } /***************************************************************************** diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index d8295a496bf38..97de8d503606c 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -6164,7 +6164,7 @@ unsigned emitter::emitCalculatePaddingForLoopAlignment(insGroup* loopHeadIG, if (emitComp->opts.compJitAlignLoopAdaptive) { // For adaptive, adjust the loop size depending on the alignment boundary - maxLoopBlocksAllowed = genLog2((unsigned)alignmentBoundary) - 1; + maxLoopBlocksAllowed = genLog2(alignmentBoundary) - 1; maxLoopSize = alignmentBoundary * maxLoopBlocksAllowed; } else diff --git a/src/coreclr/jit/emitarm.cpp b/src/coreclr/jit/emitarm.cpp index 81eb8ed27c26f..a82f37421d0dc 100644 --- a/src/coreclr/jit/emitarm.cpp +++ b/src/coreclr/jit/emitarm.cpp @@ -4190,7 +4190,7 @@ void emitter::emitIns_R_ARX( assert(!"Please use ins_Load() to select the correct instruction"); } - unsigned shift = genLog2((unsigned)mul); + unsigned shift = genLog2(mul); if ((ins == INS_lea) || emitInsIsLoad(ins)) { diff --git a/src/coreclr/jit/gcencode.cpp b/src/coreclr/jit/gcencode.cpp index dcbfd1d7064b0..eaa5a584261a3 100644 --- a/src/coreclr/jit/gcencode.cpp +++ b/src/coreclr/jit/gcencode.cpp @@ -2645,7 +2645,7 @@ size_t GCInfo::gcMakeRegPtrTable(BYTE* dest, int mask, const InfoHdr& header, un /* Get hold of the next register bit */ - tmpMask = genFindLowestReg(regMask); + tmpMask = genFindLowestBit(regMask); assert(tmpMask); /* Remember the new state of this register */ @@ -2694,7 +2694,7 @@ size_t GCInfo::gcMakeRegPtrTable(BYTE* dest, int mask, const InfoHdr& header, un /* Get hold of the next register bit */ - tmpMask = genFindLowestReg(regMask); + tmpMask = genFindLowestBit(regMask); assert(tmpMask); /* Remember the new state of this register */ @@ -4627,7 +4627,7 @@ void GCInfo::gcInfoRecordGCRegStateChange(GcInfoEncoder* gcInfoEncoder, while (regMask) { // Get hold of the next register bit. - regMaskTP tmpMask = genFindLowestReg(regMask); + regMaskTP tmpMask = genFindLowestBit(regMask); assert(tmpMask); // Remember the new state of this register. diff --git a/src/coreclr/jit/hashbv.h b/src/coreclr/jit/hashbv.h index 1c5e4310dcfa8..7ad95998add8e 100644 --- a/src/coreclr/jit/hashbv.h +++ b/src/coreclr/jit/hashbv.h @@ -323,12 +323,10 @@ HbvWalk ForEachHbvBitSet(const hashBv& bv, TFunctor func) indexType base = node->baseIndex; for (int el = 0; el < node->numElements(); el++) { - elemType i = 0; elemType e = node->elements[el]; while (e) { - int result = BitScanForwardPtr((DWORD*)&i, e); - assert(result); + unsigned i = BitOperations::BitScanForward(e); indexType index = base + (el * BITS_PER_ELEMENT) + i; e ^= (elemType(1) << i); diff --git a/src/coreclr/jit/jitpch.h b/src/coreclr/jit/jitpch.h index e99ecd6c9f330..63f12133f61bf 100644 --- a/src/coreclr/jit/jitpch.h +++ b/src/coreclr/jit/jitpch.h @@ -13,6 +13,22 @@ #include #include +// Don't allow using the windows.h #defines for the BitScan* APIs. Using the #defines means our +// `BitOperations::BitScan*` functions have their name mapped, which is confusing and messes up +// Visual Studio source browsing. +#ifdef BitScanForward +#undef BitScanForward +#endif +#ifdef BitScanReverse +#undef BitScanReverse +#endif +#ifdef BitScanForward64 +#undef BitScanForward64 +#endif +#ifdef BitScanReverse64 +#undef BitScanReverse64 +#endif + #include "jitconfig.h" #include "jit.h" #include "iallocator.h" diff --git a/src/coreclr/jit/utils.h b/src/coreclr/jit/utils.h index d78000bfb7d26..7fd3e7d10f884 100644 --- a/src/coreclr/jit/utils.h +++ b/src/coreclr/jit/utils.h @@ -25,11 +25,34 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // Needed for unreached() #include "error.h" -#ifdef TARGET_64BIT -#define BitScanForwardPtr BitScanForward64 -#else -#define BitScanForwardPtr BitScanForward -#endif +#if defined(_MSC_VER) + +// Define wrappers over the non-underscore versions of the BitScan* APIs. The PAL defines these already. +// We've #undef'ed the definitions in winnt.h for these names to avoid confusion. + +inline BOOLEAN BitScanForward(DWORD* Index, DWORD Mask) +{ + return ::_BitScanForward(Index, Mask); +} + +inline BOOLEAN BitScanReverse(DWORD* Index, DWORD Mask) +{ + return ::_BitScanReverse(Index, Mask); +} + +#if defined(HOST_64BIT) +inline BOOLEAN BitScanForward64(DWORD* Index, DWORD64 Mask) +{ + return ::_BitScanForward64(Index, Mask); +} + +inline BOOLEAN BitScanReverse64(DWORD* Index, DWORD64 Mask) +{ + return ::_BitScanReverse64(Index, Mask); +} +#endif // defined(HOST_64BIT) + +#endif // _MSC_VER template inline constexpr unsigned ArrLen(T (&)[size]) From add51b82baf268c3678bdd124480a46b89d72ce4 Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Mon, 17 Apr 2023 14:09:56 -0700 Subject: [PATCH 27/32] Memory Diagnostics: GC Bookkeeping (#84454) * Add ISOSMemoryEnum and HandleTable enum * Update comment * Add GC Bookkeeping data to the dac - bookkeeping_covered_start is now compiled into all versions of the GC, instead of just with USE_REGIONS. This allows us to find the base address of the allocated memory for GC Bookkeeping. - Added dac enumeration of GC Bookkeeping. * Add assert * Add support for free gc regions * Don't require card_table_element_layout * Fix issue with naming in request * Remote DEFINE_MISSING_FIELD from dac We should never have missing fields in the dac. This is a leftover from previous code. * Whitespace fix * Break if we loop * Fix static_assert * Segment fixes When using segments, update bookkeeping_covered_start and card_table_info.size when we update the card table. * Defensive coding Check how many times we loop through memory to guard against heap corruption. * free_region fixes * Remove hardcoding of region list * Fix gcc warnings * Remove unneeded #define * Add freeable_soh_segment/freeable_uoh_segment * Add more card table checks * Fix field definition issue * Fix pointer issue * Fix compile issue * Rename bookkeeping_covered_start to bookkeeping_start * Update src/coreclr/debug/daccess/daccess.cpp Co-authored-by: Andrew Au * Code review feedback * Remove unused parameter * Add heap number --------- Co-authored-by: Andrew Au Co-authored-by: Andrew Au --- src/coreclr/debug/daccess/daccess.cpp | 232 ++++++++++++++++++++- src/coreclr/debug/daccess/dacimpl.h | 54 +++++ src/coreclr/debug/daccess/request.cpp | 92 ++++++++ src/coreclr/debug/daccess/request_svr.cpp | 22 ++ src/coreclr/gc/dac_gcheap_fields.h | 15 +- src/coreclr/gc/gc.cpp | 53 +++-- src/coreclr/gc/gcinterface.dac.h | 50 ++++- src/coreclr/gc/gcinterface.dacvars.def | 6 + src/coreclr/gc/gcpriv.h | 6 +- src/coreclr/gc/handletableconstants.h | 117 +++++++++++ src/coreclr/gc/handletablepriv.h | 118 +---------- src/coreclr/gc/objecthandle.cpp | 2 + src/coreclr/inc/sospriv.idl | 33 ++- src/coreclr/pal/prebuilt/idl/sospriv_i.cpp | 11 +- src/coreclr/pal/prebuilt/inc/sospriv.h | 177 +++++++++++++++- src/coreclr/vm/decodemd.cpp | 1 - 16 files changed, 841 insertions(+), 148 deletions(-) create mode 100644 src/coreclr/gc/handletableconstants.h diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index 3a0ceb80e6057..88003b8893500 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -7654,7 +7654,6 @@ void DacHandleWalker::WalkHandles() { if (mask & 1) { - dac_handle_table *pTable = hTable; PTR_AppDomain pDomain = AppDomain::GetCurrentDomain(); param.AppDomain = TO_CDADDR(pDomain.GetAddr()); param.Type = handleType; @@ -8285,3 +8284,234 @@ HRESULT DacStackReferenceErrorEnum::Next(unsigned int count, SOSStackRefError re *pFetched = i; return i < count ? S_FALSE : S_OK; } + + +HRESULT DacMemoryEnumerator::Skip(unsigned int count) +{ + mIteratorIndex += count; + return S_OK; +} + +HRESULT DacMemoryEnumerator::Reset() +{ + mIteratorIndex = 0; + return S_OK; +} + +HRESULT DacMemoryEnumerator::GetCount(unsigned int* pCount) +{ + if (!pCount) + return E_POINTER; + + mRegions.GetCount(); + return S_OK; +} + +HRESULT DacMemoryEnumerator::Next(unsigned int count, SOSMemoryRegion regions[], unsigned int* pFetched) +{ + if (!pFetched) + return E_POINTER; + + if (!regions) + return E_POINTER; + + unsigned int i = 0; + while (i < count && mIteratorIndex < mRegions.GetCount()) + { + regions[i++] = mRegions.Get(mIteratorIndex++); + } + + *pFetched = i; + return i < count ? S_FALSE : S_OK; +} + + +HRESULT DacGCBookkeepingEnumerator::Init() +{ + if (g_gcDacGlobals->bookkeeping_start == nullptr) + return E_FAIL; + + TADDR ctiAddr = TO_TADDR(*g_gcDacGlobals->bookkeeping_start); + if (ctiAddr == 0) + return E_FAIL; + + DPTR(dac_card_table_info) card_table_info(ctiAddr); + + SOSMemoryRegion mem = {0}; + if (card_table_info->recount && card_table_info->size) + { + mem.Start = card_table_info.GetAddr(); + mem.Size = card_table_info->size; + mRegions.Add(mem); + } + + size_t card_table_info_size = g_gcDacGlobals->card_table_info_size; + TADDR next = card_table_info->next_card_table; + + // Cap the number of regions we will walk in case we have run into some kind of + // memory corruption. We shouldn't have more than a few linked card tables anyway. + int maxRegions = 32; + + // This loop is effectively "while (next != 0)" but with an added check to make + // sure we don't underflow next when subtracting card_table_info_size if we encounter + // a bad pointer. + while (next > card_table_info_size) + { + DPTR(dac_card_table_info) ct(next - card_table_info_size); + + if (ct->recount && ct->size) + { + mem = {0}; + mem.Start = ct.GetAddr(); + mem.Size = ct->size; + mRegions.Add(mem); + } + + next = ct->next_card_table; + if (next == card_table_info->next_card_table) + break; + + if (--maxRegions <= 0) + break; + } + + return S_OK; +} + + +HRESULT DacHandleTableMemoryEnumerator::Init() +{ + int max_slots = 1; + +#ifdef FEATURE_SVR_GC + if (GCHeapUtilities::IsServerHeap()) + max_slots = GCHeapCount(); +#endif // FEATURE_SVR_GC + + // Cap the number of regions we will walk in case we hit an infinite loop due + // to memory corruption + int maxRegions = 8192; + + for (dac_handle_table_map *map = g_gcDacGlobals->handle_table_map; map && maxRegions >= 0; map = map->pNext, maxRegions--) + { + for (int i = 0; i < INITIAL_HANDLE_TABLE_ARRAY_SIZE; ++i) + { + if (map->pBuckets[i] != NULL) + { + for (int j = 0; j < max_slots ; ++j) + { + DPTR(dac_handle_table) pTable = map->pBuckets[i]->pTable[j]; + DPTR(dac_handle_table_segment) pFirstSegment = pTable->pSegmentList; + DPTR(dac_handle_table_segment) curr = pFirstSegment; + + do + { + SOSMemoryRegion mem = {0}; + mem.Start = curr.GetAddr(); + mem.Size = HANDLE_SEGMENT_SIZE; + mem.Heap = j; // heap number + + mRegions.Add(mem); + + curr = curr->pNextSegment; + } while (curr != nullptr && curr != pFirstSegment); + } + } + } + } + + return S_OK; +} + +void DacFreeRegionEnumerator::AddSingleSegment(const dac_heap_segment &curr, FreeRegionKind kind, int heap) +{ + SOSMemoryRegion mem = {0}; + mem.Start = TO_CDADDR(curr.mem); + mem.ExtraData = (CLRDATA_ADDRESS)kind; + mem.Heap = heap; + + if (curr.mem < curr.committed) + mem.Size = TO_CDADDR(curr.committed) - mem.Start; + + if (mem.Start) + mRegions.Add(mem); +} + +void DacFreeRegionEnumerator::AddSegmentList(DPTR(dac_heap_segment) start, FreeRegionKind kind, int heap) +{ + int iterationMax = 2048; + + DPTR(dac_heap_segment) curr = start; + while (curr != nullptr) + { + AddSingleSegment(*curr, kind, heap); + + curr = curr->next; + if (curr == start) + break; + + if (iterationMax-- <= 0) + break; + } +} + +void DacFreeRegionEnumerator::AddFreeList(DPTR(dac_region_free_list) free_list, FreeRegionKind kind) +{ + if (free_list != nullptr) + { + AddSegmentList(free_list->head_free_region, kind); + } +} + +HRESULT DacFreeRegionEnumerator::Init() +{ + // Cap the number of free regions we will walk at a sensible number. This is to protect against + // memory corruption, un-initialized data, or just a bug. + int count_free_region_kinds = g_gcDacGlobals->count_free_region_kinds; + count_free_region_kinds = min(count_free_region_kinds, 16); + + unsigned int index = 0; + if (g_gcDacGlobals->global_free_huge_regions != nullptr) + { + DPTR(dac_region_free_list) global_free_huge_regions(g_gcDacGlobals->global_free_huge_regions); + AddFreeList(global_free_huge_regions, FreeRegionKind::FreeGlobalHugeRegion); + } + + if (g_gcDacGlobals->global_regions_to_decommit != nullptr) + { + DPTR(dac_region_free_list) regionList(g_gcDacGlobals->global_regions_to_decommit); + if (regionList != nullptr) + for (int i = 0; i < count_free_region_kinds; i++, regionList++) + AddFreeList(regionList, FreeRegionKind::FreeGlobalRegion); + } + +#if defined(FEATURE_SVR_GC) + if (GCHeapUtilities::IsServerHeap()) + { + AddServerRegions(); + } + else +#endif //FEATURE_SVR_GC + { + DPTR(dac_region_free_list) regionList(g_gcDacGlobals->free_regions); + if (regionList != nullptr) + for (int i = 0; i < count_free_region_kinds; i++, regionList++) + AddFreeList(regionList, FreeRegionKind::FreeRegion); + + if (g_gcDacGlobals->freeable_soh_segment != nullptr) + { + DPTR(DPTR(dac_heap_segment)) freeable_soh_segment_ptr(g_gcDacGlobals->freeable_soh_segment); + if (freeable_soh_segment_ptr != nullptr) + AddSegmentList(*freeable_soh_segment_ptr, FreeRegionKind::FreeSohSegment); + } + + if (g_gcDacGlobals->freeable_uoh_segment != nullptr) + { + DPTR(DPTR(dac_heap_segment)) freeable_uoh_segment_ptr(g_gcDacGlobals->freeable_uoh_segment); + if (freeable_uoh_segment_ptr != nullptr) + AddSegmentList(*freeable_uoh_segment_ptr, FreeRegionKind::FreeUohSegment); + } + } + + return S_OK; +} diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index 52ef9cf5979d9..ddf61370f416e 100644 --- a/src/coreclr/debug/daccess/dacimpl.h +++ b/src/coreclr/debug/daccess/dacimpl.h @@ -1211,6 +1211,10 @@ class ClrDataAccess virtual HRESULT STDMETHODCALLTYPE GetDomainLoaderAllocator(CLRDATA_ADDRESS domainAddress, CLRDATA_ADDRESS *pLoaderAllocator); virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeapNames(int count, const char **ppNames, int *pNeeded); virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocator, int count, CLRDATA_ADDRESS *pLoaderHeaps, LoaderHeapKind *pKinds, int *pNeeded); + virtual HRESULT STDMETHODCALLTYPE GetHandleTableMemoryRegions(ISOSMemoryEnum **ppEnum); + virtual HRESULT STDMETHODCALLTYPE GetGCBookkeepingMemoryRegions(ISOSMemoryEnum **ppEnum); + virtual HRESULT STDMETHODCALLTYPE GetGCFreeRegions(ISOSMemoryEnum **ppEnum); + virtual HRESULT STDMETHODCALLTYPE LockedFlush(); // // ClrDataAccess. @@ -1954,6 +1958,56 @@ class DacReferenceList unsigned int _capacity; }; + +class DacMemoryEnumerator : public DefaultCOMImpl +{ +public: + DacMemoryEnumerator() + : mIteratorIndex(0) + { + } + + virtual ~DacMemoryEnumerator() {} + virtual HRESULT Init() = 0; + + HRESULT STDMETHODCALLTYPE Skip(unsigned int count); + HRESULT STDMETHODCALLTYPE Reset(); + HRESULT STDMETHODCALLTYPE GetCount(unsigned int *pCount); + HRESULT STDMETHODCALLTYPE Next(unsigned int count, + SOSMemoryRegion regions[], + unsigned int *pFetched); + +protected: + DacReferenceList mRegions; + +private: + unsigned int mIteratorIndex; +}; + +class DacHandleTableMemoryEnumerator : public DacMemoryEnumerator +{ +public: + virtual HRESULT Init(); +}; + +class DacGCBookkeepingEnumerator : public DacMemoryEnumerator +{ +public: + virtual HRESULT Init(); +}; + +class DacFreeRegionEnumerator : public DacMemoryEnumerator +{ +public: + virtual HRESULT Init(); + +private: + void AddSingleSegment(const dac_heap_segment &seg, FreeRegionKind kind, int heap); + void AddSegmentList(DPTR(dac_heap_segment) seg, FreeRegionKind kind, int heap = 0); + void AddFreeList(DPTR(dac_region_free_list) freeList, FreeRegionKind kind); + void AddServerRegions(); +}; + struct DacGcReference; /* DacStackReferenceWalker. */ diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index b5a0aa1986bd2..9ccb7d6272442 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -5295,3 +5295,95 @@ HRESULT ClrDataAccess::GetGlobalAllocationContext( SOSDacLeave(); return hr; } + +HRESULT ClrDataAccess::GetHandleTableMemoryRegions(ISOSMemoryEnum** ppEnum) +{ + if (!ppEnum) + return E_POINTER; + + SOSDacEnter(); + + DacHandleTableMemoryEnumerator* htEnum = new (nothrow) DacHandleTableMemoryEnumerator(); + if (htEnum) + { + hr = htEnum->Init(); + + if (SUCCEEDED(hr)) + hr = htEnum->QueryInterface(__uuidof(ISOSMemoryEnum), (void**)ppEnum); + + if (FAILED(hr)) + delete htEnum; + } + else + { + hr = E_OUTOFMEMORY; + } + + SOSDacLeave(); + return hr; +} + +HRESULT ClrDataAccess::GetGCBookkeepingMemoryRegions(ISOSMemoryEnum** ppEnum) +{ + if (!ppEnum) + return E_POINTER; + + SOSDacEnter(); + + DacGCBookkeepingEnumerator* bkEnum = new (nothrow) DacGCBookkeepingEnumerator(); + if (bkEnum) + { + hr = bkEnum->Init(); + + if (SUCCEEDED(hr)) + hr = bkEnum->QueryInterface(__uuidof(ISOSMemoryEnum), (void**)ppEnum); + + if (FAILED(hr)) + delete bkEnum; + } + else + { + hr = E_OUTOFMEMORY; + } + + SOSDacLeave(); + return hr; +} + + +HRESULT ClrDataAccess::GetGCFreeRegions(ISOSMemoryEnum **ppEnum) +{ + if (!ppEnum) + return E_POINTER; + + SOSDacEnter(); + + DacFreeRegionEnumerator* frEnum = new (nothrow) DacFreeRegionEnumerator(); + if (frEnum) + { + hr = frEnum->Init(); + + if (SUCCEEDED(hr)) + hr = frEnum->QueryInterface(__uuidof(ISOSMemoryEnum), (void**)ppEnum); + + if (FAILED(hr)) + delete frEnum; + } + else + { + hr = E_OUTOFMEMORY; + } + + SOSDacLeave(); + return hr; +} + +HRESULT ClrDataAccess::LockedFlush() +{ + SOSDacEnter(); + + Flush(); + + SOSDacLeave(); + return hr; +} diff --git a/src/coreclr/debug/daccess/request_svr.cpp b/src/coreclr/debug/daccess/request_svr.cpp index e59255a4e5a68..3955d8f05db5c 100644 --- a/src/coreclr/debug/daccess/request_svr.cpp +++ b/src/coreclr/debug/daccess/request_svr.cpp @@ -459,4 +459,26 @@ HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount) return S_OK; } +void DacFreeRegionEnumerator::AddServerRegions() +{ + // Cap the number of free regions we will walk at a sensible number. This is to protect against + // memory corruption, un-initialized data, or just a bug. + int count_free_region_kinds = g_gcDacGlobals->count_free_region_kinds; + count_free_region_kinds = min(count_free_region_kinds, 16); + + for (int i = 0; i < GCHeapCount(); i++) + { + TADDR heapAddress = (TADDR)HeapTableIndex(g_gcDacGlobals->g_heaps, i); + if (heapAddress == 0) + continue; + + dac_gc_heap heap = LoadGcHeapData(heapAddress); + for (int i = 0; i < count_free_region_kinds; i++) + AddSegmentList(heap.free_regions[i].head_free_region, FreeRegionKind::FreeRegion, i); + + AddSegmentList(heap.freeable_soh_segment, FreeRegionKind::FreeSohSegment, i); + AddSegmentList(heap.freeable_uoh_segment, FreeRegionKind::FreeUohSegment, i); + } +} + #endif // defined(FEATURE_SVR_GC) diff --git a/src/coreclr/gc/dac_gcheap_fields.h b/src/coreclr/gc/dac_gcheap_fields.h index 104157261635a..37b6389ff1ea1 100644 --- a/src/coreclr/gc/dac_gcheap_fields.h +++ b/src/coreclr/gc/dac_gcheap_fields.h @@ -10,23 +10,34 @@ DEFINE_FIELD (internal_root_array, uint8_t*) DEFINE_FIELD (internal_root_array_index, size_t) DEFINE_FIELD (heap_analyze_success, BOOL) DEFINE_FIELD (card_table, uint32_t*) + #if defined(ALL_FIELDS) || defined(BACKGROUND_GC) DEFINE_FIELD (mark_array, uint32_t*) DEFINE_FIELD (next_sweep_obj, uint8_t*) DEFINE_FIELD (background_saved_lowest_address, uint8_t*) DEFINE_FIELD (background_saved_highest_address, uint8_t*) +DEFINE_DPTR_FIELD (freeable_soh_segment, dac_heap_segment) +DEFINE_DPTR_FIELD (freeable_uoh_segment, dac_heap_segment) #if defined(ALL_FIELDS) || !defined(USE_REGIONS) DEFINE_DPTR_FIELD (saved_sweep_ephemeral_seg, dac_heap_segment) DEFINE_FIELD (saved_sweep_ephemeral_start, uint8_t*) #else DEFINE_MISSING_FIELD(saved_sweep_ephemeral_seg) DEFINE_MISSING_FIELD(saved_sweep_ephemeral_start) -#endif +#endif // defined(ALL_FIELDS) || !defined(USE_REGIONS) #else DEFINE_MISSING_FIELD(mark_array) DEFINE_MISSING_FIELD(next_sweep_obj) DEFINE_MISSING_FIELD(background_saved_lowest_address) DEFINE_MISSING_FIELD(background_saved_highest_address) +DEFINE_MISSING_FIELD(freeable_soh_segment) +DEFINE_MISSING_FIELD(freeable_uoh_segment) DEFINE_MISSING_FIELD(saved_sweep_ephemeral_seg) DEFINE_MISSING_FIELD(saved_sweep_ephemeral_start) -#endif +#endif // defined(ALL_FIELDS) || defined(BACKGROUND_GC) + +#if defined(ALL_FIELDS) || defined(USE_REGIONS) +DEFINE_ARRAY_FIELD (free_regions, dac_region_free_list, FREE_REGION_KINDS) +#else +DEFINE_MISSING_FIELD(free_regions) +#endif // ALL_FIELDS diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index 474e041974cf9..358f803887e35 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -2228,8 +2228,8 @@ size_t gc_heap::g_bpromoted; #endif //MULTIPLE_HEAPS size_t gc_heap::card_table_element_layout[total_bookkeeping_elements + 1]; +uint8_t* gc_heap::bookkeeping_start = nullptr; #ifdef USE_REGIONS -uint8_t* gc_heap::bookkeeping_covered_start = nullptr; uint8_t* gc_heap::bookkeeping_covered_committed = nullptr; size_t gc_heap::bookkeeping_sizes[total_bookkeeping_elements]; #endif //USE_REGIONS @@ -8378,6 +8378,9 @@ class card_table_info { public: unsigned recount; + size_t size; + uint32_t* next_card_table; + uint8_t* lowest_address; uint8_t* highest_address; short* brick_table; @@ -8391,11 +8394,11 @@ class card_table_info #ifdef BACKGROUND_GC uint32_t* mark_array; #endif //BACKGROUND_GC - - size_t size; - uint32_t* next_card_table; }; +static_assert(offsetof(dac_card_table_info, size) == offsetof(card_table_info, size), "DAC card_table_info layout mismatch"); +static_assert(offsetof(dac_card_table_info, next_card_table) == offsetof(card_table_info, next_card_table), "DAC card_table_info layout mismatch"); + //These are accessors on untranslated cardtable inline unsigned& card_table_refcount (uint32_t* c_table) @@ -8623,6 +8626,9 @@ void gc_heap::clear_mark_array (uint8_t* from, uint8_t* end) inline uint32_t*& card_table_next (uint32_t* c_table) { + // NOTE: The dac takes a dependency on card_table_info being right before c_table. + // It's 100% ok to change this implementation detail as long as a matching change + // is made to DacGCBookkeepingEnumerator::Init in daccess.cpp. return ((card_table_info*)((uint8_t*)c_table - sizeof (card_table_info)))->next_card_table; } @@ -8907,21 +8913,21 @@ bool gc_heap::inplace_commit_card_table (uint8_t* from, uint8_t* to) uint8_t* commit_end = nullptr; if (initial_commit) { - required_begin = bookkeeping_covered_start + ((i == card_table_element) ? 0 : card_table_element_layout[i]); - required_end = bookkeeping_covered_start + card_table_element_layout[i] + new_sizes[i]; + required_begin = bookkeeping_start + ((i == card_table_element) ? 0 : card_table_element_layout[i]); + required_end = bookkeeping_start + card_table_element_layout[i] + new_sizes[i]; commit_begin = align_lower_page(required_begin); } else { assert (additional_commit); - required_begin = bookkeeping_covered_start + card_table_element_layout[i] + bookkeeping_sizes[i]; + required_begin = bookkeeping_start + card_table_element_layout[i] + bookkeeping_sizes[i]; required_end = required_begin + new_sizes[i] - bookkeeping_sizes[i]; commit_begin = align_on_page(required_begin); } assert (required_begin <= required_end); commit_end = align_on_page(required_end); - commit_end = min (commit_end, align_lower_page(bookkeeping_covered_start + card_table_element_layout[i + 1])); + commit_end = min (commit_end, align_lower_page(bookkeeping_start + card_table_element_layout[i + 1])); commit_begin = min (commit_begin, commit_end); assert (commit_begin <= commit_end); @@ -8996,9 +9002,7 @@ uint32_t* gc_heap::make_card_table (uint8_t* start, uint8_t* end) size_t alloc_size = card_table_element_layout[total_bookkeeping_elements]; uint8_t* mem = (uint8_t*)GCToOSInterface::VirtualReserve (alloc_size, 0, virtual_reserve_flags); -#ifdef USE_REGIONS - bookkeeping_covered_start = mem; -#endif //USE_REGIONS + bookkeeping_start = mem; if (!mem) return 0; @@ -9495,6 +9499,8 @@ void gc_heap::copy_brick_card_table() uint32_t* ct = &g_gc_card_table[card_word (gcard_of (g_gc_lowest_address))]; own_card_table (ct); card_table = translate_card_table (ct); + bookkeeping_start = (uint8_t*)ct - sizeof(card_table_info); + card_table_size(ct) = card_table_element_layout[total_bookkeeping_elements]; /* End of global lock */ highest_address = card_table_highest_address (ct); lowest_address = card_table_lowest_address (ct); @@ -13728,8 +13734,6 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size, &g_gc_lowest_address, &g_gc_highest_address)) return E_OUTOFMEMORY; - bookkeeping_covered_start = global_region_allocator.get_start(); - if (!allocate_initial_regions(number_of_heaps)) return E_OUTOFMEMORY; } @@ -49291,13 +49295,20 @@ void PopulateDacVars(GcDacVars *gcDacVars) assert(gcDacVars != nullptr); *gcDacVars = {}; - // Note: these version numbers are not actually checked by SOS, so if you change - // the GC in a way that makes it incompatible with SOS, please change - // SOS_BREAKING_CHANGE_VERSION in both the runtime and the diagnostics repo - gcDacVars->major_version_number = 1; + // Note: These version numbers do not need to be checked in the .Net dac/SOS because + // we always match the compiled dac and GC to the version used. NativeAOT's SOS may + // work differently than .Net SOS. When making breaking changes here you may need to + // find NativeAOT's equivalent of SOS_BREAKING_CHANGE_VERSION and increment it. + gcDacVars->major_version_number = 2; gcDacVars->minor_version_number = 0; + gcDacVars->total_bookkeeping_elements = total_bookkeeping_elements; + gcDacVars->card_table_info_size = sizeof(card_table_info); + #ifdef USE_REGIONS gcDacVars->minor_version_number |= 1; + gcDacVars->count_free_region_kinds = count_free_region_kinds; + gcDacVars->global_regions_to_decommit = reinterpret_cast(&gc_heap::global_regions_to_decommit); + gcDacVars->global_free_huge_regions = reinterpret_cast(&gc_heap::global_free_huge_regions); #endif //USE_REGIONS #ifndef BACKGROUND_GC gcDacVars->minor_version_number |= 2; @@ -49315,10 +49326,15 @@ void PopulateDacVars(GcDacVars *gcDacVars) #endif //BACKGROUND_GC #ifndef MULTIPLE_HEAPS gcDacVars->ephemeral_heap_segment = reinterpret_cast(&gc_heap::ephemeral_heap_segment); +#ifdef USE_REGIONS + gcDacVars->free_regions = reinterpret_cast(&gc_heap::free_regions); +#endif #ifdef BACKGROUND_GC gcDacVars->mark_array = &gc_heap::mark_array; gcDacVars->background_saved_lowest_address = &gc_heap::background_saved_lowest_address; gcDacVars->background_saved_highest_address = &gc_heap::background_saved_highest_address; + gcDacVars->freeable_soh_segment = reinterpret_cast(&gc_heap::freeable_soh_segment); + gcDacVars->freeable_uoh_segment = reinterpret_cast(&gc_heap::freeable_uoh_segment); gcDacVars->next_sweep_obj = &gc_heap::next_sweep_obj; #ifdef USE_REGIONS gcDacVars->saved_sweep_ephemeral_seg = 0; @@ -49331,6 +49347,8 @@ void PopulateDacVars(GcDacVars *gcDacVars) gcDacVars->mark_array = 0; gcDacVars->background_saved_lowest_address = 0; gcDacVars->background_saved_highest_address = 0; + gcDacVars->freeable_soh_segment = 0; + gcDacVars->freeable_uoh_segment = 0; gcDacVars->next_sweep_obj = 0; gcDacVars->saved_sweep_ephemeral_seg = 0; gcDacVars->saved_sweep_ephemeral_start = 0; @@ -49357,4 +49375,5 @@ void PopulateDacVars(GcDacVars *gcDacVars) gcDacVars->gc_heap_field_offsets = reinterpret_cast(&gc_heap_field_offsets); #endif // MULTIPLE_HEAPS gcDacVars->generation_field_offsets = reinterpret_cast(&generation_field_offsets); + gcDacVars->bookkeeping_start = &gc_heap::bookkeeping_start; } diff --git a/src/coreclr/gc/gcinterface.dac.h b/src/coreclr/gc/gcinterface.dac.h index cfe968b74624b..3eb66a61a003a 100644 --- a/src/coreclr/gc/gcinterface.dac.h +++ b/src/coreclr/gc/gcinterface.dac.h @@ -16,16 +16,17 @@ #define MAX_EXPAND_MECHANISMS_COUNT 6 #define MAX_GC_MECHANISM_BITS_COUNT 2 #define MAX_GLOBAL_GC_MECHANISMS_COUNT 6 +#define FREE_REGION_KINDS 3 // The number of generations is hardcoded in to the dac APIS (DacpGcHeapDetails hard codes the size of its arrays) // The number of generations is hardcoded into some older dac APIS (for example DacpGcHeapDetails hard codes the size of its arrays) // This value cannot change and should not be used in new DAC APIs. New APIs can query GcDacVars.total_generation_count // variable which is dynamically initialized at runtime - #define NUMBERGENERATIONS 4 -#define INITIAL_HANDLE_TABLE_ARRAY_SIZE 10 -#define HANDLE_MAX_INTERNAL_TYPES 12 + + +#include "handletableconstants.h" // Analogue for the GC heap_segment class, containing information regarding a single // heap segment. @@ -42,6 +43,17 @@ class dac_heap_segment { class dac_gc_heap* heap; }; +class dac_region_free_list { +public: + size_t num_free_regions; + size_t size_free_regions; + size_t size_committed_in_free_regions; + size_t num_free_regions_added; + size_t num_free_regions_removed; + DPTR(dac_heap_segment) head_free_region; + DPTR(dac_heap_segment) tail_free_region; +}; + // Analogue for the GC generation class, containing information about the start segment // of a generation and its allocation context. class dac_generation { @@ -49,12 +61,14 @@ class dac_generation { #define ALL_FIELDS #define DEFINE_FIELD(field_name, field_type) field_type field_name; #define DEFINE_DPTR_FIELD(field_name, field_type) DPTR(field_type) field_name; +#define DEFINE_MISSING_FIELD(field_name) #include "dac_generation_fields.h" #undef DEFINE_DPTR_FIELD #undef DEFINE_FIELD #undef ALL_FIELDS +#undef DEFINE_MISSING_FIELD }; // Analogue for the GC CFinalize class, containing information about the finalize queue. @@ -64,6 +78,21 @@ class dac_finalize_queue { uint8_t** m_FillPointers[NUMBERGENERATIONS + ExtraSegCount]; }; +class dac_handle_table_segment { +public: + uint8_t rgGeneration[HANDLE_BLOCKS_PER_SEGMENT * sizeof(uint32_t) / sizeof(uint8_t)]; + uint8_t rgAllocation[HANDLE_BLOCKS_PER_SEGMENT]; + uint32_t rgFreeMask[HANDLE_MASKS_PER_SEGMENT]; + uint8_t rgBlockType[HANDLE_BLOCKS_PER_SEGMENT]; + uint8_t rgUserData[HANDLE_BLOCKS_PER_SEGMENT]; + uint8_t rgLocks[HANDLE_BLOCKS_PER_SEGMENT]; + uint8_t rgTail[HANDLE_MAX_INTERNAL_TYPES]; + uint8_t rgHint[HANDLE_MAX_INTERNAL_TYPES]; + uint32_t rgFreeCount[HANDLE_MAX_INTERNAL_TYPES]; + DPTR(dac_handle_table_segment) pNextSegment; + }; + + class dac_handle_table { public: // We do try to keep everything that the DAC knows about as close to the @@ -71,6 +100,7 @@ class dac_handle_table { // HandleTable has rgTypeFlags at offset 0 for performance reasons and // we don't want to disrupt that. uint32_t padding[HANDLE_MAX_INTERNAL_TYPES]; + DPTR(dac_handle_table_segment) pSegmentList; }; class dac_handle_table_bucket { @@ -86,6 +116,13 @@ class dac_handle_table_map { uint32_t dwMaxIndex; }; +class dac_card_table_info { +public: + unsigned recount; + size_t size; + TADDR next_card_table; +}; + // Possible values of the current_c_gc_state dacvar, indicating the state of // a background GC. enum c_gc_state @@ -111,7 +148,7 @@ enum oom_reason /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ /* If you modify failure_get_memory and */ /* oom_reason be sure to make the corresponding */ -/* changes in tools\sos\strike\strike.cpp. */ +/* changes in ClrMD. */ /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ enum failure_get_memory { @@ -168,7 +205,7 @@ class dac_gc_heap { dac_generation generation_table[1]; }; -#define GENERATION_TABLE_FIELD_INDEX 18 +#define GENERATION_TABLE_FIELD_INDEX 21 // Unlike other DACized structures, these types are loaded manually in the debugger. // To avoid misuse, pointers to them are explicitly casted to these unused type. @@ -209,6 +246,9 @@ struct GcDacVars { uint8_t minor_version_number; size_t generation_size; size_t total_generation_count; + int total_bookkeeping_elements; + int count_free_region_kinds; + size_t card_table_info_size; #ifdef DACCESS_COMPILE #define GC_DAC_VAR(type, name) DPTR(type) name; #define GC_DAC_PTR_VAR(type, name) DPTR(type*) name; diff --git a/src/coreclr/gc/gcinterface.dacvars.def b/src/coreclr/gc/gcinterface.dacvars.def index a78852a09a220..f9e0eb4be7e3b 100644 --- a/src/coreclr/gc/gcinterface.dacvars.def +++ b/src/coreclr/gc/gcinterface.dacvars.def @@ -42,6 +42,8 @@ GC_DAC_PTR_VAR (uint32_t, mark_array) GC_DAC_VAR (c_gc_state, current_c_gc_state) GC_DAC_PTR_VAR (dac_heap_segment, ephemeral_heap_segment) GC_DAC_PTR_VAR (dac_heap_segment, saved_sweep_ephemeral_seg) +GC_DAC_PTR_VAR (dac_heap_segment, freeable_soh_segment) +GC_DAC_PTR_VAR (dac_heap_segment, freeable_uoh_segment) GC_DAC_PTR_VAR (uint8_t, saved_sweep_ephemeral_start) GC_DAC_PTR_VAR (uint8_t, background_saved_lowest_address) GC_DAC_PTR_VAR (uint8_t, background_saved_highest_address) @@ -62,6 +64,10 @@ GC_DAC_ARRAY_VAR (size_t, interesting_mechanism_bits_per_heap) GC_DAC_VAR (dac_handle_table_map, handle_table_map) GC_DAC_ARRAY_VAR (int, gc_heap_field_offsets) GC_DAC_ARRAY_VAR (int, generation_field_offsets) +GC_DAC_PTR_VAR (uint8_t, bookkeeping_start) +GC_DAC_ARRAY_VAR (dac_region_free_list, global_regions_to_decommit) +GC_DAC_PTR_VAR (dac_region_free_list, global_free_huge_regions) +GC_DAC_ARRAY_VAR (dac_region_free_list, free_regions) #undef GC_DAC_VAR #undef GC_DAC_ARRAY_VAR diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h index 3ca72125148d2..d72c9495dd8ea 100644 --- a/src/coreclr/gc/gcpriv.h +++ b/src/coreclr/gc/gcpriv.h @@ -1343,6 +1343,8 @@ enum free_region_kind count_free_region_kinds, }; +static_assert(count_free_region_kinds == FREE_REGION_KINDS, "Keep count_free_region_kinds in sync with FREE_REGION_KINDS, changing this is not a version breaking change."); + class region_free_list { size_t num_free_regions; @@ -1379,6 +1381,8 @@ class region_free_list void sort_by_committed_and_age(); static bool is_on_free_list (heap_segment* region, region_free_list free_list[count_free_region_kinds]); }; + +static_assert(sizeof(region_free_list) == sizeof(dac_region_free_list), "The DAC relies on the size of these two types matching for pointer arithmetic."); #endif enum bookkeeping_element @@ -4192,10 +4196,10 @@ class gc_heap #endif //BGC_SERVO_TUNING #endif //BACKGROUND_GC + PER_HEAP_ISOLATED_FIELD_INIT_ONLY uint8_t* bookkeeping_start; #ifdef USE_REGIONS PER_HEAP_ISOLATED_FIELD_INIT_ONLY size_t regions_range; PER_HEAP_ISOLATED_FIELD_INIT_ONLY bool enable_special_regions_p; - PER_HEAP_ISOLATED_FIELD_INIT_ONLY uint8_t* bookkeeping_covered_start; #else //USE_REGIONS PER_HEAP_ISOLATED_FIELD_INIT_ONLY size_t eph_gen_starts_size; PER_HEAP_ISOLATED_FIELD_INIT_ONLY size_t min_segment_size; diff --git a/src/coreclr/gc/handletableconstants.h b/src/coreclr/gc/handletableconstants.h new file mode 100644 index 0000000000000..0d6e678f2aebc --- /dev/null +++ b/src/coreclr/gc/handletableconstants.h @@ -0,0 +1,117 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +#ifndef __HANDLETABLECONSTANTS_H__ +#define __HANDLETABLECONSTANTS_H__ + + // Build support for async pinned handles into standalone GC to make it usable with older runtimes +#if defined(BUILD_AS_STANDALONE) && !defined(FEATURE_NATIVEAOT) +#define FEATURE_ASYNC_PINNED_HANDLES +#endif + +#define INITIAL_HANDLE_TABLE_ARRAY_SIZE 10 +#define HANDLE_MAX_INTERNAL_TYPES 12 + +/*--------------------------------------------------------------------------*/ + +//@TODO: find a home for this in a project-level header file +#ifndef BITS_PER_BYTE +#define BITS_PER_BYTE (8) +#endif +/*--------------------------------------------------------------------------*/ + + + +/**************************************************************************** + * + * MAJOR TABLE DEFINITIONS THAT CHANGE DEPENDING ON THE WEATHER + * + ****************************************************************************/ + +// 64k reserved per segment with 4k as header. +#define HANDLE_SEGMENT_SIZE (0x10000) // MUST be a power of 2 (and currently must be 64K due to VirtualAlloc semantics) +#define HANDLE_HEADER_SIZE (0x1000) // SHOULD be <= OS page size + +#define HANDLE_SEGMENT_ALIGNMENT HANDLE_SEGMENT_SIZE + + +#if !BIGENDIAN + + // little-endian write barrier mask manipulation + #define GEN_CLUMP_0_MASK (0x000000FF) + #define NEXT_CLUMP_IN_MASK(dw) ((dw) >> BITS_PER_BYTE) + +#else + + // big-endian write barrier mask manipulation + #define GEN_CLUMP_0_MASK (0xFF000000) + #define NEXT_CLUMP_IN_MASK(dw) ((dw) << BITS_PER_BYTE) + +#endif + + +// if the above numbers change than these will likely change as well +#define HANDLE_HANDLES_PER_CLUMP (16) // segment write-barrier granularity +#define HANDLE_HANDLES_PER_BLOCK (64) // segment suballocation granularity +#define HANDLE_OPTIMIZE_FOR_64_HANDLE_BLOCKS // flag for certain optimizations + +// number of types allowed for public callers +#define HANDLE_MAX_PUBLIC_TYPES (HANDLE_MAX_INTERNAL_TYPES - 1) // reserve one internal type + +// internal block types +#define HNDTYPE_INTERNAL_DATABLOCK (HANDLE_MAX_INTERNAL_TYPES - 1) // reserve last type for data blocks + +// max number of generations to support statistics on +#define MAXSTATGEN (5) + +/*--------------------------------------------------------------------------*/ + + + +/**************************************************************************** + * + * MORE DEFINITIONS + * + ****************************************************************************/ + +// fast handle-to-segment mapping +#define HANDLE_SEGMENT_CONTENT_MASK (HANDLE_SEGMENT_SIZE - 1) +#define HANDLE_SEGMENT_ALIGN_MASK (~HANDLE_SEGMENT_CONTENT_MASK) + +// table layout metrics +#define HANDLE_SIZE sizeof(_UNCHECKED_OBJECTREF) +#define HANDLE_HANDLES_PER_SEGMENT ((HANDLE_SEGMENT_SIZE - HANDLE_HEADER_SIZE) / HANDLE_SIZE) +#define HANDLE_BLOCKS_PER_SEGMENT (HANDLE_HANDLES_PER_SEGMENT / HANDLE_HANDLES_PER_BLOCK) +#define HANDLE_CLUMPS_PER_SEGMENT (HANDLE_HANDLES_PER_SEGMENT / HANDLE_HANDLES_PER_CLUMP) +#define HANDLE_CLUMPS_PER_BLOCK (HANDLE_HANDLES_PER_BLOCK / HANDLE_HANDLES_PER_CLUMP) +#define HANDLE_BYTES_PER_BLOCK (HANDLE_HANDLES_PER_BLOCK * HANDLE_SIZE) +#define HANDLE_HANDLES_PER_MASK (sizeof(uint32_t) * BITS_PER_BYTE) +#define HANDLE_MASKS_PER_SEGMENT (HANDLE_HANDLES_PER_SEGMENT / HANDLE_HANDLES_PER_MASK) +#define HANDLE_MASKS_PER_BLOCK (HANDLE_HANDLES_PER_BLOCK / HANDLE_HANDLES_PER_MASK) +#define HANDLE_CLUMPS_PER_MASK (HANDLE_HANDLES_PER_MASK / HANDLE_HANDLES_PER_CLUMP) + +// We use this relation to check for free mask per block. +C_ASSERT (HANDLE_HANDLES_PER_MASK * 2 == HANDLE_HANDLES_PER_BLOCK); + + +// cache layout metrics +#define HANDLE_CACHE_TYPE_SIZE 128 // 128 == 63 handles per bank +#define HANDLES_PER_CACHE_BANK ((HANDLE_CACHE_TYPE_SIZE / 2) - 1) + +// cache policy defines +#define REBALANCE_TOLERANCE (HANDLES_PER_CACHE_BANK / 3) +#define REBALANCE_LOWATER_MARK (HANDLES_PER_CACHE_BANK - REBALANCE_TOLERANCE) +#define REBALANCE_HIWATER_MARK (HANDLES_PER_CACHE_BANK + REBALANCE_TOLERANCE) + +// bulk alloc policy defines +#define SMALL_ALLOC_COUNT (HANDLES_PER_CACHE_BANK / 10) + +// misc constants +#define MASK_FULL (0) +#define MASK_EMPTY (0xFFFFFFFF) +#define MASK_LOBYTE (0x000000FF) +#define TYPE_INVALID ((uint8_t)0xFF) +#define BLOCK_INVALID ((uint8_t)0xFF) + +/*--------------------------------------------------------------------------*/ + +#endif // __HANDLETABLECONSTANTS_H__ diff --git a/src/coreclr/gc/handletablepriv.h b/src/coreclr/gc/handletablepriv.h index 4c05538996343..086ef2e018b6f 100644 --- a/src/coreclr/gc/handletablepriv.h +++ b/src/coreclr/gc/handletablepriv.h @@ -14,113 +14,7 @@ #include "handletable.h" - - // Build support for async pinned handles into standalone GC to make it usable with older runtimes -#if defined(BUILD_AS_STANDALONE) && !defined(FEATURE_NATIVEAOT) -#define FEATURE_ASYNC_PINNED_HANDLES -#endif - - -/*--------------------------------------------------------------------------*/ - -//@TODO: find a home for this in a project-level header file -#define BITS_PER_BYTE (8) -/*--------------------------------------------------------------------------*/ - - - -/**************************************************************************** - * - * MAJOR TABLE DEFINITIONS THAT CHANGE DEPENDING ON THE WEATHER - * - ****************************************************************************/ - -// 64k reserved per segment with 4k as header. -#define HANDLE_SEGMENT_SIZE (0x10000) // MUST be a power of 2 (and currently must be 64K due to VirtualAlloc semantics) -#define HANDLE_HEADER_SIZE (0x1000) // SHOULD be <= OS page size - -#define HANDLE_SEGMENT_ALIGNMENT HANDLE_SEGMENT_SIZE - - -#if !BIGENDIAN - - // little-endian write barrier mask manipulation - #define GEN_CLUMP_0_MASK (0x000000FF) - #define NEXT_CLUMP_IN_MASK(dw) ((dw) >> BITS_PER_BYTE) - -#else - - // big-endian write barrier mask manipulation - #define GEN_CLUMP_0_MASK (0xFF000000) - #define NEXT_CLUMP_IN_MASK(dw) ((dw) << BITS_PER_BYTE) - -#endif - - -// if the above numbers change than these will likely change as well -#define HANDLE_HANDLES_PER_CLUMP (16) // segment write-barrier granularity -#define HANDLE_HANDLES_PER_BLOCK (64) // segment suballocation granularity -#define HANDLE_OPTIMIZE_FOR_64_HANDLE_BLOCKS // flag for certain optimizations - -// number of types allowed for public callers -#define HANDLE_MAX_PUBLIC_TYPES (HANDLE_MAX_INTERNAL_TYPES - 1) // reserve one internal type - -// internal block types -#define HNDTYPE_INTERNAL_DATABLOCK (HANDLE_MAX_INTERNAL_TYPES - 1) // reserve last type for data blocks - -// max number of generations to support statistics on -#define MAXSTATGEN (5) - -/*--------------------------------------------------------------------------*/ - - - -/**************************************************************************** - * - * MORE DEFINITIONS - * - ****************************************************************************/ - -// fast handle-to-segment mapping -#define HANDLE_SEGMENT_CONTENT_MASK (HANDLE_SEGMENT_SIZE - 1) -#define HANDLE_SEGMENT_ALIGN_MASK (~HANDLE_SEGMENT_CONTENT_MASK) - -// table layout metrics -#define HANDLE_SIZE sizeof(_UNCHECKED_OBJECTREF) -#define HANDLE_HANDLES_PER_SEGMENT ((HANDLE_SEGMENT_SIZE - HANDLE_HEADER_SIZE) / HANDLE_SIZE) -#define HANDLE_BLOCKS_PER_SEGMENT (HANDLE_HANDLES_PER_SEGMENT / HANDLE_HANDLES_PER_BLOCK) -#define HANDLE_CLUMPS_PER_SEGMENT (HANDLE_HANDLES_PER_SEGMENT / HANDLE_HANDLES_PER_CLUMP) -#define HANDLE_CLUMPS_PER_BLOCK (HANDLE_HANDLES_PER_BLOCK / HANDLE_HANDLES_PER_CLUMP) -#define HANDLE_BYTES_PER_BLOCK (HANDLE_HANDLES_PER_BLOCK * HANDLE_SIZE) -#define HANDLE_HANDLES_PER_MASK (sizeof(uint32_t) * BITS_PER_BYTE) -#define HANDLE_MASKS_PER_SEGMENT (HANDLE_HANDLES_PER_SEGMENT / HANDLE_HANDLES_PER_MASK) -#define HANDLE_MASKS_PER_BLOCK (HANDLE_HANDLES_PER_BLOCK / HANDLE_HANDLES_PER_MASK) -#define HANDLE_CLUMPS_PER_MASK (HANDLE_HANDLES_PER_MASK / HANDLE_HANDLES_PER_CLUMP) - -// We use this relation to check for free mask per block. -C_ASSERT (HANDLE_HANDLES_PER_MASK * 2 == HANDLE_HANDLES_PER_BLOCK); - - -// cache layout metrics -#define HANDLE_CACHE_TYPE_SIZE 128 // 128 == 63 handles per bank -#define HANDLES_PER_CACHE_BANK ((HANDLE_CACHE_TYPE_SIZE / 2) - 1) - -// cache policy defines -#define REBALANCE_TOLERANCE (HANDLES_PER_CACHE_BANK / 3) -#define REBALANCE_LOWATER_MARK (HANDLES_PER_CACHE_BANK - REBALANCE_TOLERANCE) -#define REBALANCE_HIWATER_MARK (HANDLES_PER_CACHE_BANK + REBALANCE_TOLERANCE) - -// bulk alloc policy defines -#define SMALL_ALLOC_COUNT (HANDLES_PER_CACHE_BANK / 10) - -// misc constants -#define MASK_FULL (0) -#define MASK_EMPTY (0xFFFFFFFF) -#define MASK_LOBYTE (0x000000FF) -#define TYPE_INVALID ((uint8_t)0xFF) -#define BLOCK_INVALID ((uint8_t)0xFF) - -/*--------------------------------------------------------------------------*/ +#include "handletableconstants.h" @@ -483,6 +377,11 @@ struct HandleTable */ uint32_t rgTypeFlags[HANDLE_MAX_INTERNAL_TYPES]; + /* + * head of segment list for this table + */ + PTR_TableSegment pSegmentList; + /* * lock for this table */ @@ -499,11 +398,6 @@ struct HandleTable */ uint32_t dwCount; - /* - * head of segment list for this table - */ - PTR_TableSegment pSegmentList; - /* * information on current async scan (if any) */ diff --git a/src/coreclr/gc/objecthandle.cpp b/src/coreclr/gc/objecthandle.cpp index 52b25b88adf51..43e09789bab81 100644 --- a/src/coreclr/gc/objecthandle.cpp +++ b/src/coreclr/gc/objecthandle.cpp @@ -1811,6 +1811,8 @@ void PopulateHandleTableDacVars(GcDacVars* gcDacVars) static_assert(offsetof(HandleTableMap, dwMaxIndex) == offsetof(dac_handle_table_map, dwMaxIndex), "handle table map DAC layout mismatch"); static_assert(offsetof(HandleTableBucket, pTable) == offsetof(dac_handle_table_bucket, pTable), "handle table bucket DAC layout mismatch"); static_assert(offsetof(HandleTableBucket, HandleTableIndex) == offsetof(dac_handle_table_bucket, HandleTableIndex), "handle table bucket DAC layout mismatch"); + static_assert(offsetof(HandleTable, pSegmentList) == offsetof(dac_handle_table, pSegmentList), "handle table bucket DAC layout mismatch"); + static_assert(offsetof(_TableSegmentHeader, pNextSegment) == offsetof(dac_handle_table_segment, pNextSegment), "handle table bucket DAC layout mismatch"); #ifndef DACCESS_COMPILE gcDacVars->handle_table_map = reinterpret_cast(&g_HandleTableMap); diff --git a/src/coreclr/inc/sospriv.idl b/src/coreclr/inc/sospriv.idl index b1a3b18e06b8b..ac7b93a9a7bc1 100644 --- a/src/coreclr/inc/sospriv.idl +++ b/src/coreclr/inc/sospriv.idl @@ -49,6 +49,7 @@ cpp_quote("#endif") cpp_quote("typedef enum { TYPEDEFTOMETHODTABLE, TYPEREFTOMETHODTABLE } ModuleMapType;") cpp_quote("typedef enum {IndcellHeap, LookupHeap, ResolveHeap, DispatchHeap, CacheEntryHeap, VtableHeap} VCSHeapType;") cpp_quote("typedef enum {LoaderHeapKindNormal = 0, LoaderHeapKindExplicitControl = 1} LoaderHeapKind;") +cpp_quote("typedef enum {FreeUnknownRegion = 0, FreeGlobalHugeRegion = 1, FreeGlobalRegion = 2, FreeRegion = 3, FreeSohSegment = 4, FreeUohSegment = 5 } FreeRegionKind;") typedef void (*MODULEMAPTRAVERSE)(UINT index, CLRDATA_ADDRESS methodTable,LPVOID token); typedef void (*VISITHEAP)(CLRDATA_ADDRESS blockData,size_t blockSize,BOOL blockIsCurrentBlock); @@ -172,6 +173,32 @@ interface ISOSStackRefEnum : ISOSEnum } +cpp_quote("#ifndef _SOS_MemoryRegion_") +cpp_quote("#define _SOS_MemoryRegion_") + +typedef struct _SOSMemoryRegion +{ + CLRDATA_ADDRESS Start; + CLRDATA_ADDRESS Size; + CLRDATA_ADDRESS ExtraData; + int Heap; +} SOSMemoryRegion; + +cpp_quote("#endif // _SOS_MemoryRegion_") + +[ + object, + local, + uuid(E4B860EC-337A-40C0-A591-F09A9680690F) +] +interface ISOSMemoryEnum : ISOSEnum +{ + HRESULT Next([in] unsigned int count, + [out, size_is(count), length_is(*pNeeded)] SOSMemoryRegion memRegion[], + [out] unsigned int *pNeeded); +} + + [ object, local, @@ -465,7 +492,7 @@ interface ISOSDacInterface12 : IUnknown [ object, local, - uuid(3176a8ed-597b-4f54-a71f-83695c6a8c5d) + uuid(3176a8ed-597b-4f54-a71f-83695c6a8c5e) ] interface ISOSDacInterface13 : IUnknown { @@ -473,4 +500,8 @@ interface ISOSDacInterface13 : IUnknown HRESULT GetDomainLoaderAllocator(CLRDATA_ADDRESS domainAddress, CLRDATA_ADDRESS *pLoaderAllocator); HRESULT GetLoaderAllocatorHeapNames(int count, const char **ppNames, int *pNeeded); HRESULT GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocator, int count, CLRDATA_ADDRESS *pLoaderHeaps, LoaderHeapKind *pKinds, int *pNeeded); + HRESULT GetHandleTableMemoryRegions(ISOSMemoryEnum **ppEnum); + HRESULT GetGCBookkeepingMemoryRegions(ISOSMemoryEnum **ppEnum); + HRESULT GetGCFreeRegions(ISOSMemoryEnum **ppEnum); + HRESULT LockedFlush(); } diff --git a/src/coreclr/pal/prebuilt/idl/sospriv_i.cpp b/src/coreclr/pal/prebuilt/idl/sospriv_i.cpp index 07f02d061e86c..141ec62612e48 100644 --- a/src/coreclr/pal/prebuilt/idl/sospriv_i.cpp +++ b/src/coreclr/pal/prebuilt/idl/sospriv_i.cpp @@ -5,9 +5,11 @@ /* link this file in with the server and any clients */ - /* File created by MIDL compiler version 8.01.0626 */ + /* File created by MIDL compiler version 8.01.0622 */ +/* at Mon Jan 18 19:14:07 2038 + */ /* Compiler settings for sospriv.idl: - Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.01.0626 + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.01.0622 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: @@ -77,6 +79,9 @@ MIDL_DEFINE_GUID(IID, IID_ISOSStackRefErrorEnum,0x774F4E1B,0xFB7B,0x491B,0x97,0x MIDL_DEFINE_GUID(IID, IID_ISOSStackRefEnum,0x8FA642BD,0x9F10,0x4799,0x9A,0xA3,0x51,0x2A,0xE7,0x8C,0x77,0xEE); +MIDL_DEFINE_GUID(IID, IID_ISOSMemoryEnum,0xE4B860EC,0x337A,0x40C0,0xA5,0x91,0xF0,0x9A,0x96,0x80,0x69,0x0F); + + MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface,0x436f00f2,0xb42a,0x4b9f,0x87,0x0c,0xe7,0x3d,0xb6,0x6a,0xe9,0x30); @@ -113,7 +118,7 @@ MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface11,0x96BA1DB9,0x14CD,0x4492,0x80,0x65, MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface12,0x1b93bacc,0x8ca4,0x432d,0x94,0x3a,0x3e,0x6e,0x7e,0xc0,0xb0,0xa3); -MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface13,0x3176a8ed,0x597b,0x4f54,0xa7,0x1f,0x83,0x69,0x5c,0x6a,0x8c,0x5d); +MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface13,0x3176a8ed,0x597b,0x4f54,0xa7,0x1f,0x83,0x69,0x5c,0x6a,0x8c,0x5e); #undef MIDL_DEFINE_GUID diff --git a/src/coreclr/pal/prebuilt/inc/sospriv.h b/src/coreclr/pal/prebuilt/inc/sospriv.h index cc34480996560..e6f2b7b4f049e 100644 --- a/src/coreclr/pal/prebuilt/inc/sospriv.h +++ b/src/coreclr/pal/prebuilt/inc/sospriv.h @@ -73,6 +73,13 @@ typedef interface ISOSStackRefEnum ISOSStackRefEnum; #endif /* __ISOSStackRefEnum_FWD_DEFINED__ */ +#ifndef __ISOSMemoryEnum_FWD_DEFINED__ +#define __ISOSMemoryEnum_FWD_DEFINED__ +typedef interface ISOSMemoryEnum ISOSMemoryEnum; + +#endif /* __ISOSMemoryEnum_FWD_DEFINED__ */ + + #ifndef __ISOSDacInterface_FWD_DEFINED__ #define __ISOSDacInterface_FWD_DEFINED__ typedef interface ISOSDacInterface ISOSDacInterface; @@ -198,6 +205,7 @@ typedef int VCSHeapType; typedef enum { TYPEDEFTOMETHODTABLE, TYPEREFTOMETHODTABLE } ModuleMapType; typedef enum {IndcellHeap, LookupHeap, ResolveHeap, DispatchHeap, CacheEntryHeap, VtableHeap} VCSHeapType; typedef enum {LoaderHeapKindNormal = 0, LoaderHeapKindExplicitControl = 1} LoaderHeapKind; +typedef enum {FreeUnknownRegion = 0, FreeGlobalHugeRegion = 1, FreeGlobalRegion = 2, FreeRegion = 3, FreeSohSegment = 4, FreeUohSegment = 5 } FreeRegionKind; typedef void ( *MODULEMAPTRAVERSE )( UINT index, CLRDATA_ADDRESS methodTable, @@ -489,6 +497,17 @@ typedef struct _SOS_StackRefError extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0002_v0_0_c_ifspec; extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0002_v0_0_s_ifspec; +#ifndef _SOS_MemoryRegion_ +#define _SOS_MemoryRegion_ +typedef struct _SOSMemoryRegion + { + CLRDATA_ADDRESS Start; + CLRDATA_ADDRESS Size; + CLRDATA_ADDRESS ExtraData; + int Heap; + } SOSMemoryRegion; +#endif // _SOS_MemoryRegion_ + #ifndef __ISOSStackRefErrorEnum_INTERFACE_DEFINED__ #define __ISOSStackRefErrorEnum_INTERFACE_DEFINED__ @@ -594,6 +613,112 @@ EXTERN_C const IID IID_ISOSStackRefErrorEnum; #endif /* __ISOSStackRefErrorEnum_INTERFACE_DEFINED__ */ + +#ifndef __ISOSMemoryEnum_INTERFACE_DEFINED__ +#define __ISOSMemoryEnum_INTERFACE_DEFINED__ + +/* interface ISOSMemoryEnum */ +/* [uuid][local][object] */ + + +EXTERN_C const IID IID_ISOSMemoryEnum; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("E4B860EC-337A-40C0-A591-F09A9680690F") + ISOSMemoryEnum : public ISOSEnum + { + public: + virtual HRESULT STDMETHODCALLTYPE Next( + /* [in] */ unsigned int count, + /* [length_is][size_is][out] */ SOSMemoryRegion memRegion[ ], + /* [out] */ unsigned int *pNeeded) = 0; + + }; + + +#else /* C style interface */ + + typedef struct ISOSMemoryEnumVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISOSMemoryEnum * This, + /* [in] */ REFIID riid, + /* [annotation][iid_is][out] */ + _COM_Outptr_ void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISOSMemoryEnum * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISOSMemoryEnum * This); + + HRESULT ( STDMETHODCALLTYPE *Skip )( + ISOSMemoryEnum * This, + /* [in] */ unsigned int count); + + HRESULT ( STDMETHODCALLTYPE *Reset )( + ISOSMemoryEnum * This); + + HRESULT ( STDMETHODCALLTYPE *GetCount )( + ISOSMemoryEnum * This, + /* [out] */ unsigned int *pCount); + + HRESULT ( STDMETHODCALLTYPE *Next )( + ISOSMemoryEnum * This, + /* [in] */ unsigned int count, + /* [length_is][size_is][out] */ SOSMemoryRegion memRegion[ ], + /* [out] */ unsigned int *pNeeded); + + END_INTERFACE + } ISOSMemoryEnumVtbl; + + interface ISOSMemoryEnum + { + CONST_VTBL struct ISOSMemoryEnumVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISOSMemoryEnum_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISOSMemoryEnum_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISOSMemoryEnum_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISOSMemoryEnum_Skip(This,count) \ + ( (This)->lpVtbl -> Skip(This,count) ) + +#define ISOSMemoryEnum_Reset(This) \ + ( (This)->lpVtbl -> Reset(This) ) + +#define ISOSMemoryEnum_GetCount(This,pCount) \ + ( (This)->lpVtbl -> GetCount(This,pCount) ) + + +#define ISOSMemoryEnum_Next(This,count,memRegion,pNeeded) \ + ( (This)->lpVtbl -> Next(This,count,memRegion,pNeeded) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISOSMemoryEnum_INTERFACE_DEFINED__ */ + + #ifndef __ISOSStackRefEnum_INTERFACE_DEFINED__ #define __ISOSStackRefEnum_INTERFACE_DEFINED__ @@ -3084,7 +3209,7 @@ EXTERN_C const IID IID_ISOSDacInterface13; #if defined(__cplusplus) && !defined(CINTERFACE) - MIDL_INTERFACE("3176a8ed-597b-4f54-a71f-83695c6a8c5d") + MIDL_INTERFACE("3176a8ed-597b-4f54-a71f-83695c6a8c5e") ISOSDacInterface13 : public IUnknown { public: @@ -3108,37 +3233,79 @@ EXTERN_C const IID IID_ISOSDacInterface13; CLRDATA_ADDRESS *pLoaderHeaps, LoaderHeapKind *pKinds, int *pNeeded) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetHandleTableMemoryRegions( + ISOSMemoryEnum **ppEnum) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetGCBookkeepingMemoryRegions( + ISOSMemoryEnum **ppEnum) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetGCFreeRegions( + ISOSMemoryEnum **ppEnum) = 0; + + virtual HRESULT STDMETHODCALLTYPE LockedFlush( void) = 0; }; #else /* C style interface */ + typedef struct ISOSDacInterface13Vtbl { BEGIN_INTERFACE - DECLSPEC_XFGVIRT(IUnknown, QueryInterface) HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ISOSDacInterface13 * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ _COM_Outptr_ void **ppvObject); - DECLSPEC_XFGVIRT(IUnknown, AddRef) ULONG ( STDMETHODCALLTYPE *AddRef )( ISOSDacInterface13 * This); - DECLSPEC_XFGVIRT(IUnknown, Release) ULONG ( STDMETHODCALLTYPE *Release )( ISOSDacInterface13 * This); - DECLSPEC_XFGVIRT(ISOSDacInterface13, TraverseLoaderHeap) HRESULT ( STDMETHODCALLTYPE *TraverseLoaderHeap )( ISOSDacInterface13 * This, CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback); + HRESULT ( STDMETHODCALLTYPE *GetDomainLoaderAllocator )( + ISOSDacInterface13 * This, + CLRDATA_ADDRESS domainAddress, + CLRDATA_ADDRESS *pLoaderAllocator); + + HRESULT ( STDMETHODCALLTYPE *GetLoaderAllocatorHeapNames )( + ISOSDacInterface13 * This, + int count, + const unsigned char **ppNames, + int *pNeeded); + + HRESULT ( STDMETHODCALLTYPE *GetLoaderAllocatorHeaps )( + ISOSDacInterface13 * This, + CLRDATA_ADDRESS loaderAllocator, + int count, + CLRDATA_ADDRESS *pLoaderHeaps, + LoaderHeapKind *pKinds, + int *pNeeded); + + HRESULT ( STDMETHODCALLTYPE *GetHandleTableMemoryRegions )( + ISOSDacInterface13 * This, + ISOSMemoryEnum **ppEnum); + + HRESULT ( STDMETHODCALLTYPE *GetGCBookkeepingMemoryRegions )( + ISOSDacInterface13 * This, + ISOSMemoryEnum **ppEnum); + + HRESULT ( STDMETHODCALLTYPE *GetGCFreeRegions )( + ISOSDacInterface13 * This, + ISOSMemoryEnum **ppEnum); + + HRESULT ( STDMETHODCALLTYPE *LockedFlush )( + ISOSDacInterface13 * This); + END_INTERFACE } ISOSDacInterface13Vtbl; diff --git a/src/coreclr/vm/decodemd.cpp b/src/coreclr/vm/decodemd.cpp index 6def9757c9b26..e1f7e8e3877a7 100644 --- a/src/coreclr/vm/decodemd.cpp +++ b/src/coreclr/vm/decodemd.cpp @@ -73,7 +73,6 @@ const BYTE decoded_10[2] = {10, END_DECODED }; #define DECODING_ERROR ((unsigned) -1) #define MASK(len) (~(~0u <<(len))) #define MASK64(len) ((~((~((unsigned __int64)0))<<(len)))) -#define BITS_PER_BYTE (sizeof(BYTE)*8) const Decoder::Decode emptyDecode = {decoded_end, DECODING_HEADER(0)}; From 07834fdf017a7629dee7d6773c4bf00112c0f86f Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 17 Apr 2023 15:28:40 -0700 Subject: [PATCH 28/32] Deduplicate Binary Integer parsing logic (#84582) * Deduplicate TryNumberToInt* * Deduplicate TryParseInt*IntegerStyle parsing methods * Deduplicate TryParseInt*HexNumberStyle * Deduplicate TryParseInt*Number * Deduplicate TryParseInt* * Deduplicate ParseInt* * Deduplicate some more binary integer parsing logic * Ensure the right overflow message is used for binary integer parsing * Ensure HasTrailingCharsZero handling is in the right spot * Resolving PR feedback * Revert using the public throw helpers --- .../System.Private.CoreLib/src/System/Byte.cs | 99 +- .../System.Private.CoreLib/src/System/Char.cs | 85 +- .../System.Private.CoreLib/src/System/Enum.cs | 149 +- .../System/Globalization/NumberFormatInfo.cs | 1 + .../System.Private.CoreLib/src/System/Guid.cs | 2 +- .../src/System/Int128.cs | 78 +- .../src/System/Int16.cs | 103 +- .../src/System/Int32.cs | 86 +- .../src/System/Int64.cs | 76 +- .../src/System/Number.Parsing.cs | 1955 +++-------------- .../src/System/SByte.cs | 107 +- .../src/System/ThrowHelper.cs | 6 + .../src/System/UInt128.cs | 78 +- .../src/System/UInt16.cs | 96 +- .../src/System/UInt32.cs | 72 +- .../src/System/UInt64.cs | 72 +- 16 files changed, 696 insertions(+), 2369 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs index e90fb025a1b67..6716614028f66 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs @@ -23,7 +23,8 @@ public readonly struct Byte IMinMaxValue, IUnsignedNumber, IUtf8SpanFormattable, - IUtfChar + IUtfChar, + IBinaryIntegerParseAndFormatInfo { private readonly byte m_value; // Do not rename (binary serialization) @@ -92,98 +93,44 @@ public override int GetHashCode() return m_value; } - public static byte Parse(string s) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); - } + public static byte Parse(string s) => Parse(s, NumberStyles.Integer, provider: null); - public static byte Parse(string s, NumberStyles style) - { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, style, NumberFormatInfo.CurrentInfo); - } + public static byte Parse(string s, NumberStyles style) => Parse(s, style, provider: null); - public static byte Parse(string s, IFormatProvider? provider) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); - } + public static byte Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); - // Parses an unsigned byte from a String in the given style. If - // a NumberFormatInfo isn't specified, the current culture's - // NumberFormatInfo is assumed. public static byte Parse(string s, NumberStyles style, IFormatProvider? provider) { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider)); + if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } + return Parse(s.AsSpan(), style, provider); } public static byte Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Parse(s, style, NumberFormatInfo.GetInstance(provider)); - } - - private static byte Parse(ReadOnlySpan s, NumberStyles style, NumberFormatInfo info) - { - Number.ParsingStatus status = Number.TryParseUInt32(s, style, info, out uint i); - if (status != Number.ParsingStatus.OK) - { - Number.ThrowOverflowOrFormatException(status, s, TypeCode.Byte); - } - - if (i > MaxValue) Number.ThrowOverflowException(TypeCode.Byte); - return (byte)i; + return Number.ParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse([NotNullWhen(true)] string? s, out byte result) - { - if (s == null) - { - result = 0; - return false; - } + public static bool TryParse([NotNullWhen(true)] string? s, out byte result) => TryParse(s, NumberStyles.Integer, provider: null, out result); - return TryParse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); - } - - public static bool TryParse(ReadOnlySpan s, out byte result) - { - return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); - } + public static bool TryParse(ReadOnlySpan s, out byte result) => TryParse(s, NumberStyles.Integer, provider: null, out result); public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out byte result) { NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) + if (s is null) { result = 0; return false; } - - return TryParse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider), out result); + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out byte result) { NumberFormatInfo.ValidateParseStyleInteger(style); - return TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result); - } - - private static bool TryParse(ReadOnlySpan s, NumberStyles style, NumberFormatInfo info, out byte result) - { - if (Number.TryParseUInt32(s, style, info, out uint i) != Number.ParsingStatus.OK - || i > MaxValue) - { - result = 0; - return false; - } - result = (byte)i; - return true; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } public override string ToString() @@ -1213,5 +1160,25 @@ static bool INumberBase.TryConvertToTruncating(byte value, [MaybeN static byte IUtfChar.CastFrom(int value) => (byte)value; static byte IUtfChar.CastFrom(uint value) => (byte)value; static byte IUtfChar.CastFrom(ulong value) => (byte)value; + + // + // IBinaryIntegerParseAndFormatInfo + // + + static bool IBinaryIntegerParseAndFormatInfo.IsSigned => false; + + static int IBinaryIntegerParseAndFormatInfo.MaxDigitCount => 3; // 255 + + static int IBinaryIntegerParseAndFormatInfo.MaxHexDigitCount => 2; // 0xFF + + static byte IBinaryIntegerParseAndFormatInfo.MaxValueDiv10 => MaxValue / 10; + + static string IBinaryIntegerParseAndFormatInfo.OverflowMessage => SR.Overflow_Byte; + + static bool IBinaryIntegerParseAndFormatInfo.IsGreaterThanAsUnsigned(byte left, byte right) => left > right; + + static byte IBinaryIntegerParseAndFormatInfo.MultiplyBy10(byte value) => (byte)(value * 10); + + static byte IBinaryIntegerParseAndFormatInfo.MultiplyBy16(byte value) => (byte)(value * 16); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Char.cs b/src/libraries/System.Private.CoreLib/src/System/Char.cs index 7d0c8dc2e7d3e..bac465382d004 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Char.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Char.cs @@ -36,7 +36,8 @@ public readonly struct Char IMinMaxValue, IUnsignedNumber, IUtf8SpanFormattable, - IUtfChar + IUtfChar, + IBinaryIntegerParseAndFormatInfo { // // Member Variables @@ -201,29 +202,37 @@ bool IUtf8SpanFormattable.TryFormat(Span utf8Destination, out int bytesWri public static char Parse(string s) { - if (s == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - } + if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } + return Parse(s.AsSpan()); + } + internal static char Parse(ReadOnlySpan s) + { if (s.Length != 1) { - throw new FormatException(SR.Format_NeedSingleChar); + ThrowHelper.ThrowFormatException_NeedSingleChar(); } return s[0]; } public static bool TryParse([NotNullWhen(true)] string? s, out char result) { - result = '\0'; - if (s == null) + if (s is null) { + result = '\0'; return false; } + return TryParse(s.AsSpan(), out result); + } + + internal static bool TryParse(ReadOnlySpan s, out char result) + { if (s.Length != 1) { + result = '\0'; return false; } + result = s[0]; return true; } @@ -1509,14 +1518,7 @@ bool IBinaryInteger.TryWriteLittleEndian(Span destination, out int b static char INumberBase.Parse(string s, NumberStyles style, IFormatProvider? provider) => Parse(s); - static char INumberBase.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider) - { - if (s.Length != 1) - { - throw new FormatException(SR.Format_NeedSingleChar); - } - return s[0]; - } + static char INumberBase.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider) => Parse(s); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1930,16 +1932,7 @@ static bool INumberBase.TryConvertToTruncating(char value, [MaybeN static bool INumberBase.TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out char result) => TryParse(s, out result); - static bool INumberBase.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out char result) - { - if (s.Length != 1) - { - result = default; - return false; - } - result = s[0]; - return true; - } + static bool INumberBase.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out char result) => TryParse(s, out result); // // IParsable @@ -1966,25 +1959,9 @@ static bool INumberBase.TryParse(ReadOnlySpan s, NumberStyles style, // ISpanParsable // - static char ISpanParsable.Parse(ReadOnlySpan s, IFormatProvider? provider) - { - if (s.Length != 1) - { - throw new FormatException(SR.Format_NeedSingleChar); - } - return s[0]; - } + static char ISpanParsable.Parse(ReadOnlySpan s, IFormatProvider? provider) => Parse(s); - static bool ISpanParsable.TryParse(ReadOnlySpan s, IFormatProvider? provider, out char result) - { - if (s.Length != 1) - { - result = default; - return false; - } - result = s[0]; - return true; - } + static bool ISpanParsable.TryParse(ReadOnlySpan s, IFormatProvider? provider, out char result) => TryParse(s, out result); // // ISubtractionOperators @@ -2022,5 +1999,25 @@ static bool ISpanParsable.TryParse(ReadOnlySpan s, IFormatProvider? static char IUtfChar.CastFrom(int value) => (char)value; static char IUtfChar.CastFrom(uint value) => (char)value; static char IUtfChar.CastFrom(ulong value) => (char)value; + + // + // IBinaryIntegerParseAndFormatInfo + // + + static bool IBinaryIntegerParseAndFormatInfo.IsSigned => false; + + static int IBinaryIntegerParseAndFormatInfo.MaxDigitCount => 5; // 65_535 + + static int IBinaryIntegerParseAndFormatInfo.MaxHexDigitCount => 4; // 0xFFFF + + static char IBinaryIntegerParseAndFormatInfo.MaxValueDiv10 => (char)(MaxValue / 10); + + static string IBinaryIntegerParseAndFormatInfo.OverflowMessage => SR.Overflow_Char; + + static bool IBinaryIntegerParseAndFormatInfo.IsGreaterThanAsUnsigned(char left, char right) => left > right; + + static char IBinaryIntegerParseAndFormatInfo.MultiplyBy10(char value) => (char)(value * 10); + + static char IBinaryIntegerParseAndFormatInfo.MultiplyBy16(char value) => (char)(value * 16); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index 33a5beae402de..bb7fbaa73fffa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -781,35 +781,35 @@ static bool TryParseRareTypes(RuntimeType rt, ReadOnlySpan value, bool ign { case CorElementType.ELEMENT_TYPE_R4: { - parsed = TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out float localResult); + parsed = TryParseRareTypeByValueOrName(rt, value, ignoreCase, throwOnFailure, out float localResult); result = BitConverter.SingleToInt32Bits(localResult); } break; case CorElementType.ELEMENT_TYPE_R8: { - parsed = TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out double localResult); + parsed = TryParseRareTypeByValueOrName(rt, value, ignoreCase, throwOnFailure, out double localResult); result = BitConverter.DoubleToInt64Bits(localResult); } break; case CorElementType.ELEMENT_TYPE_I: { - parsed = TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out nint localResult); + parsed = TryParseRareTypeByValueOrName(rt, value, ignoreCase, throwOnFailure, out nint localResult); result = localResult; } break; case CorElementType.ELEMENT_TYPE_U: { - parsed = TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out nuint localResult); + parsed = TryParseRareTypeByValueOrName(rt, value, ignoreCase, throwOnFailure, out nuint localResult); result = (long)localResult; } break; case CorElementType.ELEMENT_TYPE_CHAR: { - parsed = TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out char localResult); + parsed = TryParseRareTypeByValueOrName(rt, value, ignoreCase, throwOnFailure, out char localResult); result = localResult; } break; @@ -901,11 +901,11 @@ private static bool TryParse(ReadOnlySpan value, bool ignoreCase, b if (underlyingType == typeof(long)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); if (underlyingType == typeof(ulong)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); #if RARE_ENUMS - if (underlyingType == typeof(nint)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); - if (underlyingType == typeof(nuint)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); - if (underlyingType == typeof(float)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); - if (underlyingType == typeof(double)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); - if (underlyingType == typeof(char)) return TryParseByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); + if (underlyingType == typeof(nint)) return TryParseRareTypeByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); + if (underlyingType == typeof(nuint)) return TryParseRareTypeByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); + if (underlyingType == typeof(float)) return TryParseRareTypeByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); + if (underlyingType == typeof(double)) return TryParseRareTypeByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); + if (underlyingType == typeof(char)) return TryParseRareTypeByValueOrName(rt, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); #endif throw CreateUnknownEnumTypeException(); @@ -914,8 +914,8 @@ private static bool TryParse(ReadOnlySpan value, bool ignoreCase, b /// Core implementation for all {Try}Parse methods, both generic and non-generic, parsing either by value or by name. private static unsafe bool TryParseByValueOrName( RuntimeType enumType, ReadOnlySpan value, bool ignoreCase, bool throwOnFailure, out TUnderlying result) - where TUnderlying : struct, INumber, IBitwiseOperators, IMinMaxValue - where TStorage : struct, INumber, IBitwiseOperators, IMinMaxValue + where TUnderlying : unmanaged, IBinaryIntegerParseAndFormatInfo + where TStorage : unmanaged, IBinaryIntegerParseAndFormatInfo { AssertValidGenerics(); @@ -942,89 +942,77 @@ private static unsafe bool TryParseByValueOrName( NumberFormatInfo numberFormat = CultureInfo.InvariantCulture.NumberFormat; const NumberStyles NumberStyle = NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingWhite; - Number.ParsingStatus status; - if (typeof(TUnderlying) == typeof(int)) + Number.ParsingStatus status = Number.TryParseBinaryIntegerStyle(value, NumberStyle, numberFormat, out result); + if (status == Number.ParsingStatus.OK) { - Unsafe.SkipInit(out result); - status = Number.TryParseInt32IntegerStyle(value, NumberStyle, numberFormat, out Unsafe.As(ref result)); - if (status == Number.ParsingStatus.OK) - { - return true; - } + return true; } - else if (typeof(TUnderlying) == typeof(uint)) + + if (status != Number.ParsingStatus.Overflow) { Unsafe.SkipInit(out result); - status = Number.TryParseUInt32IntegerStyle(value, NumberStyle, numberFormat, out Unsafe.As(ref result)); - if (status == Number.ParsingStatus.OK) - { - return true; - } + return TryParseByName(enumType, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); } - else if (typeof(TUnderlying) == typeof(long)) + + if (throwOnFailure) { - Unsafe.SkipInit(out result); - status = Number.TryParseInt64IntegerStyle(value, NumberStyle, numberFormat, out Unsafe.As(ref result)); - if (status == Number.ParsingStatus.OK) + Number.ThrowOverflowException(Type.GetTypeCode(typeof(TUnderlying))); + } + } + + ParseFailure: + if (throwOnFailure) + { + ThrowInvalidEmptyParseArgument(); + } + + result = default; + return false; + } + + private static unsafe bool TryParseRareTypeByValueOrName( + RuntimeType enumType, ReadOnlySpan value, bool ignoreCase, bool throwOnFailure, out TUnderlying result) + where TUnderlying : struct, INumber, IBitwiseOperators, IMinMaxValue + where TStorage : struct, INumber, IBitwiseOperators, IMinMaxValue + { + AssertValidGenerics(); + + if (!value.IsEmpty) + { + char c = value[0]; + if (char.IsWhiteSpace(c)) + { + value = value.TrimStart(); + if (value.IsEmpty) { - return true; + goto ParseFailure; } + + c = value[0]; } - else if (typeof(TUnderlying) == typeof(ulong)) + + if (!char.IsAsciiDigit(c) && c != '-' && c != '+') { Unsafe.SkipInit(out result); - status = Number.TryParseUInt64IntegerStyle(value, NumberStyle, numberFormat, out Unsafe.As(ref result)); - if (status == Number.ParsingStatus.OK) - { - return true; - } + return TryParseByName(enumType, value, ignoreCase, throwOnFailure, out Unsafe.As(ref result)); } - else if (typeof(TUnderlying) == typeof(byte) || typeof(TUnderlying) == typeof(ushort)) + +#if RARE_ENUMS + Number.ParsingStatus status; + Type underlyingType = GetUnderlyingType(enumType); + + try { - status = Number.TryParseUInt32IntegerStyle(value, NumberStyle, numberFormat, out uint uint32result); - if (status == Number.ParsingStatus.OK) - { - if (uint32result <= uint.CreateTruncating(TUnderlying.MaxValue)) - { - result = TUnderlying.CreateTruncating(uint32result); - return true; - } - status = Number.ParsingStatus.Overflow; - } + result = (TUnderlying)ToObject(enumType, Convert.ChangeType(value.ToString(), underlyingType, CultureInfo.InvariantCulture)!); + return true; } - else if (typeof(TUnderlying) == typeof(sbyte) || typeof(TUnderlying) == typeof(short)) + catch (FormatException) { - status = Number.TryParseInt32IntegerStyle(value, NumberStyle, numberFormat, out int int32result); - if (status == Number.ParsingStatus.OK) - { - if (int32result >= int.CreateTruncating(TUnderlying.MinValue) && int32result <= int.CreateTruncating(TUnderlying.MaxValue)) - { - result = TUnderlying.CreateTruncating(int32result); - return true; - } - status = Number.ParsingStatus.Overflow; - } + status = Number.ParsingStatus.Failed; // e.g. tlbimp enums that can have values of the form "3D" } - else + catch when (!throwOnFailure) { -#if RARE_ENUMS - Type underlyingType = GetUnderlyingType(enumType); - try - { - result = (TUnderlying)ToObject(enumType, Convert.ChangeType(value.ToString(), underlyingType, CultureInfo.InvariantCulture)!); - return true; - } - catch (FormatException) - { - status = Number.ParsingStatus.Failed; // e.g. tlbimp enums that can have values of the form "3D" - } - catch when (!throwOnFailure) - { - status = Number.ParsingStatus.Overflow; // fall through to returning failure - } -#else - throw CreateUnknownEnumTypeException(); -#endif + status = Number.ParsingStatus.Overflow; // fall through to returning failure } if (status != Number.ParsingStatus.Overflow) @@ -1037,6 +1025,9 @@ private static unsafe bool TryParseByValueOrName( { Number.ThrowOverflowException(Type.GetTypeCode(typeof(TUnderlying))); } +#else + throw CreateUnknownEnumTypeException(); +#endif } ParseFailure: @@ -1049,7 +1040,7 @@ private static unsafe bool TryParseByValueOrName( return false; } - /// Handles just the name parsing portion of . + /// Handles just the name parsing portion of . private static bool TryParseByName(RuntimeType enumType, ReadOnlySpan value, bool ignoreCase, bool throwOnFailure, out TStorage result) where TStorage : struct, INumber, IBitwiseOperators { diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs index 5af77c998154a..03a4ba17f78c6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs @@ -830,6 +830,7 @@ public static NumberFormatInfo ReadOnly(NumberFormatInfo nfi) | NumberStyles.AllowThousands | NumberStyles.AllowExponent | NumberStyles.AllowCurrencySymbol | NumberStyles.AllowHexSpecifier); + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void ValidateParseStyleInteger(NumberStyles style) { // Check for undefined flags or invalid hex number flags diff --git a/src/libraries/System.Private.CoreLib/src/System/Guid.cs b/src/libraries/System.Private.CoreLib/src/System/Guid.cs index ec28fdeb45aaa..12f2f11ce6f02 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Guid.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Guid.cs @@ -491,7 +491,7 @@ static bool TryCompatParsing(ReadOnlySpan guidString, ref GuidResult resul result._fg = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness((ushort)uintTmp) : (ushort)uintTmp; // Unlike the other components, this one never allowed 0x or +, so we can parse it as straight hex. - if (Number.TryParseUInt32HexNumberStyle(guidString.Slice(28, 8), NumberStyles.AllowHexSpecifier, out uintTmp) == Number.ParsingStatus.OK) // _h, _i, _j, _k + if (Number.TryParseBinaryIntegerHexNumberStyle(guidString.Slice(28, 8), NumberStyles.AllowHexSpecifier, out uintTmp) == Number.ParsingStatus.OK) // _h, _i, _j, _k { result._hijk = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(uintTmp) : uintTmp; return true; diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index d4f7c6a2c1928..c6b98d28526c9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -18,7 +18,8 @@ public readonly struct Int128 : IBinaryInteger, IMinMaxValue, ISignedNumber, - IUtf8SpanFormattable + IUtf8SpanFormattable, + IBinaryIntegerParseAndFormatInfo { internal const int Size = 16; @@ -125,75 +126,44 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS return Number.TryFormatInt128(this, format, provider, utf8Destination, out bytesWritten); } - public static Int128 Parse(string s) - { - ArgumentNullException.ThrowIfNull(s); - return Number.ParseInt128(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); - } + public static Int128 Parse(string s) => Parse(s, NumberStyles.Integer, provider: null); - public static Int128 Parse(string s, NumberStyles style) - { - ArgumentNullException.ThrowIfNull(s); - NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.ParseInt128(s, style, NumberFormatInfo.CurrentInfo); - } + public static Int128 Parse(string s, NumberStyles style) => Parse(s, style, provider: null); - public static Int128 Parse(string s, IFormatProvider? provider) - { - ArgumentNullException.ThrowIfNull(s); - return Number.ParseInt128(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); - } + public static Int128 Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); public static Int128 Parse(string s, NumberStyles style, IFormatProvider? provider) { - ArgumentNullException.ThrowIfNull(s); - NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.ParseInt128(s, style, NumberFormatInfo.GetInstance(provider)); + if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } + return Parse(s.AsSpan(), style, provider); } public static Int128 Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.ParseInt128(s, style, NumberFormatInfo.GetInstance(provider)); + return Number.ParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse([NotNullWhen(true)] string? s, out Int128 result) - { - if (s is not null) - { - return Number.TryParseInt128IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } - else - { - result = default; - return false; - } - } + public static bool TryParse([NotNullWhen(true)] string? s, out Int128 result) => TryParse(s, NumberStyles.Integer, provider: null, out result); - public static bool TryParse(ReadOnlySpan s, out Int128 result) - { - return Number.TryParseInt128IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } + public static bool TryParse(ReadOnlySpan s, out Int128 result) => TryParse(s, NumberStyles.Integer, provider: null, out result); public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out Int128 result) { NumberFormatInfo.ValidateParseStyleInteger(style); - if (s is not null) - { - return Number.TryParseInt128(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; - } - else + if (s is null) { - result = default; + result = 0; return false; } + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out Int128 result) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.TryParseInt128(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } // @@ -2199,5 +2169,25 @@ static bool INumberBase.TryConvertToTruncating(Int128 value, [Ma /// public static Int128 operator +(Int128 value) => value; + + // + // IBinaryIntegerParseAndFormatInfo + // + + static bool IBinaryIntegerParseAndFormatInfo.IsSigned => true; + + static int IBinaryIntegerParseAndFormatInfo.MaxDigitCount => 39; // 170_141_183_460_469_231_731_687_303_715_884_105_727 + + static int IBinaryIntegerParseAndFormatInfo.MaxHexDigitCount => 32; // 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF + + static Int128 IBinaryIntegerParseAndFormatInfo.MaxValueDiv10 => new Int128(0x0CCC_CCCC_CCCC_CCCC, 0xCCCC_CCCC_CCCC_CCCC); + + static string IBinaryIntegerParseAndFormatInfo.OverflowMessage => SR.Overflow_Int128; + + static bool IBinaryIntegerParseAndFormatInfo.IsGreaterThanAsUnsigned(Int128 left, Int128 right) => (UInt128)(left) > (UInt128)(right); + + static Int128 IBinaryIntegerParseAndFormatInfo.MultiplyBy10(Int128 value) => value * 10; + + static Int128 IBinaryIntegerParseAndFormatInfo.MultiplyBy16(Int128 value) => value * 16; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs index 2b3d0bf60d324..02d896f981fb3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs @@ -24,7 +24,8 @@ public readonly struct Int16 IBinaryInteger, IMinMaxValue, ISignedNumber, - IUtf8SpanFormattable + IUtf8SpanFormattable, + IBinaryIntegerParseAndFormatInfo { private readonly short m_value; // Do not rename (binary serialization) @@ -125,102 +126,44 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS return Number.TryFormatInt32(m_value, 0x0000FFFF, format, provider, utf8Destination, out bytesWritten); } - public static short Parse(string s) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); - } + public static short Parse(string s) => Parse(s, NumberStyles.Integer, provider: null); - public static short Parse(string s, NumberStyles style) - { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, style, NumberFormatInfo.CurrentInfo); - } + public static short Parse(string s, NumberStyles style) => Parse(s, style, provider: null); - public static short Parse(string s, IFormatProvider? provider) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); - } + public static short Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); public static short Parse(string s, NumberStyles style, IFormatProvider? provider) { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider)); + if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } + return Parse(s.AsSpan(), style, provider); } public static short Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Parse(s, style, NumberFormatInfo.GetInstance(provider)); + return Number.ParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider)); } - private static short Parse(ReadOnlySpan s, NumberStyles style, NumberFormatInfo info) - { - Number.ParsingStatus status = Number.TryParseInt32(s, style, info, out int i); - if (status != Number.ParsingStatus.OK) - { - Number.ThrowOverflowOrFormatException(status, s, TypeCode.Int16); - } + public static bool TryParse([NotNullWhen(true)] string? s, out short result) => TryParse(s, NumberStyles.Integer, provider: null, out result); - // For hex number styles AllowHexSpecifier << 6 == 0x8000 and cancels out MinValue so the check is effectively: (uint)i > ushort.MaxValue - // For integer styles it's zero and the effective check is (uint)(i - MinValue) > ushort.MaxValue - if ((uint)(i - MinValue - ((int)(style & NumberStyles.AllowHexSpecifier) << 6)) > ushort.MaxValue) - { - Number.ThrowOverflowException(TypeCode.Int16); - } - return (short)i; - } - - public static bool TryParse([NotNullWhen(true)] string? s, out short result) - { - if (s == null) - { - result = 0; - return false; - } - - return TryParse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); - } - - public static bool TryParse(ReadOnlySpan s, out short result) - { - return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); - } + public static bool TryParse(ReadOnlySpan s, out short result) => TryParse(s, NumberStyles.Integer, provider: null, out result); public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out short result) { NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) + if (s is null) { result = 0; return false; } - - return TryParse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider), out result); + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out short result) { NumberFormatInfo.ValidateParseStyleInteger(style); - return TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result); - } - - private static bool TryParse(ReadOnlySpan s, NumberStyles style, NumberFormatInfo info, out short result) - { - // For hex number styles AllowHexSpecifier << 6 == 0x8000 and cancels out MinValue so the check is effectively: (uint)i > ushort.MaxValue - // For integer styles it's zero and the effective check is (uint)(i - MinValue) > ushort.MaxValue - if (Number.TryParseInt32(s, style, info, out int i) != Number.ParsingStatus.OK - || (uint)(i - MinValue - ((int)(style & NumberStyles.AllowHexSpecifier) << 6)) > ushort.MaxValue) - { - result = 0; - return false; - } - result = (short)i; - return true; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } // @@ -1421,5 +1364,25 @@ static bool INumberBase.TryConvertToTruncating(short value, [Mayb /// static short IUnaryPlusOperators.operator +(short value) => (short)(+value); + + // + // IBinaryIntegerParseAndFormatInfo + // + + static bool IBinaryIntegerParseAndFormatInfo.IsSigned => true; + + static int IBinaryIntegerParseAndFormatInfo.MaxDigitCount => 5; // 32_767 + + static int IBinaryIntegerParseAndFormatInfo.MaxHexDigitCount => 4; // 0x7FFF + + static short IBinaryIntegerParseAndFormatInfo.MaxValueDiv10 => MaxValue / 10; + + static string IBinaryIntegerParseAndFormatInfo.OverflowMessage => SR.Overflow_Int16; + + static bool IBinaryIntegerParseAndFormatInfo.IsGreaterThanAsUnsigned(short left, short right) => (ushort)(left) > (ushort)(right); + + static short IBinaryIntegerParseAndFormatInfo.MultiplyBy10(short value) => (short)(value * 10); + + static short IBinaryIntegerParseAndFormatInfo.MultiplyBy16(short value) => (short)(value * 16); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Int32.cs b/src/libraries/System.Private.CoreLib/src/System/Int32.cs index dc1986c0098fa..a0c055cd21a34 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int32.cs @@ -24,7 +24,8 @@ public readonly struct Int32 IBinaryInteger, IMinMaxValue, ISignedNumber, - IUtf8SpanFormattable + IUtf8SpanFormattable, + IBinaryIntegerParseAndFormatInfo { private readonly int m_value; // Do not rename (binary serialization) @@ -135,85 +136,44 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS return Number.TryFormatInt32(m_value, ~0, format, provider, utf8Destination, out bytesWritten); } - public static int Parse(string s) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); - } + public static int Parse(string s) => Parse(s, NumberStyles.Integer, provider: null); - public static int Parse(string s, NumberStyles style) - { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseInt32(s, style, NumberFormatInfo.CurrentInfo); - } + public static int Parse(string s, NumberStyles style) => Parse(s, style, provider: null); - // Parses an integer from a String in the given style. If - // a NumberFormatInfo isn't specified, the current culture's - // NumberFormatInfo is assumed. - // - public static int Parse(string s, IFormatProvider? provider) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); - } + public static int Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); - // Parses an integer from a String in the given style. If - // a NumberFormatInfo isn't specified, the current culture's - // NumberFormatInfo is assumed. - // public static int Parse(string s, NumberStyles style, IFormatProvider? provider) { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseInt32(s, style, NumberFormatInfo.GetInstance(provider)); + if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } + return Parse(s.AsSpan(), style, provider); } public static int Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.ParseInt32(s, style, NumberFormatInfo.GetInstance(provider)); + return Number.ParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider)); } - // Parses an integer from a String. Returns false rather - // than throwing an exception if input is invalid. - // - public static bool TryParse([NotNullWhen(true)] string? s, out int result) - { - if (s == null) - { - result = 0; - return false; - } + public static bool TryParse([NotNullWhen(true)] string? s, out int result) => TryParse(s, NumberStyles.Integer, provider: null, out result); - return Number.TryParseInt32IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } + public static bool TryParse(ReadOnlySpan s, out int result) => TryParse(s, NumberStyles.Integer, provider: null, out result); - public static bool TryParse(ReadOnlySpan s, out int result) - { - return Number.TryParseInt32IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } - - // Parses an integer from a String in the given style. Returns false rather - // than throwing an exception if input is invalid. - // public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out int result) { NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) + if (s is null) { result = 0; return false; } - - return Number.TryParseInt32(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out int result) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.TryParseInt32(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } // @@ -1440,5 +1400,25 @@ static bool INumberBase.TryConvertToTruncating(int value, [MaybeNul /// static int IUnaryPlusOperators.operator +(int value) => +value; + + // + // IBinaryIntegerParseAndFormatInfo + // + + static bool IBinaryIntegerParseAndFormatInfo.IsSigned => true; + + static int IBinaryIntegerParseAndFormatInfo.MaxDigitCount => 10; // 2_147_483_647 + + static int IBinaryIntegerParseAndFormatInfo.MaxHexDigitCount => 8; // 0x7FFF_FFFF + + static int IBinaryIntegerParseAndFormatInfo.MaxValueDiv10 => MaxValue / 10; + + static string IBinaryIntegerParseAndFormatInfo.OverflowMessage => SR.Overflow_Int32; + + static bool IBinaryIntegerParseAndFormatInfo.IsGreaterThanAsUnsigned(int left, int right) => (uint)(left) > (uint)(right); + + static int IBinaryIntegerParseAndFormatInfo.MultiplyBy10(int value) => value * 10; + + static int IBinaryIntegerParseAndFormatInfo.MultiplyBy16(int value) => value * 16; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Int64.cs b/src/libraries/System.Private.CoreLib/src/System/Int64.cs index d8a3787917e16..7f4ace2b1c725 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int64.cs @@ -24,7 +24,8 @@ public readonly struct Int64 IBinaryInteger, IMinMaxValue, ISignedNumber, - IUtf8SpanFormattable + IUtf8SpanFormattable, + IBinaryIntegerParseAndFormatInfo { private readonly long m_value; // Do not rename (binary serialization) @@ -132,75 +133,44 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS return Number.TryFormatInt64(m_value, format, provider, utf8Destination, out bytesWritten); } - public static long Parse(string s) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseInt64(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); - } + public static long Parse(string s) => Parse(s, NumberStyles.Integer, provider: null); - public static long Parse(string s, NumberStyles style) - { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseInt64(s, style, NumberFormatInfo.CurrentInfo); - } + public static long Parse(string s, NumberStyles style) => Parse(s, style, provider: null); - public static long Parse(string s, IFormatProvider? provider) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseInt64(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); - } + public static long Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); - // Parses a long from a String in the given style. If - // a NumberFormatInfo isn't specified, the current culture's - // NumberFormatInfo is assumed. - // public static long Parse(string s, NumberStyles style, IFormatProvider? provider) { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseInt64(s, style, NumberFormatInfo.GetInstance(provider)); + if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } + return Parse(s.AsSpan(), style, provider); } public static long Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.ParseInt64(s, style, NumberFormatInfo.GetInstance(provider)); + return Number.ParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse([NotNullWhen(true)] string? s, out long result) - { - if (s == null) - { - result = 0; - return false; - } - - return Number.TryParseInt64IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } + public static bool TryParse([NotNullWhen(true)] string? s, out long result) => TryParse(s, NumberStyles.Integer, provider: null, out result); - public static bool TryParse(ReadOnlySpan s, out long result) - { - return Number.TryParseInt64IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } + public static bool TryParse(ReadOnlySpan s, out long result) => TryParse(s, NumberStyles.Integer, provider: null, out result); public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out long result) { NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) + if (s is null) { result = 0; return false; } - - return Number.TryParseInt64(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out long result) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.TryParseInt64(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } // @@ -1433,5 +1403,25 @@ static bool INumberBase.TryConvertToTruncating(long value, [MaybeN /// static long IUnaryPlusOperators.operator +(long value) => +value; + + // + // IBinaryIntegerParseAndFormatInfo + // + + static bool IBinaryIntegerParseAndFormatInfo.IsSigned => true; + + static int IBinaryIntegerParseAndFormatInfo.MaxDigitCount => 19; // 9_223_372_036_854_775_807 + + static int IBinaryIntegerParseAndFormatInfo.MaxHexDigitCount => 16; // 0x7FFF_FFFF_FFFF_FFFF + + static long IBinaryIntegerParseAndFormatInfo.MaxValueDiv10 => MaxValue / 10; + + static string IBinaryIntegerParseAndFormatInfo.OverflowMessage => SR.Overflow_Int64; + + static bool IBinaryIntegerParseAndFormatInfo.IsGreaterThanAsUnsigned(long left, long right) => (ulong)(left) > (ulong)(right); + + static long IBinaryIntegerParseAndFormatInfo.MultiplyBy10(long value) => value * 10; + + static long IBinaryIntegerParseAndFormatInfo.MultiplyBy16(long value) => value * 16; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs index b738f5058d08a..fd89703d9d96f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +25,26 @@ namespace System // specified. Note, however, that the Parse methods do not accept // NaNs or Infinities. + internal interface IBinaryIntegerParseAndFormatInfo : IBinaryInteger, IMinMaxValue + where TSelf : unmanaged, IBinaryIntegerParseAndFormatInfo + { + static abstract bool IsSigned { get; } + + static abstract int MaxDigitCount { get; } + + static abstract int MaxHexDigitCount { get; } + + static abstract TSelf MaxValueDiv10 { get; } + + static abstract string OverflowMessage { get; } + + static abstract bool IsGreaterThanAsUnsigned(TSelf left, TSelf right); + + static abstract TSelf MultiplyBy10(TSelf value); + + static abstract TSelf MultiplyBy16(TSelf value); + } + internal static partial class Number { private const int Int32Precision = 10; @@ -45,300 +66,75 @@ internal static partial class Number private const int HalfMaxExponent = 5; private const int HalfMinExponent = -8; - private static unsafe bool TryNumberToInt32(ref NumberBuffer number, ref int value) + private static unsafe bool TryNumberBufferToBinaryInteger(ref NumberBuffer number, ref TInteger value) + where TInteger : unmanaged, IBinaryIntegerParseAndFormatInfo { number.CheckConsistency(); int i = number.Scale; - if (i > Int32Precision || i < number.DigitsCount) - { - return false; - } - byte* p = number.GetDigitsPointer(); - Debug.Assert(p != null); - int n = 0; - while (--i >= 0) - { - if ((uint)n > (0x7FFFFFFF / 10)) - { - return false; - } - n *= 10; - if (*p != '\0') - { - n += (*p++ - '0'); - } - } - if (number.IsNegative) - { - n = -n; - if (n > 0) - { - return false; - } - } - else - { - if (n < 0) - { - return false; - } - } - value = n; - return true; - } - - private static unsafe bool TryNumberToInt64(ref NumberBuffer number, ref long value) - { - number.CheckConsistency(); - int i = number.Scale; - if (i > Int64Precision || i < number.DigitsCount) + if ((i > TInteger.MaxDigitCount) || (i < number.DigitsCount) || (!TInteger.IsSigned && number.IsNegative)) { return false; } - byte* p = number.GetDigitsPointer(); - Debug.Assert(p != null); - long n = 0; - while (--i >= 0) - { - if ((ulong)n > (0x7FFFFFFFFFFFFFFF / 10)) - { - return false; - } - n *= 10; - if (*p != '\0') - { - n += (*p++ - '0'); - } - } - if (number.IsNegative) - { - n = -n; - if (n > 0) - { - return false; - } - } - else - { - if (n < 0) - { - return false; - } - } - value = n; - return true; - } - - private static unsafe bool TryNumberToInt128(ref NumberBuffer number, ref Int128 value) - { - number.CheckConsistency(); - int i = number.Scale; - if ((i > Int128Precision) || (i < number.DigitsCount)) - { - return false; - } byte* p = number.GetDigitsPointer(); + Debug.Assert(p != null); - Int128 n = 0; + TInteger n = TInteger.Zero; + while (--i >= 0) { - if ((UInt128)n > new UInt128(0x0CCCCCCCCCCCCCCC, 0xCCCCCCCCCCCCCCCC)) // Int128.MaxValue / 10 - { - return false; - } - n *= 10; - if (*p != '\0') - { - n += (*p++ - '0'); - } - } - if (number.IsNegative) - { - n = -n; - if (n > 0) - { - return false; - } - } - else - { - if (n < 0) + if (TInteger.IsGreaterThanAsUnsigned(n, TInteger.MaxValueDiv10)) { return false; } - } - value = n; - return true; - } - private static unsafe bool TryNumberToUInt32(ref NumberBuffer number, ref uint value) - { - number.CheckConsistency(); + n = TInteger.MultiplyBy10(n); - int i = number.Scale; - if (i > UInt32Precision || i < number.DigitsCount || number.IsNegative) - { - return false; - } - byte* p = number.GetDigitsPointer(); - Debug.Assert(p != null); - uint n = 0; - while (--i >= 0) - { - if (n > (0xFFFFFFFF / 10)) - { - return false; - } - n *= 10; if (*p != '\0') { - uint newN = n + (uint)(*p++ - '0'); - // Detect an overflow here... - if (newN < n) + TInteger newN = n + TInteger.CreateTruncating(*p++ - '0'); + + if (!TInteger.IsSigned && (newN < n)) { return false; } + n = newN; } } - value = n; - return true; - } - private static unsafe bool TryNumberToUInt64(ref NumberBuffer number, ref ulong value) - { - number.CheckConsistency(); - - int i = number.Scale; - if (i > UInt64Precision || i < number.DigitsCount || number.IsNegative) - { - return false; - } - byte* p = number.GetDigitsPointer(); - Debug.Assert(p != null); - ulong n = 0; - while (--i >= 0) + if (TInteger.IsSigned) { - if (n > (0xFFFFFFFFFFFFFFFF / 10)) - { - return false; - } - n *= 10; - if (*p != '\0') + if (number.IsNegative) { - ulong newN = n + (ulong)(*p++ - '0'); - // Detect an overflow here... - if (newN < n) + n = -n; + + if (n > TInteger.Zero) { return false; } - n = newN; } - } - value = n; - return true; - } - - private static unsafe bool TryNumberToUInt128(ref NumberBuffer number, ref UInt128 value) - { - number.CheckConsistency(); - - int i = number.Scale; - if (i > UInt128Precision || (i < number.DigitsCount) || number.IsNegative) - { - return false; - } - byte* p = number.GetDigitsPointer(); - Debug.Assert(p != null); - UInt128 n = 0U; - while (--i >= 0) - { - if (n > new UInt128(0x1999999999999999, 0x9999999999999999)) // UInt128.MaxValue / 10 + else if (n < TInteger.Zero) { return false; } - n *= 10U; - if (*p != '\0') - { - UInt128 newN = n + (UInt128)(*p++ - '0'); - // Detect an overflow here... - if (newN < n) - { - return false; - } - n = newN; - } } + value = n; return true; } - internal static int ParseInt32(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) - { - ParsingStatus status = TryParseInt32(value, styles, info, out int result); - if (status != ParsingStatus.OK) - { - ThrowOverflowOrFormatException(status, value, TypeCode.Int32); - } - - return result; - } - - internal static long ParseInt64(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) + internal static TInteger ParseBinaryInteger(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) + where TInteger : unmanaged, IBinaryIntegerParseAndFormatInfo { - ParsingStatus status = TryParseInt64(value, styles, info, out long result); - if (status != ParsingStatus.OK) - { - ThrowOverflowOrFormatException(status, value, TypeCode.Int64); - } - - return result; - } - - internal static Int128 ParseInt128(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) - { - ParsingStatus status = TryParseInt128(value, styles, info, out Int128 result); - if (status != ParsingStatus.OK) - { - ThrowOverflowOrFormatExceptionInt128(status); - } - - return result; - } - - internal static uint ParseUInt32(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) - { - ParsingStatus status = TryParseUInt32(value, styles, info, out uint result); - if (status != ParsingStatus.OK) - { - ThrowOverflowOrFormatException(status, value, TypeCode.UInt32); - } - - return result; - } - - internal static ulong ParseUInt64(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) - { - ParsingStatus status = TryParseUInt64(value, styles, info, out ulong result); - if (status != ParsingStatus.OK) - { - ThrowOverflowOrFormatException(status, value, TypeCode.UInt64); - } - - return result; - } + ParsingStatus status = TryParseBinaryInteger(value, styles, info, out TInteger result); - internal static UInt128 ParseUInt128(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info) - { - ParsingStatus status = TryParseUInt128(value, styles, info, out UInt128 result); if (status != ParsingStatus.OK) { - ThrowOverflowOrFormatExceptionUInt128(status); + ThrowOverflowOrFormatException(status, value); } - return result; } @@ -478,1473 +274,159 @@ private static unsafe bool TryParseNumber(scoped ref char* str, char* strEnd, Nu { number.Scale--; } - } - else if (((styles & NumberStyles.AllowDecimalPoint) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, decSep)) != null || (parsingCurrency && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, info.NumberDecimalSeparator)) != null)) - { - state |= StateDecimal; - p = next - 1; - } - else if (((styles & NumberStyles.AllowThousands) != 0) && ((state & StateDigits) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, groupSep)) != null || (parsingCurrency && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, info.NumberGroupSeparator)) != null)) - { - p = next - 1; - } - else - { - break; - } - ch = ++p < strEnd ? *p : '\0'; - } - - bool negExp = false; - number.DigitsCount = digEnd; - number.Digits[digEnd] = (byte)('\0'); - if ((state & StateDigits) != 0) - { - if ((ch == 'E' || ch == 'e') && ((styles & NumberStyles.AllowExponent) != 0)) - { - char* temp = p; - ch = ++p < strEnd ? *p : '\0'; - if ((next = MatchChars(p, strEnd, info._positiveSign)) != null) - { - ch = (p = next) < strEnd ? *p : '\0'; - } - else if ((next = MatchNegativeSignChars(p, strEnd, info)) != null) - { - ch = (p = next) < strEnd ? *p : '\0'; - negExp = true; - } - if (IsDigit(ch)) - { - int exp = 0; - do - { - exp = exp * 10 + (ch - '0'); - ch = ++p < strEnd ? *p : '\0'; - if (exp > 1000) - { - exp = 9999; - while (IsDigit(ch)) - { - ch = ++p < strEnd ? *p : '\0'; - } - } - } while (IsDigit(ch)); - if (negExp) - { - exp = -exp; - } - number.Scale += exp; - } - else - { - p = temp; - ch = p < strEnd ? *p : '\0'; - } - } - - if (number.Kind == NumberBufferKind.FloatingPoint && !number.HasNonZeroTail) - { - // Adjust the number buffer for trailing zeros - int numberOfFractionalDigits = digEnd - number.Scale; - if (numberOfFractionalDigits > 0) - { - numberOfTrailingZeros = Math.Min(numberOfTrailingZeros, numberOfFractionalDigits); - Debug.Assert(numberOfTrailingZeros >= 0); - number.DigitsCount = digEnd - numberOfTrailingZeros; - number.Digits[number.DigitsCount] = (byte)('\0'); - } - } - - while (true) - { - if (!IsWhite(ch) || (styles & NumberStyles.AllowTrailingWhite) == 0) - { - if ((styles & NumberStyles.AllowTrailingSign) != 0 && ((state & StateSign) == 0) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || (((next = MatchNegativeSignChars(p, strEnd, info)) != null) && (number.IsNegative = true)))) - { - state |= StateSign; - p = next - 1; - } - else if (ch == ')' && ((state & StateParens) != 0)) - { - state &= ~StateParens; - } - else if (currSymbol != null && (next = MatchChars(p, strEnd, currSymbol)) != null) - { - currSymbol = null; - p = next - 1; - } - else - { - break; - } - } - ch = ++p < strEnd ? *p : '\0'; - } - if ((state & StateParens) == 0) - { - if ((state & StateNonZero) == 0) - { - if (number.Kind != NumberBufferKind.Decimal) - { - number.Scale = 0; - } - if ((number.Kind == NumberBufferKind.Integer) && (state & StateDecimal) == 0) - { - number.IsNegative = false; - } - } - str = p; - return true; - } - } - str = p; - return false; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ParsingStatus TryParseInt32(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out int result) - { - if ((styles & ~NumberStyles.Integer) == 0) - { - // Optimized path for the common case of anything that's allowed for integer style. - return TryParseInt32IntegerStyle(value, styles, info, out result); - } - - if ((styles & NumberStyles.AllowHexSpecifier) != 0) - { - result = 0; - return TryParseUInt32HexNumberStyle(value, styles, out Unsafe.As(ref result)); - } - - return TryParseInt32Number(value, styles, info, out result); - } - - private static unsafe ParsingStatus TryParseInt32Number(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out int result) - { - result = 0; - NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, stackalloc byte[Int32NumberBufferLength]); - - if (!TryStringToNumber(value, styles, ref number, info)) - { - return ParsingStatus.Failed; - } - - if (!TryNumberToInt32(ref number, ref result)) - { - return ParsingStatus.Overflow; - } - - return ParsingStatus.OK; - } - - /// Parses int limited to styles that make up NumberStyles.Integer. - internal static ParsingStatus TryParseInt32IntegerStyle(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out int result) - { - Debug.Assert((styles & ~NumberStyles.Integer) == 0, "Only handles subsets of Integer format"); - - if (value.IsEmpty) - goto FalseExit; - - int index = 0; - int num = value[0]; - - // Skip past any whitespace at the beginning. - if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num)) - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - while (IsWhite(num)); - } - - // Parse leading sign. - int sign = 1; - if ((styles & NumberStyles.AllowLeadingSign) != 0) - { - if (info.HasInvariantNumberSigns) - { - if (num == '-') - { - sign = -1; - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else if (num == '+') - { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - } - else if (info.AllowHyphenDuringParsing && num == '-') - { - sign = -1; - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else - { - value = value.Slice(index); - index = 0; - string positiveSign = info.PositiveSign, negativeSign = info.NegativeSign; - if (!string.IsNullOrEmpty(positiveSign) && value.StartsWith(positiveSign)) - { - index += positiveSign.Length; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else if (!string.IsNullOrEmpty(negativeSign) && value.StartsWith(negativeSign)) - { - sign = -1; - index += negativeSign.Length; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - } - } - - bool overflow = false; - int answer = 0; - - if (IsDigit(num)) - { - // Skip past leading zeros. - if (num == '0') - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - } while (num == '0'); - if (!IsDigit(num)) - goto HasTrailingChars; - } - - // Parse most digits, up to the potential for overflow, which can't happen until after 9 digits. - answer = num - '0'; // first digit - index++; - for (int i = 0; i < 8; i++) // next 8 digits can't overflow - { - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - if (!IsDigit(num)) - goto HasTrailingChars; - index++; - answer = 10 * answer + num - '0'; - } - - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - if (!IsDigit(num)) - goto HasTrailingChars; - index++; - // Potential overflow now processing the 10th digit. - overflow = answer > int.MaxValue / 10; - answer = answer * 10 + num - '0'; - overflow |= (uint)answer > int.MaxValue + (((uint)sign) >> 31); - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - - // At this point, we're either overflowing or hitting a formatting error. - // Format errors take precedence for compatibility. - num = value[index]; - while (IsDigit(num)) - { - overflow = true; - index++; - if ((uint)index >= (uint)value.Length) - goto OverflowExit; - num = value[index]; - } - goto HasTrailingChars; - } - goto FalseExit; - - DoneAtEndButPotentialOverflow: - if (overflow) - { - goto OverflowExit; - } - DoneAtEnd: - result = answer * sign; - ParsingStatus status = ParsingStatus.OK; - Exit: - return status; - - FalseExit: // parsing failed - result = 0; - status = ParsingStatus.Failed; - goto Exit; - OverflowExit: - result = 0; - status = ParsingStatus.Overflow; - goto Exit; - - HasTrailingChars: // we've successfully parsed, but there are still remaining characters in the span - // Skip past trailing whitespace, then past trailing zeros, and if anything else remains, fail. - if (IsWhite(num)) - { - if ((styles & NumberStyles.AllowTrailingWhite) == 0) - goto FalseExit; - for (index++; index < value.Length; index++) - { - if (!IsWhite(value[index])) - break; - } - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - } - - if (!TrailingZeros(value, index)) - goto FalseExit; - - goto DoneAtEndButPotentialOverflow; - } - - /// Parses long inputs limited to styles that make up NumberStyles.Integer. - internal static ParsingStatus TryParseInt64IntegerStyle(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out long result) - { - Debug.Assert((styles & ~NumberStyles.Integer) == 0, "Only handles subsets of Integer format"); - - if (value.IsEmpty) - goto FalseExit; - - int index = 0; - int num = value[0]; - - // Skip past any whitespace at the beginning. - if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num)) - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - while (IsWhite(num)); - } - - // Parse leading sign. - int sign = 1; - if ((styles & NumberStyles.AllowLeadingSign) != 0) - { - if (info.HasInvariantNumberSigns) - { - if (num == '-') - { - sign = -1; - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else if (num == '+') - { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - } - else if (info.AllowHyphenDuringParsing && num == '-') - { - sign = -1; - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else - { - value = value.Slice(index); - index = 0; - string positiveSign = info.PositiveSign, negativeSign = info.NegativeSign; - if (!string.IsNullOrEmpty(positiveSign) && value.StartsWith(positiveSign)) - { - index += positiveSign.Length; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else if (!string.IsNullOrEmpty(negativeSign) && value.StartsWith(negativeSign)) - { - sign = -1; - index += negativeSign.Length; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - } - } - - bool overflow = false; - long answer = 0; - - if (IsDigit(num)) - { - // Skip past leading zeros. - if (num == '0') - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - } while (num == '0'); - if (!IsDigit(num)) - goto HasTrailingChars; - } - - // Parse most digits, up to the potential for overflow, which can't happen until after 18 digits. - answer = num - '0'; // first digit - index++; - for (int i = 0; i < 17; i++) // next 17 digits can't overflow - { - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - if (!IsDigit(num)) - goto HasTrailingChars; - index++; - answer = 10 * answer + num - '0'; - } - - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - if (!IsDigit(num)) - goto HasTrailingChars; - index++; - // Potential overflow now processing the 19th digit. - overflow = answer > long.MaxValue / 10; - answer = answer * 10 + num - '0'; - overflow |= (ulong)answer > (ulong)long.MaxValue + (((uint)sign) >> 31); - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - - // At this point, we're either overflowing or hitting a formatting error. - // Format errors take precedence for compatibility. - num = value[index]; - while (IsDigit(num)) - { - overflow = true; - index++; - if ((uint)index >= (uint)value.Length) - goto OverflowExit; - num = value[index]; - } - goto HasTrailingChars; - } - goto FalseExit; - - DoneAtEndButPotentialOverflow: - if (overflow) - { - goto OverflowExit; - } - DoneAtEnd: - result = answer * sign; - ParsingStatus status = ParsingStatus.OK; - Exit: - return status; - - FalseExit: // parsing failed - result = 0; - status = ParsingStatus.Failed; - goto Exit; - OverflowExit: - result = 0; - status = ParsingStatus.Overflow; - goto Exit; - - HasTrailingChars: // we've successfully parsed, but there are still remaining characters in the span - // Skip past trailing whitespace, then past trailing zeros, and if anything else remains, fail. - if (IsWhite(num)) - { - if ((styles & NumberStyles.AllowTrailingWhite) == 0) - goto FalseExit; - for (index++; index < value.Length; index++) - { - if (!IsWhite(value[index])) - break; - } - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - } - - if (!TrailingZeros(value, index)) - goto FalseExit; - - goto DoneAtEndButPotentialOverflow; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ParsingStatus TryParseInt64(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out long result) - { - if ((styles & ~NumberStyles.Integer) == 0) - { - // Optimized path for the common case of anything that's allowed for integer style. - return TryParseInt64IntegerStyle(value, styles, info, out result); - } - - if ((styles & NumberStyles.AllowHexSpecifier) != 0) - { - result = 0; - return TryParseUInt64HexNumberStyle(value, styles, out Unsafe.As(ref result)); - } - - return TryParseInt64Number(value, styles, info, out result); - } - - private static unsafe ParsingStatus TryParseInt64Number(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out long result) - { - result = 0; - NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, stackalloc byte[Int64NumberBufferLength]); - - if (!TryStringToNumber(value, styles, ref number, info)) - { - return ParsingStatus.Failed; - } - - if (!TryNumberToInt64(ref number, ref result)) - { - return ParsingStatus.Overflow; - } - - return ParsingStatus.OK; - } - - /// Parses Int128 inputs limited to styles that make up NumberStyles.Integer. - internal static ParsingStatus TryParseInt128IntegerStyle(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out Int128 result) - { - Debug.Assert((styles & ~NumberStyles.Integer) == 0, "Only handles subsets of Integer format"); - - if (value.IsEmpty) - goto FalseExit; - - int index = 0; - int num = value[0]; - - // Skip past any whitespace at the beginning. - if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num)) - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - while (IsWhite(num)); - } - - // Parse leading sign. - int sign = 1; - if ((styles & NumberStyles.AllowLeadingSign) != 0) - { - if (info.HasInvariantNumberSigns) - { - if (num == '-') - { - sign = -1; - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else if (num == '+') - { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - } - else if (info.AllowHyphenDuringParsing && num == '-') - { - sign = -1; - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else - { - value = value.Slice(index); - index = 0; - string positiveSign = info.PositiveSign, negativeSign = info.NegativeSign; - if (!string.IsNullOrEmpty(positiveSign) && value.StartsWith(positiveSign)) - { - index += positiveSign.Length; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else if (!string.IsNullOrEmpty(negativeSign) && value.StartsWith(negativeSign)) - { - sign = -1; - index += negativeSign.Length; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - } - } - - bool overflow = false; - Int128 answer = 0; - - if (IsDigit(num)) - { - // Skip past leading zeros. - if (num == '0') - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - } while (num == '0'); - if (!IsDigit(num)) - goto HasTrailingChars; - } - - // Parse most digits, up to the potential for overflow, which can't happen until after 18 digits. - answer = num - '0'; // first digit - index++; - for (int i = 0; i < 37; i++) // next 37 digits can't overflow - { - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - if (!IsDigit(num)) - goto HasTrailingChars; - index++; - answer = 10 * answer + num - '0'; - } - - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - if (!IsDigit(num)) - goto HasTrailingChars; - index++; - // Potential overflow now processing the 39th digit. - overflow = answer > new Int128(0x0CCCCCCCCCCCCCCC, 0xCCCCCCCCCCCCCCCC); // Int128.MaxValue / 10 - answer = answer * 10 + num - '0'; - overflow |= (UInt128)answer > new UInt128(0x7FFF_FFFF_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF) + (((uint)sign) >> 31); - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - - // At this point, we're either overflowing or hitting a formatting error. - // Format errors take precedence for compatibility. - num = value[index]; - while (IsDigit(num)) - { - overflow = true; - index++; - if ((uint)index >= (uint)value.Length) - goto OverflowExit; - num = value[index]; - } - goto HasTrailingChars; - } - goto FalseExit; - - DoneAtEndButPotentialOverflow: - if (overflow) - { - goto OverflowExit; - } - DoneAtEnd: - result = answer * sign; - ParsingStatus status = ParsingStatus.OK; - Exit: - return status; - - FalseExit: // parsing failed - result = 0; - status = ParsingStatus.Failed; - goto Exit; - OverflowExit: - result = 0; - status = ParsingStatus.Overflow; - goto Exit; - - HasTrailingChars: // we've successfully parsed, but there are still remaining characters in the span - // Skip past trailing whitespace, then past trailing zeros, and if anything else remains, fail. - if (IsWhite(num)) - { - if ((styles & NumberStyles.AllowTrailingWhite) == 0) - goto FalseExit; - for (index++; index < value.Length; index++) - { - if (!IsWhite(value[index])) - break; - } - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - } - - if (!TrailingZeros(value, index)) - goto FalseExit; - - goto DoneAtEndButPotentialOverflow; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ParsingStatus TryParseInt128(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out Int128 result) - { - if ((styles & ~NumberStyles.Integer) == 0) - { - // Optimized path for the common case of anything that's allowed for integer style. - return TryParseInt128IntegerStyle(value, styles, info, out result); - } - - if ((styles & NumberStyles.AllowHexSpecifier) != 0) - { - ParsingStatus status = TryParseUInt128HexNumberStyle(value, styles, out UInt128 unsignedResult); - result = new Int128(unsignedResult.Upper, unsignedResult.Lower); - return status; - } - - return TryParseInt128Number(value, styles, info, out result); - } - - private static unsafe ParsingStatus TryParseInt128Number(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out Int128 result) - { - result = 0; - NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, stackalloc byte[Int128NumberBufferLength]); - - if (!TryStringToNumber(value, styles, ref number, info)) - { - return ParsingStatus.Failed; - } - - if (!TryNumberToInt128(ref number, ref result)) - { - return ParsingStatus.Overflow; - } - - return ParsingStatus.OK; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ParsingStatus TryParseUInt32(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out uint result) - { - if ((styles & ~NumberStyles.Integer) == 0) - { - // Optimized path for the common case of anything that's allowed for integer style. - return TryParseUInt32IntegerStyle(value, styles, info, out result); - } - - if ((styles & NumberStyles.AllowHexSpecifier) != 0) - { - return TryParseUInt32HexNumberStyle(value, styles, out result); - } - - return TryParseUInt32Number(value, styles, info, out result); - } - - private static unsafe ParsingStatus TryParseUInt32Number(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out uint result) - { - result = 0; - NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, stackalloc byte[UInt32NumberBufferLength]); - - if (!TryStringToNumber(value, styles, ref number, info)) - { - return ParsingStatus.Failed; - } - - if (!TryNumberToUInt32(ref number, ref result)) - { - return ParsingStatus.Overflow; - } - - return ParsingStatus.OK; - } - - /// Parses uint limited to styles that make up NumberStyles.Integer. - internal static ParsingStatus TryParseUInt32IntegerStyle(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out uint result) - { - Debug.Assert((styles & ~NumberStyles.Integer) == 0, "Only handles subsets of Integer format"); - - if (value.IsEmpty) - goto FalseExit; - - int index = 0; - int num = value[0]; - - // Skip past any whitespace at the beginning. - if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num)) - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - while (IsWhite(num)); - } - - // Parse leading sign. - bool overflow = false; - if ((styles & NumberStyles.AllowLeadingSign) != 0) - { - if (info.HasInvariantNumberSigns) - { - if (num == '+') - { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else if (num == '-') - { - overflow = true; - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - } - else if (info.AllowHyphenDuringParsing && num == '-') - { - overflow = true; - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else - { - value = value.Slice(index); - index = 0; - string positiveSign = info.PositiveSign, negativeSign = info.NegativeSign; - if (!string.IsNullOrEmpty(positiveSign) && value.StartsWith(positiveSign)) - { - index += positiveSign.Length; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else if (!string.IsNullOrEmpty(negativeSign) && value.StartsWith(negativeSign)) - { - overflow = true; - index += negativeSign.Length; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - } - } - - int answer = 0; - - if (IsDigit(num)) - { - // Skip past leading zeros. - if (num == '0') - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - } while (num == '0'); - if (!IsDigit(num)) - goto HasTrailingCharsZero; - } - - // Parse most digits, up to the potential for overflow, which can't happen until after 9 digits. - answer = num - '0'; // first digit - index++; - for (int i = 0; i < 8; i++) // next 8 digits can't overflow - { - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - num = value[index]; - if (!IsDigit(num)) - goto HasTrailingChars; - index++; - answer = 10 * answer + num - '0'; - } - - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - num = value[index]; - if (!IsDigit(num)) - goto HasTrailingChars; - index++; - // Potential overflow now processing the 10th digit. - overflow |= (uint)answer > uint.MaxValue / 10 || ((uint)answer == uint.MaxValue / 10 && num > '5'); - answer = answer * 10 + num - '0'; - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - - // At this point, we're either overflowing or hitting a formatting error. - // Format errors take precedence for compatibility. - num = value[index]; - while (IsDigit(num)) - { - overflow = true; - index++; - if ((uint)index >= (uint)value.Length) - goto OverflowExit; - num = value[index]; - } - goto HasTrailingChars; - } - goto FalseExit; - - DoneAtEndButPotentialOverflow: - if (overflow) - { - goto OverflowExit; - } - DoneAtEnd: - result = (uint)answer; - ParsingStatus status = ParsingStatus.OK; - Exit: - return status; - - FalseExit: // parsing failed - result = 0; - status = ParsingStatus.Failed; - goto Exit; - OverflowExit: - result = 0; - status = ParsingStatus.Overflow; - goto Exit; - - HasTrailingCharsZero: - overflow = false; - HasTrailingChars: // we've successfully parsed, but there are still remaining characters in the span - // Skip past trailing whitespace, then past trailing zeros, and if anything else remains, fail. - if (IsWhite(num)) - { - if ((styles & NumberStyles.AllowTrailingWhite) == 0) - goto FalseExit; - for (index++; index < value.Length; index++) - { - if (!IsWhite(value[index])) - break; - } - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - } - - if (!TrailingZeros(value, index)) - goto FalseExit; - - goto DoneAtEndButPotentialOverflow; - } - - /// Parses uint limited to styles that make up NumberStyles.HexNumber. - internal static ParsingStatus TryParseUInt32HexNumberStyle(ReadOnlySpan value, NumberStyles styles, out uint result) - { - Debug.Assert((styles & ~NumberStyles.HexNumber) == 0, "Only handles subsets of HexNumber format"); - - if (value.IsEmpty) - goto FalseExit; - - int index = 0; - int num = value[0]; - - // Skip past any whitespace at the beginning. - if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num)) - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - while (IsWhite(num)); - } - - bool overflow = false; - uint answer = 0; - - if (HexConverter.IsHexChar(num)) - { - // Skip past leading zeros. - if (num == '0') - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - } while (num == '0'); - if (!HexConverter.IsHexChar(num)) - goto HasTrailingChars; - } - - // Parse up through 8 digits, as no overflow is possible - answer = (uint)HexConverter.FromChar(num); // first digit - index++; - for (int i = 0; i < 7; i++) // next 7 digits can't overflow - { - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - - uint numValue = (uint)HexConverter.FromChar(num); - if (numValue == 0xFF) - goto HasTrailingChars; - index++; - answer = 16 * answer + numValue; - } - - // If there's another digit, it's an overflow. - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - if (!HexConverter.IsHexChar(num)) - goto HasTrailingChars; - - // At this point, we're either overflowing or hitting a formatting error. - // Format errors take precedence for compatibility. Read through any remaining digits. - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto OverflowExit; - num = value[index]; - } while (HexConverter.IsHexChar(num)); - overflow = true; - goto HasTrailingChars; - } - goto FalseExit; - - DoneAtEndButPotentialOverflow: - if (overflow) - { - goto OverflowExit; - } - DoneAtEnd: - result = answer; - ParsingStatus status = ParsingStatus.OK; - Exit: - return status; - - FalseExit: // parsing failed - result = 0; - status = ParsingStatus.Failed; - goto Exit; - OverflowExit: - result = 0; - status = ParsingStatus.Overflow; - goto Exit; - - HasTrailingChars: // we've successfully parsed, but there are still remaining characters in the span - // Skip past trailing whitespace, then past trailing zeros, and if anything else remains, fail. - if (IsWhite(num)) - { - if ((styles & NumberStyles.AllowTrailingWhite) == 0) - goto FalseExit; - for (index++; index < value.Length; index++) - { - if (!IsWhite(value[index])) - break; - } - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - } - - if (!TrailingZeros(value, index)) - goto FalseExit; - - goto DoneAtEndButPotentialOverflow; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ParsingStatus TryParseUInt64(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out ulong result) - { - if ((styles & ~NumberStyles.Integer) == 0) - { - // Optimized path for the common case of anything that's allowed for integer style. - return TryParseUInt64IntegerStyle(value, styles, info, out result); - } - - if ((styles & NumberStyles.AllowHexSpecifier) != 0) - { - return TryParseUInt64HexNumberStyle(value, styles, out result); - } - - return TryParseUInt64Number(value, styles, info, out result); - } - - private static unsafe ParsingStatus TryParseUInt64Number(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out ulong result) - { - result = 0; - NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, stackalloc byte[UInt64NumberBufferLength]); - - if (!TryStringToNumber(value, styles, ref number, info)) - { - return ParsingStatus.Failed; - } - - if (!TryNumberToUInt64(ref number, ref result)) - { - return ParsingStatus.Overflow; - } - - return ParsingStatus.OK; - } - - /// Parses ulong limited to styles that make up NumberStyles.Integer. - internal static ParsingStatus TryParseUInt64IntegerStyle(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out ulong result) - { - Debug.Assert((styles & ~NumberStyles.Integer) == 0, "Only handles subsets of Integer format"); - - if (value.IsEmpty) - goto FalseExit; - - int index = 0; - int num = value[0]; - - // Skip past any whitespace at the beginning. - if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num)) - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - while (IsWhite(num)); - } - - // Parse leading sign. - bool overflow = false; - if ((styles & NumberStyles.AllowLeadingSign) != 0) - { - if (info.HasInvariantNumberSigns) - { - if (num == '+') - { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else if (num == '-') - { - overflow = true; - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - } - else if (info.AllowHyphenDuringParsing && num == '-') - { - overflow = true; - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else - { - value = value.Slice(index); - index = 0; - string positiveSign = info.PositiveSign, negativeSign = info.NegativeSign; - if (!string.IsNullOrEmpty(positiveSign) && value.StartsWith(positiveSign)) - { - index += positiveSign.Length; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - else if (!string.IsNullOrEmpty(negativeSign) && value.StartsWith(negativeSign)) - { - overflow = true; - index += negativeSign.Length; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; - } - } - } - - long answer = 0; - - if (IsDigit(num)) - { - // Skip past leading zeros. - if (num == '0') - { - do - { - index++; - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - } while (num == '0'); - if (!IsDigit(num)) - goto HasTrailingCharsZero; - } - - // Parse most digits, up to the potential for overflow, which can't happen until after 19 digits. - answer = num - '0'; // first digit - index++; - for (int i = 0; i < 18; i++) // next 18 digits can't overflow - { - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - num = value[index]; - if (!IsDigit(num)) - goto HasTrailingChars; - index++; - answer = 10 * answer + num - '0'; - } - - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - num = value[index]; - if (!IsDigit(num)) - goto HasTrailingChars; - index++; - // Potential overflow now processing the 20th digit. - overflow |= (ulong)answer > ulong.MaxValue / 10 || ((ulong)answer == ulong.MaxValue / 10 && num > '5'); - answer = answer * 10 + num - '0'; - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - - // At this point, we're either overflowing or hitting a formatting error. - // Format errors take precedence for compatibility. - num = value[index]; - while (IsDigit(num)) - { - overflow = true; - index++; - if ((uint)index >= (uint)value.Length) - goto OverflowExit; - num = value[index]; - } - goto HasTrailingChars; - } - goto FalseExit; - - DoneAtEndButPotentialOverflow: - if (overflow) - { - goto OverflowExit; - } - DoneAtEnd: - result = (ulong)answer; - ParsingStatus status = ParsingStatus.OK; - Exit: - return status; - - FalseExit: // parsing failed - result = 0; - status = ParsingStatus.Failed; - goto Exit; - OverflowExit: - result = 0; - status = ParsingStatus.Overflow; - goto Exit; - - HasTrailingCharsZero: - overflow = false; - HasTrailingChars: // we've successfully parsed, but there are still remaining characters in the span - // Skip past trailing whitespace, then past trailing zeros, and if anything else remains, fail. - if (IsWhite(num)) - { - if ((styles & NumberStyles.AllowTrailingWhite) == 0) - goto FalseExit; - for (index++; index < value.Length; index++) + } + else if (((styles & NumberStyles.AllowDecimalPoint) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, decSep)) != null || (parsingCurrency && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, info.NumberDecimalSeparator)) != null)) { - if (!IsWhite(value[index])) - break; + state |= StateDecimal; + p = next - 1; } - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; - } - - if (!TrailingZeros(value, index)) - goto FalseExit; - - goto DoneAtEndButPotentialOverflow; - } - - /// Parses ulong limited to styles that make up NumberStyles.HexNumber. - private static ParsingStatus TryParseUInt64HexNumberStyle(ReadOnlySpan value, NumberStyles styles, out ulong result) - { - Debug.Assert((styles & ~NumberStyles.HexNumber) == 0, "Only handles subsets of HexNumber format"); - - if (value.IsEmpty) - goto FalseExit; - - int index = 0; - int num = value[0]; - - // Skip past any whitespace at the beginning. - if ((styles & NumberStyles.AllowLeadingWhite) != 0 && IsWhite(num)) - { - do + else if (((styles & NumberStyles.AllowThousands) != 0) && ((state & StateDigits) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, strEnd, groupSep)) != null || (parsingCurrency && (state & StateCurrency) == 0) && (next = MatchChars(p, strEnd, info.NumberGroupSeparator)) != null)) { - index++; - if ((uint)index >= (uint)value.Length) - goto FalseExit; - num = value[index]; + p = next - 1; } - while (IsWhite(num)); + else + { + break; + } + ch = ++p < strEnd ? *p : '\0'; } - bool overflow = false; - ulong answer = 0; - - if (HexConverter.IsHexChar(num)) + bool negExp = false; + number.DigitsCount = digEnd; + number.Digits[digEnd] = (byte)('\0'); + if ((state & StateDigits) != 0) { - // Skip past leading zeros. - if (num == '0') + if ((ch == 'E' || ch == 'e') && ((styles & NumberStyles.AllowExponent) != 0)) { - do + char* temp = p; + ch = ++p < strEnd ? *p : '\0'; + if ((next = MatchChars(p, strEnd, info._positiveSign)) != null) { - index++; - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - } while (num == '0'); - if (!HexConverter.IsHexChar(num)) - goto HasTrailingChars; + ch = (p = next) < strEnd ? *p : '\0'; + } + else if ((next = MatchNegativeSignChars(p, strEnd, info)) != null) + { + ch = (p = next) < strEnd ? *p : '\0'; + negExp = true; + } + if (IsDigit(ch)) + { + int exp = 0; + do + { + exp = exp * 10 + (ch - '0'); + ch = ++p < strEnd ? *p : '\0'; + if (exp > 1000) + { + exp = 9999; + while (IsDigit(ch)) + { + ch = ++p < strEnd ? *p : '\0'; + } + } + } while (IsDigit(ch)); + if (negExp) + { + exp = -exp; + } + number.Scale += exp; + } + else + { + p = temp; + ch = p < strEnd ? *p : '\0'; + } } - // Parse up through 16 digits, as no overflow is possible - answer = (uint)HexConverter.FromChar(num); // first digit - index++; - for (int i = 0; i < 15; i++) // next 15 digits can't overflow + if (number.Kind == NumberBufferKind.FloatingPoint && !number.HasNonZeroTail) { - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - - uint numValue = (uint)HexConverter.FromChar(num); - if (numValue == 0xFF) - goto HasTrailingChars; - index++; - answer = 16 * answer + numValue; + // Adjust the number buffer for trailing zeros + int numberOfFractionalDigits = digEnd - number.Scale; + if (numberOfFractionalDigits > 0) + { + numberOfTrailingZeros = Math.Min(numberOfTrailingZeros, numberOfFractionalDigits); + Debug.Assert(numberOfTrailingZeros >= 0); + number.DigitsCount = digEnd - numberOfTrailingZeros; + number.Digits[number.DigitsCount] = (byte)('\0'); + } } - // If there's another digit, it's an overflow. - if ((uint)index >= (uint)value.Length) - goto DoneAtEnd; - num = value[index]; - if (!HexConverter.IsHexChar(num)) - goto HasTrailingChars; - - // At this point, we're either overflowing or hitting a formatting error. - // Format errors take precedence for compatibility. Read through any remaining digits. - do + while (true) { - index++; - if ((uint)index >= (uint)value.Length) - goto OverflowExit; - num = value[index]; - } while (HexConverter.IsHexChar(num)); - overflow = true; - goto HasTrailingChars; - } - goto FalseExit; - - DoneAtEndButPotentialOverflow: - if (overflow) - { - goto OverflowExit; - } - DoneAtEnd: - result = answer; - ParsingStatus status = ParsingStatus.OK; - Exit: - return status; - - FalseExit: // parsing failed - result = 0; - status = ParsingStatus.Failed; - goto Exit; - OverflowExit: - result = 0; - status = ParsingStatus.Overflow; - goto Exit; - - HasTrailingChars: // we've successfully parsed, but there are still remaining characters in the span - // Skip past trailing whitespace, then past trailing zeros, and if anything else remains, fail. - if (IsWhite(num)) - { - if ((styles & NumberStyles.AllowTrailingWhite) == 0) - goto FalseExit; - for (index++; index < value.Length; index++) + if (!IsWhite(ch) || (styles & NumberStyles.AllowTrailingWhite) == 0) + { + if ((styles & NumberStyles.AllowTrailingSign) != 0 && ((state & StateSign) == 0) && ((next = MatchChars(p, strEnd, info.PositiveSign)) != null || (((next = MatchNegativeSignChars(p, strEnd, info)) != null) && (number.IsNegative = true)))) + { + state |= StateSign; + p = next - 1; + } + else if (ch == ')' && ((state & StateParens) != 0)) + { + state &= ~StateParens; + } + else if (currSymbol != null && (next = MatchChars(p, strEnd, currSymbol)) != null) + { + currSymbol = null; + p = next - 1; + } + else + { + break; + } + } + ch = ++p < strEnd ? *p : '\0'; + } + if ((state & StateParens) == 0) { - if (!IsWhite(value[index])) - break; + if ((state & StateNonZero) == 0) + { + if (number.Kind != NumberBufferKind.Decimal) + { + number.Scale = 0; + } + if ((number.Kind == NumberBufferKind.Integer) && (state & StateDecimal) == 0) + { + number.IsNegative = false; + } + } + str = p; + return true; } - if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; } - - if (!TrailingZeros(value, index)) - goto FalseExit; - - goto DoneAtEndButPotentialOverflow; + str = p; + return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ParsingStatus TryParseUInt128(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out UInt128 result) + internal static ParsingStatus TryParseBinaryInteger(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out TInteger result) + where TInteger : unmanaged, IBinaryIntegerParseAndFormatInfo { if ((styles & ~NumberStyles.Integer) == 0) { // Optimized path for the common case of anything that's allowed for integer style. - return TryParseUInt128IntegerStyle(value, styles, info, out result); + return TryParseBinaryIntegerStyle(value, styles, info, out result); } if ((styles & NumberStyles.AllowHexSpecifier) != 0) { - return TryParseUInt128HexNumberStyle(value, styles, out result); + return TryParseBinaryIntegerHexNumberStyle(value, styles, out result); } - return TryParseUInt128Number(value, styles, info, out result); + return TryParseBinaryIntegerNumber(value, styles, info, out result); } - private static unsafe ParsingStatus TryParseUInt128Number(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out UInt128 result) + private static unsafe ParsingStatus TryParseBinaryIntegerNumber(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out TInteger result) + where TInteger : unmanaged, IBinaryIntegerParseAndFormatInfo { - result = 0U; - NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, stackalloc byte[UInt128NumberBufferLength]); + result = TInteger.Zero; + NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, stackalloc byte[TInteger.MaxDigitCount + 1]); if (!TryStringToNumber(value, styles, ref number, info)) { return ParsingStatus.Failed; } - if (!TryNumberToUInt128(ref number, ref result)) + if (!TryNumberBufferToBinaryInteger(ref number, ref result)) { return ParsingStatus.Overflow; } @@ -1952,8 +434,9 @@ private static unsafe ParsingStatus TryParseUInt128Number(ReadOnlySpan val return ParsingStatus.OK; } - /// Parses UInt128 limited to styles that make up NumberStyles.Integer. - internal static ParsingStatus TryParseUInt128IntegerStyle(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out UInt128 result) + /// Parses int limited to styles that make up NumberStyles.Integer. + internal static ParsingStatus TryParseBinaryIntegerStyle(ReadOnlySpan value, NumberStyles styles, NumberFormatInfo info, out TInteger result) + where TInteger : unmanaged, IBinaryIntegerParseAndFormatInfo { Debug.Assert((styles & ~NumberStyles.Integer) == 0, "Only handles subsets of Integer format"); @@ -1977,21 +460,21 @@ internal static ParsingStatus TryParseUInt128IntegerStyle(ReadOnlySpan val } // Parse leading sign. - bool overflow = false; + bool isNegative = false; if ((styles & NumberStyles.AllowLeadingSign) != 0) { if (info.HasInvariantNumberSigns) { - if (num == '+') + if (num == '-') { + isNegative = true; index++; if ((uint)index >= (uint)value.Length) goto FalseExit; num = value[index]; } - else if (num == '-') + else if (num == '+') { - overflow = true; index++; if ((uint)index >= (uint)value.Length) goto FalseExit; @@ -2000,7 +483,7 @@ internal static ParsingStatus TryParseUInt128IntegerStyle(ReadOnlySpan val } else if (info.AllowHyphenDuringParsing && num == '-') { - overflow = true; + isNegative = true; index++; if ((uint)index >= (uint)value.Length) goto FalseExit; @@ -2020,7 +503,7 @@ internal static ParsingStatus TryParseUInt128IntegerStyle(ReadOnlySpan val } else if (!string.IsNullOrEmpty(negativeSign) && value.StartsWith(negativeSign)) { - overflow = true; + isNegative = true; index += negativeSign.Length; if ((uint)index >= (uint)value.Length) goto FalseExit; @@ -2029,7 +512,8 @@ internal static ParsingStatus TryParseUInt128IntegerStyle(ReadOnlySpan val } } - Int128 answer = 0; + bool overflow = !TInteger.IsSigned && isNegative; + TInteger answer = TInteger.Zero; if (IsDigit(num)) { @@ -2043,35 +527,63 @@ internal static ParsingStatus TryParseUInt128IntegerStyle(ReadOnlySpan val goto DoneAtEnd; num = value[index]; } while (num == '0'); + if (!IsDigit(num)) - goto HasTrailingCharsZero; + { + if (!TInteger.IsSigned) + { + overflow = false; + } + goto HasTrailingChars; + } } - // Parse most digits, up to the potential for overflow, which can't happen until after 38 digits. - answer = num - '0'; // first digit + // Parse most digits, up to the potential for overflow, which can't happen until after MaxDigitCount - 1 digits. + answer = TInteger.CreateTruncating(num - '0'); // first digit index++; - for (int i = 0; i < 37; i++) // next 37 digits can't overflow + for (int i = 0; i < TInteger.MaxDigitCount - 2; i++) // next MaxDigitCount - 2 digits can't overflow { if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; + { + if (!TInteger.IsSigned) + goto DoneAtEndButPotentialOverflow; + else + goto DoneAtEnd; + } num = value[index]; if (!IsDigit(num)) goto HasTrailingChars; index++; - answer = 10 * answer + num - '0'; + answer = TInteger.MultiplyBy10(answer); + answer += TInteger.CreateTruncating(num - '0'); } if ((uint)index >= (uint)value.Length) - goto DoneAtEndButPotentialOverflow; + { + if (!TInteger.IsSigned) + goto DoneAtEndButPotentialOverflow; + else + goto DoneAtEnd; + } num = value[index]; if (!IsDigit(num)) goto HasTrailingChars; index++; - // Potential overflow now processing the 39th digit. - UInt128 maxValueDiv10 = new UInt128(0x1999999999999999, 0x9999999999999999); // UInt128.MaxValue / 10 - overflow |= (UInt128)answer > maxValueDiv10; - overflow |= ((UInt128)answer == maxValueDiv10 && num > '5'); - answer = answer * 10 + num - '0'; + // Potential overflow now processing the MaxDigitCount digit. + if (!TInteger.IsSigned) + { + overflow |= (answer > TInteger.MaxValueDiv10) || (answer == TInteger.MaxValueDiv10) && (num > '5'); + } + else + { + overflow = answer > TInteger.MaxValueDiv10; + } + answer = TInteger.MultiplyBy10(answer); + answer += TInteger.CreateTruncating(num - '0'); + if (TInteger.IsSigned) + { + overflow |= TInteger.IsGreaterThanAsUnsigned(answer, TInteger.MaxValue + (isNegative ? TInteger.One : TInteger.Zero)); + } if ((uint)index >= (uint)value.Length) goto DoneAtEndButPotentialOverflow; @@ -2096,22 +608,27 @@ internal static ParsingStatus TryParseUInt128IntegerStyle(ReadOnlySpan val goto OverflowExit; } DoneAtEnd: - result = (UInt128)answer; + if (!TInteger.IsSigned) + { + result = answer; + } + else + { + result = isNegative ? -answer : answer; + } ParsingStatus status = ParsingStatus.OK; Exit: return status; FalseExit: // parsing failed - result = 0U; + result = TInteger.Zero; status = ParsingStatus.Failed; goto Exit; OverflowExit: - result = 0U; + result = TInteger.Zero; status = ParsingStatus.Overflow; goto Exit; - HasTrailingCharsZero: - overflow = false; HasTrailingChars: // we've successfully parsed, but there are still remaining characters in the span // Skip past trailing whitespace, then past trailing zeros, and if anything else remains, fail. if (IsWhite(num)) @@ -2133,8 +650,9 @@ internal static ParsingStatus TryParseUInt128IntegerStyle(ReadOnlySpan val goto DoneAtEndButPotentialOverflow; } - /// Parses UInt128 limited to styles that make up NumberStyles.HexNumber. - private static ParsingStatus TryParseUInt128HexNumberStyle(ReadOnlySpan value, NumberStyles styles, out UInt128 result) + /// Parses uint limited to styles that make up NumberStyles.HexNumber. + internal static ParsingStatus TryParseBinaryIntegerHexNumberStyle(ReadOnlySpan value, NumberStyles styles, out TInteger result) + where TInteger : unmanaged, IBinaryIntegerParseAndFormatInfo { Debug.Assert((styles & ~NumberStyles.HexNumber) == 0, "Only handles subsets of HexNumber format"); @@ -2158,7 +676,7 @@ private static ParsingStatus TryParseUInt128HexNumberStyle(ReadOnlySpan va } bool overflow = false; - UInt128 answer = 0U; + TInteger answer = TInteger.Zero; if (HexConverter.IsHexChar(num)) { @@ -2176,10 +694,10 @@ private static ParsingStatus TryParseUInt128HexNumberStyle(ReadOnlySpan va goto HasTrailingChars; } - // Parse up through 32 digits, as no overflow is possible - answer = (uint)HexConverter.FromChar(num); // first digit + // Parse up through MaxHexDigitCount digits, as no overflow is possible + answer = TInteger.CreateTruncating((uint)HexConverter.FromChar(num)); // first digit index++; - for (int i = 0; i < 31; i++) // next 31 digits can't overflow + for (int i = 0; i < TInteger.MaxHexDigitCount - 1; i++) // next MaxHexDigitCount - 1 digits can't overflow { if ((uint)index >= (uint)value.Length) goto DoneAtEnd; @@ -2189,7 +707,8 @@ private static ParsingStatus TryParseUInt128HexNumberStyle(ReadOnlySpan va if (numValue == 0xFF) goto HasTrailingChars; index++; - answer = 16U * answer + numValue; + answer = TInteger.MultiplyBy16(answer); + answer += TInteger.CreateTruncating(numValue); } // If there's another digit, it's an overflow. @@ -2225,11 +744,11 @@ private static ParsingStatus TryParseUInt128HexNumberStyle(ReadOnlySpan va return status; FalseExit: // parsing failed - result = 0U; + result = TInteger.Zero; status = ParsingStatus.Failed; goto Exit; OverflowExit: - result = 0U; + result = TInteger.Zero; status = ParsingStatus.Overflow; goto Exit; @@ -2719,6 +1238,13 @@ internal enum ParsingStatus [DoesNotReturn] internal static void ThrowOverflowOrFormatException(ParsingStatus status, ReadOnlySpan value, TypeCode type = 0) => throw GetException(status, value, type); + [DoesNotReturn] + internal static void ThrowOverflowOrFormatException(ParsingStatus status, ReadOnlySpan value) + where TInteger : unmanaged, IBinaryIntegerParseAndFormatInfo + { + throw GetException(status, value); + } + [DoesNotReturn] internal static void ThrowOverflowException(TypeCode type) => throw GetOverflowException(type); @@ -2736,6 +1262,15 @@ private static Exception GetException(ParsingStatus status, ReadOnlySpan v return GetOverflowException(type); } + private static Exception GetException(ParsingStatus status, ReadOnlySpan value) + where TInteger : unmanaged, IBinaryIntegerParseAndFormatInfo + { + if (status == ParsingStatus.Failed) + return new FormatException(SR.Format(SR.Format_InvalidStringWithValue, value.ToString())); + + return new OverflowException(TInteger.OverflowMessage); + } + private static OverflowException GetOverflowException(TypeCode type) { string s; diff --git a/src/libraries/System.Private.CoreLib/src/System/SByte.cs b/src/libraries/System.Private.CoreLib/src/System/SByte.cs index 610c5f5c6dd4e..9f09ec5318ad6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SByte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SByte.cs @@ -24,7 +24,8 @@ public readonly struct SByte IBinaryInteger, IMinMaxValue, ISignedNumber, - IUtf8SpanFormattable + IUtf8SpanFormattable, + IBinaryIntegerParseAndFormatInfo { private readonly sbyte m_value; // Do not rename (binary serialization) @@ -128,106 +129,44 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS return Number.TryFormatInt32(m_value, 0x000000FF, format, provider, utf8Destination, out bytesWritten); } - public static sbyte Parse(string s) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); - } + public static sbyte Parse(string s) => Parse(s, NumberStyles.Integer, provider: null); - public static sbyte Parse(string s, NumberStyles style) - { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, style, NumberFormatInfo.CurrentInfo); - } + public static sbyte Parse(string s, NumberStyles style) => Parse(s, style, provider: null); - public static sbyte Parse(string s, IFormatProvider? provider) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); - } + public static sbyte Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); - // Parses a signed byte from a String in the given style. If - // a NumberFormatInfo isn't specified, the current culture's - // NumberFormatInfo is assumed. - // public static sbyte Parse(string s, NumberStyles style, IFormatProvider? provider) { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider)); + if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } + return Parse(s.AsSpan(), style, provider); } public static sbyte Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Parse(s, style, NumberFormatInfo.GetInstance(provider)); + return Number.ParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider)); } - private static sbyte Parse(ReadOnlySpan s, NumberStyles style, NumberFormatInfo info) - { - Number.ParsingStatus status = Number.TryParseInt32(s, style, info, out int i); - if (status != Number.ParsingStatus.OK) - { - Number.ThrowOverflowOrFormatException(status, s, TypeCode.SByte); - } - - // For hex number styles AllowHexSpecifier >> 2 == 0x80 and cancels out MinValue so the check is effectively: (uint)i > byte.MaxValue - // For integer styles it's zero and the effective check is (uint)(i - MinValue) > byte.MaxValue - if ((uint)(i - MinValue - ((int)(style & NumberStyles.AllowHexSpecifier) >> 2)) > byte.MaxValue) - { - Number.ThrowOverflowException(TypeCode.SByte); - } - return (sbyte)i; - } - - public static bool TryParse([NotNullWhen(true)] string? s, out sbyte result) - { - if (s == null) - { - result = 0; - return false; - } - - return TryParse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); - } + public static bool TryParse([NotNullWhen(true)] string? s, out sbyte result) => TryParse(s, NumberStyles.Integer, provider: null, out result); - public static bool TryParse(ReadOnlySpan s, out sbyte result) - { - return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); - } + public static bool TryParse(ReadOnlySpan s, out sbyte result) => TryParse(s, NumberStyles.Integer, provider: null, out result); public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out sbyte result) { NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) + if (s is null) { result = 0; return false; } - - return TryParse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider), out result); + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out sbyte result) { NumberFormatInfo.ValidateParseStyleInteger(style); - return TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result); - } - - private static bool TryParse(ReadOnlySpan s, NumberStyles style, NumberFormatInfo info, out sbyte result) - { - // For hex number styles AllowHexSpecifier >> 2 == 0x80 and cancels out MinValue so the check is effectively: (uint)i > byte.MaxValue - // For integer styles it's zero and the effective check is (uint)(i - MinValue) > byte.MaxValue - if (Number.TryParseInt32(s, style, info, out int i) != Number.ParsingStatus.OK - || (uint)(i - MinValue - ((int)(style & NumberStyles.AllowHexSpecifier) >> 2)) > byte.MaxValue) - { - result = 0; - return false; - } - result = (sbyte)i; - return true; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } // @@ -1386,5 +1325,25 @@ static bool INumberBase.TryConvertToTruncating(sbyte value, [Mayb /// static sbyte IUnaryPlusOperators.operator +(sbyte value) => (sbyte)(+value); + + // + // IBinaryIntegerParseAndFormatInfo + // + + static bool IBinaryIntegerParseAndFormatInfo.IsSigned => true; + + static int IBinaryIntegerParseAndFormatInfo.MaxDigitCount => 3; // 127 + + static int IBinaryIntegerParseAndFormatInfo.MaxHexDigitCount => 2; // 0x7F + + static sbyte IBinaryIntegerParseAndFormatInfo.MaxValueDiv10 => MaxValue / 10; + + static string IBinaryIntegerParseAndFormatInfo.OverflowMessage => SR.Overflow_SByte; + + static bool IBinaryIntegerParseAndFormatInfo.IsGreaterThanAsUnsigned(sbyte left, sbyte right) => (byte)(left) > (byte)(right); + + static sbyte IBinaryIntegerParseAndFormatInfo.MultiplyBy10(sbyte value) => (sbyte)(value * 10); + + static sbyte IBinaryIntegerParseAndFormatInfo.MultiplyBy16(sbyte value) => (sbyte)(value * 16); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs index e8b9232e48901..142b94d84a545 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs @@ -521,6 +521,12 @@ internal static void ThrowFormatException_BadFormatSpecifier() throw new FormatException(SR.Argument_BadFormatSpecifier); } + [DoesNotReturn] + internal static void ThrowFormatException_NeedSingleChar() + { + throw new FormatException(SR.Format_NeedSingleChar); + } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException_PrecisionTooLarge() { diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs index c420c268fe018..85ff1a912a4c4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs @@ -19,7 +19,8 @@ public readonly struct UInt128 : IBinaryInteger, IMinMaxValue, IUnsignedNumber, - IUtf8SpanFormattable + IUtf8SpanFormattable, + IBinaryIntegerParseAndFormatInfo { internal const int Size = 16; @@ -126,75 +127,44 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS return Number.TryFormatUInt128(this, format, provider, utf8Destination, out bytesWritten); } - public static UInt128 Parse(string s) - { - ArgumentNullException.ThrowIfNull(s); - return Number.ParseUInt128(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); - } + public static UInt128 Parse(string s) => Parse(s, NumberStyles.Integer, provider: null); - public static UInt128 Parse(string s, NumberStyles style) - { - ArgumentNullException.ThrowIfNull(s); - NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.ParseUInt128(s, style, NumberFormatInfo.CurrentInfo); - } + public static UInt128 Parse(string s, NumberStyles style) => Parse(s, style, provider: null); - public static UInt128 Parse(string s, IFormatProvider? provider) - { - ArgumentNullException.ThrowIfNull(s); - return Number.ParseUInt128(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); - } + public static UInt128 Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); public static UInt128 Parse(string s, NumberStyles style, IFormatProvider? provider) { - ArgumentNullException.ThrowIfNull(s); - NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.ParseUInt128(s, style, NumberFormatInfo.GetInstance(provider)); + if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } + return Parse(s.AsSpan(), style, provider); } public static UInt128 Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.ParseUInt128(s, style, NumberFormatInfo.GetInstance(provider)); + return Number.ParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse([NotNullWhen(true)] string? s, out UInt128 result) - { - if (s is not null) - { - return Number.TryParseUInt128IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } - else - { - result = default; - return false; - } - } + public static bool TryParse([NotNullWhen(true)] string? s, out UInt128 result) => TryParse(s, NumberStyles.Integer, provider: null, out result); - public static bool TryParse(ReadOnlySpan s, out UInt128 result) - { - return Number.TryParseUInt128IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } + public static bool TryParse(ReadOnlySpan s, out UInt128 result) => TryParse(s, NumberStyles.Integer, provider: null, out result); public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out UInt128 result) { NumberFormatInfo.ValidateParseStyleInteger(style); - if (s is not null) - { - return Number.TryParseUInt128(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; - } - else + if (s is null) { - result = default; + result = 0; return false; } + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out UInt128 result) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.TryParseUInt128(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } // @@ -2162,5 +2132,25 @@ static bool INumberBase.TryConvertToTruncating(UInt128 value, [ /// public static UInt128 operator +(UInt128 value) => value; + + // + // IBinaryIntegerParseAndFormatInfo + // + + static bool IBinaryIntegerParseAndFormatInfo.IsSigned => false; + + static int IBinaryIntegerParseAndFormatInfo.MaxDigitCount => 39; // 340_282_366_920_938_463_463_374_607_431_768_211_455 + + static int IBinaryIntegerParseAndFormatInfo.MaxHexDigitCount => 32; // 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF + + static UInt128 IBinaryIntegerParseAndFormatInfo.MaxValueDiv10 => new UInt128(0x1999_9999_9999_9999, 0x9999_9999_9999_9999); + + static string IBinaryIntegerParseAndFormatInfo.OverflowMessage => SR.Overflow_UInt128; + + static bool IBinaryIntegerParseAndFormatInfo.IsGreaterThanAsUnsigned(UInt128 left, UInt128 right) => left > right; + + static UInt128 IBinaryIntegerParseAndFormatInfo.MultiplyBy10(UInt128 value) => value * 10; + + static UInt128 IBinaryIntegerParseAndFormatInfo.MultiplyBy16(UInt128 value) => value * 16; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs index d43bd48fe68b0..54f87f1264cea 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs @@ -24,7 +24,8 @@ public readonly struct UInt16 IBinaryInteger, IMinMaxValue, IUnsignedNumber, - IUtf8SpanFormattable + IUtf8SpanFormattable, + IBinaryIntegerParseAndFormatInfo { private readonly ushort m_value; // Do not rename (binary serialization) @@ -120,95 +121,44 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS return Number.TryFormatUInt32(m_value, format, provider, utf8Destination, out bytesWritten); } - public static ushort Parse(string s) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); - } + public static ushort Parse(string s) => Parse(s, NumberStyles.Integer, provider: null); - public static ushort Parse(string s, NumberStyles style) - { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, style, NumberFormatInfo.CurrentInfo); - } + public static ushort Parse(string s, NumberStyles style) => Parse(s, style, provider: null); - public static ushort Parse(string s, IFormatProvider? provider) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); - } + public static ushort Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); public static ushort Parse(string s, NumberStyles style, IFormatProvider? provider) { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Parse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider)); + if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } + return Parse(s.AsSpan(), style, provider); } public static ushort Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Parse(s, style, NumberFormatInfo.GetInstance(provider)); - } - - private static ushort Parse(ReadOnlySpan s, NumberStyles style, NumberFormatInfo info) - { - Number.ParsingStatus status = Number.TryParseUInt32(s, style, info, out uint i); - if (status != Number.ParsingStatus.OK) - { - Number.ThrowOverflowOrFormatException(status, s, TypeCode.UInt16); - } - - if (i > MaxValue) Number.ThrowOverflowException(TypeCode.UInt16); - return (ushort)i; + return Number.ParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse([NotNullWhen(true)] string? s, out ushort result) - { - if (s == null) - { - result = 0; - return false; - } + public static bool TryParse([NotNullWhen(true)] string? s, out ushort result) => TryParse(s, NumberStyles.Integer, provider: null, out result); - return TryParse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); - } - - public static bool TryParse(ReadOnlySpan s, out ushort result) - { - return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); - } + public static bool TryParse(ReadOnlySpan s, out ushort result) => TryParse(s, NumberStyles.Integer, provider: null, out result); public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out ushort result) { NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) + if (s is null) { result = 0; return false; } - - return TryParse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider), out result); + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out ushort result) { NumberFormatInfo.ValidateParseStyleInteger(style); - return TryParse(s, style, NumberFormatInfo.GetInstance(provider), out result); - } - - private static bool TryParse(ReadOnlySpan s, NumberStyles style, NumberFormatInfo info, out ushort result) - { - if (Number.TryParseUInt32(s, style, info, out uint i) != Number.ParsingStatus.OK - || i > MaxValue) - { - result = 0; - return false; - } - result = (ushort)i; - return true; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } // @@ -1229,5 +1179,25 @@ static bool INumberBase.TryConvertToTruncating(ushort value, [Ma /// static ushort IUnaryPlusOperators.operator +(ushort value) => (ushort)(+value); + + // + // IBinaryIntegerParseAndFormatInfo + // + + static bool IBinaryIntegerParseAndFormatInfo.IsSigned => false; + + static int IBinaryIntegerParseAndFormatInfo.MaxDigitCount => 5; // 65_535 + + static int IBinaryIntegerParseAndFormatInfo.MaxHexDigitCount => 4; // 0xFFFF + + static ushort IBinaryIntegerParseAndFormatInfo.MaxValueDiv10 => MaxValue / 10; + + static string IBinaryIntegerParseAndFormatInfo.OverflowMessage => SR.Overflow_UInt16; + + static bool IBinaryIntegerParseAndFormatInfo.IsGreaterThanAsUnsigned(ushort left, ushort right) => left > right; + + static ushort IBinaryIntegerParseAndFormatInfo.MultiplyBy10(ushort value) => (ushort)(value * 10); + + static ushort IBinaryIntegerParseAndFormatInfo.MultiplyBy16(ushort value) => (ushort)(value * 16); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs index 0a9f9c0aea125..dcec51866930d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs @@ -24,7 +24,8 @@ public readonly struct UInt32 IBinaryInteger, IMinMaxValue, IUnsignedNumber, - IUtf8SpanFormattable + IUtf8SpanFormattable, + IBinaryIntegerParseAndFormatInfo { private readonly uint m_value; // Do not rename (binary serialization) @@ -130,71 +131,44 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS return Number.TryFormatUInt32(m_value, format, provider, utf8Destination, out bytesWritten); } - public static uint Parse(string s) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseUInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); - } + public static uint Parse(string s) => Parse(s, NumberStyles.Integer, provider: null); - public static uint Parse(string s, NumberStyles style) - { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseUInt32(s, style, NumberFormatInfo.CurrentInfo); - } + public static uint Parse(string s, NumberStyles style) => Parse(s, style, provider: null); - public static uint Parse(string s, IFormatProvider? provider) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseUInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); - } + public static uint Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); public static uint Parse(string s, NumberStyles style, IFormatProvider? provider) { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseUInt32(s, style, NumberFormatInfo.GetInstance(provider)); + if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } + return Parse(s.AsSpan(), style, provider); } public static uint Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.ParseUInt32(s, style, NumberFormatInfo.GetInstance(provider)); + return Number.ParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse([NotNullWhen(true)] string? s, out uint result) - { - if (s == null) - { - result = 0; - return false; - } + public static bool TryParse([NotNullWhen(true)] string? s, out uint result) => TryParse(s, NumberStyles.Integer, provider: null, out result); - return Number.TryParseUInt32IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } - - public static bool TryParse(ReadOnlySpan s, out uint result) - { - return Number.TryParseUInt32IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } + public static bool TryParse(ReadOnlySpan s, out uint result) => TryParse(s, NumberStyles.Integer, provider: null, out result); public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out uint result) { NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) + if (s is null) { result = 0; return false; } - - return Number.TryParseUInt32(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out uint result) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.TryParseUInt32(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } // @@ -1244,5 +1218,25 @@ static bool INumberBase.TryConvertToTruncating(uint value, [MaybeN /// static uint IUnaryPlusOperators.operator +(uint value) => +value; + + // + // IBinaryIntegerParseAndFormatInfo + // + + static bool IBinaryIntegerParseAndFormatInfo.IsSigned => false; + + static int IBinaryIntegerParseAndFormatInfo.MaxDigitCount => 10; // 4_294_967_295 + + static int IBinaryIntegerParseAndFormatInfo.MaxHexDigitCount => 8; // 0xFFFF_FFFF + + static uint IBinaryIntegerParseAndFormatInfo.MaxValueDiv10 => MaxValue / 10; + + static string IBinaryIntegerParseAndFormatInfo.OverflowMessage => SR.Overflow_UInt32; + + static bool IBinaryIntegerParseAndFormatInfo.IsGreaterThanAsUnsigned(uint left, uint right) => left > right; + + static uint IBinaryIntegerParseAndFormatInfo.MultiplyBy10(uint value) => value * 10; + + static uint IBinaryIntegerParseAndFormatInfo.MultiplyBy16(uint value) => value * 16; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs index 962064b83c310..c9b2e057480d7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs @@ -24,7 +24,8 @@ public readonly struct UInt64 IBinaryInteger, IMinMaxValue, IUnsignedNumber, - IUtf8SpanFormattable + IUtf8SpanFormattable, + IBinaryIntegerParseAndFormatInfo { private readonly ulong m_value; // Do not rename (binary serialization) @@ -129,71 +130,44 @@ public bool TryFormat(Span utf8Destination, out int bytesWritten, [StringS return Number.TryFormatUInt64(m_value, format, provider, utf8Destination, out bytesWritten); } - public static ulong Parse(string s) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseUInt64(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); - } + public static ulong Parse(string s) => Parse(s, NumberStyles.Integer, provider: null); - public static ulong Parse(string s, NumberStyles style) - { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseUInt64(s, style, NumberFormatInfo.CurrentInfo); - } + public static ulong Parse(string s, NumberStyles style) => Parse(s, style, provider: null); - public static ulong Parse(string s, IFormatProvider? provider) - { - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseUInt64(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); - } + public static ulong Parse(string s, IFormatProvider? provider) => Parse(s, NumberStyles.Integer, provider); public static ulong Parse(string s, NumberStyles style, IFormatProvider? provider) { - NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); - return Number.ParseUInt64(s, style, NumberFormatInfo.GetInstance(provider)); + if (s is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); } + return Parse(s.AsSpan(), style, provider); } public static ulong Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.ParseUInt64(s, style, NumberFormatInfo.GetInstance(provider)); + return Number.ParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse([NotNullWhen(true)] string? s, out ulong result) - { - if (s == null) - { - result = 0; - return false; - } + public static bool TryParse([NotNullWhen(true)] string? s, out ulong result) => TryParse(s, NumberStyles.Integer, provider: null, out result); - return Number.TryParseUInt64IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } - - public static bool TryParse(ReadOnlySpan s, out ulong result) - { - return Number.TryParseUInt64IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; - } + public static bool TryParse(ReadOnlySpan s, out ulong result) => TryParse(s, NumberStyles.Integer, provider: null, out result); public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out ulong result) { NumberFormatInfo.ValidateParseStyleInteger(style); - if (s == null) + if (s is null) { result = 0; return false; } - - return Number.TryParseUInt64(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out ulong result) { NumberFormatInfo.ValidateParseStyleInteger(style); - return Number.TryParseUInt64(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; + return Number.TryParseBinaryInteger(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } // @@ -1237,5 +1211,25 @@ static bool INumberBase.TryConvertToTruncating(ulong value, [Mayb /// static ulong IUnaryPlusOperators.operator +(ulong value) => +value; + + // + // IBinaryIntegerParseAndFormatInfo + // + + static bool IBinaryIntegerParseAndFormatInfo.IsSigned => false; + + static int IBinaryIntegerParseAndFormatInfo.MaxDigitCount => 20; // 18_446_744_073_709_551_615 + + static int IBinaryIntegerParseAndFormatInfo.MaxHexDigitCount => 16; // 0xFFFF_FFFF_FFFF_FFFF + + static ulong IBinaryIntegerParseAndFormatInfo.MaxValueDiv10 => MaxValue / 10; + + static string IBinaryIntegerParseAndFormatInfo.OverflowMessage => SR.Overflow_UInt64; + + static bool IBinaryIntegerParseAndFormatInfo.IsGreaterThanAsUnsigned(ulong left, ulong right) => left > right; + + static ulong IBinaryIntegerParseAndFormatInfo.MultiplyBy10(ulong value) => value * 10; + + static ulong IBinaryIntegerParseAndFormatInfo.MultiplyBy16(ulong value) => value * 16; } } From 410aa0a7cb47d66d82634c62633ba26e8a1a002d Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 17 Apr 2023 15:49:02 -0700 Subject: [PATCH 29/32] Re-enable gc-sections with lld for NativeAOT (#84935) * Revert "Revert "Write linker script for lld to enable gc-sections (#84493)"" This reverts the revert of commit 3ab663e128e233ad1f4a1a4a0df64b08a846bcd5. The revert of that commit was included in 887c043eb94be364188e2b23a87efa214ea57f1e. * Lower the lld version requirement * Adjust dwarfdump baseline --------- Co-authored-by: Adeel <3840695+am11@users.noreply.github.com> --- .../Microsoft.NETCore.Native.Unix.targets | 9 +++++++++ .../BuildIntegration/Microsoft.NETCore.Native.targets | 6 +++++- src/tests/nativeaot/SmokeTests/DwarfDump/Program.cs | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets index 2c1edf7ab0ecd..27955fd6bc22c 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets @@ -181,6 +181,15 @@ The .NET Foundation licenses this file to you under the MIT license. + + + + + + + <_LinkerVersion>$([System.Text.RegularExpressions.Regex]::Match($(_LinkerVersionString), '[1-9]\d*')) + + diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index 44703efeb45cd..a0c5cbae672eb 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -318,7 +318,8 @@ The .NET Foundation licenses this file to you under the MIT license. - + + @@ -335,6 +336,9 @@ The .NET Foundation licenses this file to you under the MIT license. -x + + + diff --git a/src/tests/nativeaot/SmokeTests/DwarfDump/Program.cs b/src/tests/nativeaot/SmokeTests/DwarfDump/Program.cs index 0096a28c92f1e..39e6c815c0dda 100644 --- a/src/tests/nativeaot/SmokeTests/DwarfDump/Program.cs +++ b/src/tests/nativeaot/SmokeTests/DwarfDump/Program.cs @@ -54,8 +54,8 @@ public static int Main(string[] args) const int MinWarnings = 16500; const int MaxWarnings = 18500; #else - const int MinWarnings = 9500; - const int MaxWarnings = 10500; + const int MinWarnings = 12000; + const int MaxWarnings = 13000; #endif int count = 0; string line; From 80ce3b666823f2855b678307850e719a5f7366af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rylek?= Date: Tue, 18 Apr 2023 00:55:02 +0200 Subject: [PATCH 30/32] Add issues.targets entries for four tests failing on Windows arm (#84943) After several fixes and additions to issues.targets I'm now seeing a relatively limited set of tests failing on Windows arm with a nullref tracked under https://github.com/dotnet/runtime/issues/84818 This should finally let us see a green outerloop run despite the fact that some additional rare failures still remain, I've seen a few in the runs from the last couple of days. Thanks Tomas --- src/tests/issues.targets | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 3f409b5c33135..d362b4c04fc3c 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -293,6 +293,9 @@ + + https://github.com/dotnet/runtime/issues/84818 + https://github.com/dotnet/runtime/issues/49184 @@ -509,12 +512,21 @@ https://github.com/dotnet/runtime/issues/66745 + + https://github.com/dotnet/runtime/issues/84818 + https://github.com/dotnet/runtime/issues/84750 https://github.com/dotnet/runtime/issues/84750 + + https://github.com/dotnet/runtime/issues/84818 + + + https://github.com/dotnet/runtime/issues/84818 + https://github.com/dotnet/runtime/issues/81241 From 4dc6603ace319209e944cc3d0bf7cac549de150c Mon Sep 17 00:00:00 2001 From: lexi-nadia Date: Mon, 17 Apr 2023 19:24:04 -0400 Subject: [PATCH 31/32] fix aarch64+clang compilation errors (#84947) * don't use the gcc workaround on clang clang doesn't need it, and clang also doesn't support the `optimize` attribute. * cast _zzq_default to a 64-bit type Otherwise, clang complains that "value-size does not match register size", since the 32-bit value (generally a literal 0) doesn't match the 64-bit x3 register. --- src/mono/mono/mini/mini-exceptions.c | 2 +- src/mono/mono/utils/valgrind.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/mini-exceptions.c b/src/mono/mono/mini/mini-exceptions.c index 56935279a18bd..c75c124b7d400 100644 --- a/src/mono/mono/mini/mini-exceptions.c +++ b/src/mono/mono/mini/mini-exceptions.c @@ -754,7 +754,7 @@ unwinder_init (Unwinder *unwinder) memset (unwinder, 0, sizeof (Unwinder)); } -#if defined(__GNUC__) && defined(TARGET_ARM64) +#if defined(__GNUC__) && defined(TARGET_ARM64) && !defined(__clang__) /* gcc 4.9.2 seems to miscompile this on arm64 */ static __attribute__((optimize("O0"))) gboolean #else diff --git a/src/mono/mono/utils/valgrind.h b/src/mono/mono/utils/valgrind.h index 03058c1fc840f..3d802e5d4a7e5 100644 --- a/src/mono/mono/utils/valgrind.h +++ b/src/mono/mono/utils/valgrind.h @@ -769,12 +769,14 @@ typedef __extension__ \ ({volatile unsigned long long int _zzq_args[6]; \ volatile unsigned long long int _zzq_result; \ + volatile unsigned long long int _zzq_default_ll; \ _zzq_args[0] = (unsigned long long int)(_zzq_request); \ _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ + _zzq_default_ll = (unsigned long long int)(_zzq_default); \ __asm__ volatile("mov x3, %1\n\t" /*default*/ \ "mov x4, %2\n\t" /*ptr*/ \ __SPECIAL_INSTRUCTION_PREAMBLE \ @@ -782,7 +784,7 @@ typedef "orr x10, x10, x10\n\t" \ "mov %0, x3" /*result*/ \ : "=r" (_zzq_result) \ - : "r" (_zzq_default), "r" (&_zzq_args[0]) \ + : "r" (_zzq_default_ll), "r" (&_zzq_args[0]) \ : "cc","memory", "x3", "x4"); \ _zzq_result; \ }) From 9aefa9daa141bb7d9ba3f2b373d4b050c9b243fe Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 17 Apr 2023 16:29:15 -0700 Subject: [PATCH 32/32] Reconfigure the HWIntrinsic tests to run more selectively (#84948) * Increase the number of stripes to use in stress for HardwareIntrinsics tests * Reconfigure the HWIntrinsic tests to run more selectively * Fix a _ro.csproj --- .../Arm/Directory.Build.props | 10 ++++++++++ .../Arm/Directory.Build.targets | 6 ------ .../HardwareIntrinsics/Directory.Build.props | 1 + .../Directory.Build.targets | 20 +++++++++++++++++++ .../General/Vector256/Vector256_r.csproj | 7 +------ .../General/Vector256/Vector256_ro.csproj | 7 +------ .../General/Vector256_1/Vector256_1_r.csproj | 8 +------- .../General/Vector256_1/Vector256_1_ro.csproj | 8 +------- .../General/Vector512/Vector512_r.csproj | 6 +----- .../General/Vector512/Vector512_ro.csproj | 6 +----- .../General/Vector512_1/Vector512_1_r.csproj | 6 +----- .../General/Vector512_1/Vector512_1_ro.csproj | 6 +----- .../General/Vector64/Vector64_r.csproj | 6 +----- .../General/Vector64/Vector64_ro.csproj | 6 +----- .../General/Vector64_1/Vector64_1_r.csproj | 6 +----- .../General/Vector64_1/Vector64_1_ro.csproj | 6 +----- .../HardwareIntrinsics_r.csproj | 3 ++- .../HardwareIntrinsics_ro.csproj | 2 +- .../X86/Directory.Build.props | 10 ++++++++++ .../X86/Directory.Build.targets | 7 ------- 20 files changed, 56 insertions(+), 81 deletions(-) create mode 100644 src/tests/JIT/HardwareIntrinsics/Arm/Directory.Build.props create mode 100644 src/tests/JIT/HardwareIntrinsics/Directory.Build.targets create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/Directory.Build.props diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Directory.Build.props b/src/tests/JIT/HardwareIntrinsics/Arm/Directory.Build.props new file mode 100644 index 0000000000000..23625a46fc4ce --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Directory.Build.props @@ -0,0 +1,10 @@ + + + + + + + true + + + diff --git a/src/tests/JIT/HardwareIntrinsics/Arm/Directory.Build.targets b/src/tests/JIT/HardwareIntrinsics/Arm/Directory.Build.targets index d72d49174ce0d..eca47c9c796ad 100644 --- a/src/tests/JIT/HardwareIntrinsics/Arm/Directory.Build.targets +++ b/src/tests/JIT/HardwareIntrinsics/Arm/Directory.Build.targets @@ -3,12 +3,6 @@ - - - 1 - 0 - - $(IntermediateOutputPath)$(MSBuildProjectName)/gen/ $(GeneratedHWIntrinsicTestDirectory)GeneratedHWIntrinsicTestList.txt diff --git a/src/tests/JIT/HardwareIntrinsics/Directory.Build.props b/src/tests/JIT/HardwareIntrinsics/Directory.Build.props index 81ddb5af5a309..8df9869fb8699 100644 --- a/src/tests/JIT/HardwareIntrinsics/Directory.Build.props +++ b/src/tests/JIT/HardwareIntrinsics/Directory.Build.props @@ -1,3 +1,4 @@ + diff --git a/src/tests/JIT/HardwareIntrinsics/Directory.Build.targets b/src/tests/JIT/HardwareIntrinsics/Directory.Build.targets new file mode 100644 index 0000000000000..e10bfde46063a --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/Directory.Build.targets @@ -0,0 +1,20 @@ + + + + + + + + + true + + + + + + true + true + true + + + diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Vector256_r.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Vector256_r.csproj index 09b38909db712..b525dacf167c4 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Vector256_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Vector256_r.csproj @@ -1,17 +1,12 @@ true + true Embedded - - - 1 - 0 - 0 - diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Vector256_ro.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Vector256_ro.csproj index b76e7ea9ee3b3..9194d3a9763a5 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256/Vector256_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256/Vector256_ro.csproj @@ -1,17 +1,12 @@ true + true Embedded True - - - 1 - 0 - 0 - diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_r.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_r.csproj index 688c23b52914f..24486d9d9555c 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_r.csproj @@ -1,7 +1,7 @@ true - + true true true @@ -10,12 +10,6 @@ Embedded - - - 1 - 0 - 0 - diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_ro.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_ro.csproj index 10a0920bb9153..32ce1332e61a0 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_ro.csproj @@ -1,7 +1,7 @@ true - + true true true @@ -10,12 +10,6 @@ Embedded True - - - 1 - 0 - 0 - diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector512/Vector512_r.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector512/Vector512_r.csproj index 5bd89c674d2a8..681f7971f5f5c 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector512/Vector512_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector512/Vector512_r.csproj @@ -1,16 +1,12 @@ true + true Embedded - - - - 1 - diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector512/Vector512_ro.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector512/Vector512_ro.csproj index 097a1aef36503..d458d5bf48614 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector512/Vector512_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector512/Vector512_ro.csproj @@ -1,16 +1,12 @@ true + true Embedded True - - - - 1 - diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector512_1/Vector512_1_r.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector512_1/Vector512_1_r.csproj index 2529fc56bf863..ee8b16107dc8f 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector512_1/Vector512_1_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector512_1/Vector512_1_r.csproj @@ -1,16 +1,12 @@ true + true Embedded - - - - 1 - diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector512_1/Vector512_1_ro.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector512_1/Vector512_1_ro.csproj index 66c501a722e2d..4b8799ae937ab 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector512_1/Vector512_1_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector512_1/Vector512_1_ro.csproj @@ -1,16 +1,12 @@ true + true Embedded True - - - - 1 - diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Vector64_r.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Vector64_r.csproj index bb555014d8ff3..7e05ced6512f1 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Vector64_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Vector64_r.csproj @@ -1,16 +1,12 @@ true + true Embedded - - - 1 - 0 - diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Vector64_ro.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Vector64_ro.csproj index f41eecd53c7f4..1713e65402227 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64/Vector64_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64/Vector64_ro.csproj @@ -1,16 +1,12 @@ true + true Embedded True - - - 1 - 0 - diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_r.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_r.csproj index 676fb4cfe89b1..aeeaf5a1738fe 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_r.csproj @@ -1,16 +1,12 @@ true + true Embedded - - - 1 - 0 - diff --git a/src/tests/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_ro.csproj b/src/tests/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_ro.csproj index dce5b934909f1..2310470cc212f 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_ro.csproj @@ -1,16 +1,12 @@ true + true Embedded True - - - 1 - 0 - diff --git a/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_r.csproj b/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_r.csproj index 2c8f90272ce3d..a44c0bfb5145d 100644 --- a/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_r.csproj @@ -1,9 +1,10 @@ - 20 + 32 true true + diff --git a/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_ro.csproj b/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_ro.csproj index e10ee544a203e..44c6f2f9f679f 100644 --- a/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_ro.csproj @@ -1,6 +1,6 @@ - 20 + 32 true true diff --git a/src/tests/JIT/HardwareIntrinsics/X86/Directory.Build.props b/src/tests/JIT/HardwareIntrinsics/X86/Directory.Build.props new file mode 100644 index 0000000000000..e3e1bac79c32c --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/Directory.Build.props @@ -0,0 +1,10 @@ + + + + + + + true + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/Directory.Build.targets b/src/tests/JIT/HardwareIntrinsics/X86/Directory.Build.targets index 77fd5e210fc55..933c13be21e6a 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/Directory.Build.targets +++ b/src/tests/JIT/HardwareIntrinsics/X86/Directory.Build.targets @@ -3,13 +3,6 @@ - - - 1 - 0 - 0 - - $(IntermediateOutputPath)$(MSBuildProjectName)/gen/ $(GeneratedHWIntrinsicTestDirectory)GeneratedHWIntrinsicTestList.txt